Merge "SurfaceFlinger: relative size RefreshRateOverlay"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 20bfe65..4a84884 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -14,10 +14,12 @@
libs/renderengine/
libs/ui/
libs/vr/
+ opengl/libs/
services/bufferhub/
services/inputflinger/
services/surfaceflinger/
services/vr/
+ vulkan/
[Hook Scripts]
owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 08a31c1..402767a 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -15,6 +15,7 @@
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
+ "android.hardware.vibrator-ndk_platform",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
@@ -24,7 +25,6 @@
"libhidlbase",
"liblog",
"libutils",
- "vintf-vibrator-ndk_platform",
],
cflags: [
"-DLOG_TAG=\"idlcli\"",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index f8a68b4..6b14bee 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -639,10 +639,8 @@
if (delete_dir_contents(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
- path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
- if (delete_dir_contents(path, true) != 0) {
- res = error("Failed to delete contents of " + path);
- }
+ // Note that we explicitly don't delete OBBs - those are only removed on
+ // app uninstall.
}
}
}
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index a71e01c..e080291 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -101,6 +101,26 @@
}
}
+int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId) {
+ const std::string device = FindQuotaDeviceForUuid(uuid);
+ if (device == "") {
+ return -1;
+ }
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, PRJQUOTA), device.c_str(), projectId,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for Project ID " << projectId;
+ }
+ return -1;
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for Project ID " << projectId << " " << dq.dqb_curspace;
+#endif
+ return dq.dqb_curspace;
+ }
+}
+
int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
const std::string device = FindQuotaDeviceForUuid(uuid);
if (device == "") {
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
index 9ad170f..96aca04 100644
--- a/cmds/installd/QuotaUtils.h
+++ b/cmds/installd/QuotaUtils.h
@@ -35,6 +35,8 @@
/* Get the current occupied space in bytes for a gid or -1 if fails */
int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+/* Get the current occupied space in bytes for a project id or -1 if fails */
+int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId);
} // namespace installd
} // namespace android
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
index 082378d..b598f68 100644
--- a/data/etc/android.hardware.telephony.cdma.xml
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -18,4 +18,5 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.hardware.telephony.cdma" />
+ <feature name="android.hardware.telephony.data" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
index 7927fa8..fe8a5cf 100644
--- a/data/etc/android.hardware.telephony.gsm.xml
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -18,4 +18,5 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.hardware.telephony.gsm" />
+ <feature name="android.hardware.telephony.data" />
</permissions>
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
new file mode 100644
index 0000000..b6c0765
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
new file mode 100644
index 0000000..4e975e5
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
new file mode 100644
index 0000000..a331095
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
new file mode 100644
index 0000000..41e6668
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
Binary files differ
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 6479109..a9c2311 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -178,6 +178,10 @@
this->callbacks_.key_authorized(arg, id);
this->dispatched_prompt_ = std::nullopt;
+
+ // We need to dispatch pending prompts here upon success as well,
+ // since we might have multiple queued prompts.
+ DispatchPendingPrompt();
} else if (packet[0] == 'N' && packet[1] == 'O') {
CHECK_EQ(2UL, packet.length());
// TODO: Do we want a callback if the key is denied?
diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp
index 98d8e8a..8062be6 100644
--- a/libs/android_runtime_lazy/android_runtime_lazy.cpp
+++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "ANDROID_RUNTIME_LAZY"
#include "android_runtime/AndroidRuntime.h"
+#include "android_os_Parcel.h"
#include "android_util_Binder.h"
#include <dlfcn.h>
@@ -28,12 +29,18 @@
std::once_flag loadFlag;
typedef JNIEnv* (*getJNIEnv_t)();
+
+// android_util_Binder.h
typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val);
+// android_os_Parcel.h
+typedef Parcel* (*parcelForJavaObject_t)(JNIEnv* env, jobject obj);
+
getJNIEnv_t _getJNIEnv;
ibinderForJavaObject_t _ibinderForJavaObject;
javaObjectForIBinder_t _javaObjectForIBinder;
+parcelForJavaObject_t _parcelForJavaObject;
void load() {
std::call_once(loadFlag, []() {
@@ -64,6 +71,13 @@
ALOGW("Could not find javaObjectForIBinder.");
// no return
}
+
+ _parcelForJavaObject = reinterpret_cast<parcelForJavaObject_t>(
+ dlsym(handle, "_ZN7android19parcelForJavaObjectEP7_JNIEnvP8_jobject"));
+ if (_parcelForJavaObject == nullptr) {
+ ALOGW("Could not find parcelForJavaObject.");
+ // no return
+ }
});
}
@@ -95,4 +109,12 @@
return _javaObjectForIBinder(env, val);
}
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) {
+ load();
+ if (_parcelForJavaObject == nullptr) {
+ return nullptr;
+ }
+ return _parcelForJavaObject(env, obj);
+}
+
} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_os_Parcel.h b/libs/android_runtime_lazy/include/android_os_Parcel.h
new file mode 100644
index 0000000..19b094d
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_os_Parcel.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include "jni.h"
+
+namespace android {
+
+// The name of this file is same with the file in frameworks/base/core/jni/
+// This is intentional to make the client use these exported functions
+// in the same way with the original.
+
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
+
+} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index fa07d04..b37db43 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -50,6 +50,7 @@
"ibinder.cpp",
"ibinder_jni.cpp",
"parcel.cpp",
+ "parcel_jni.cpp",
"process.cpp",
"stability.cpp",
"status.cpp",
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index be3029c..cd1ff1f 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -36,13 +36,13 @@
/**
* Converts an android.os.IBinder object into an AIBinder* object.
*
- * If either env or the binder is null, null is returned. If this binder object was originally an
+ * If the binder is null, null is returned. If this binder object was originally an
* AIBinder object, the original object is returned. The returned object has one refcount
* associated with it, and so this should be accompanied with an AIBinder_decStrong call.
*
* Available since API level 29.
*
- * \param env Java environment.
+ * \param env Java environment. Must not be null.
* \param binder android.os.IBinder java object.
*
* \return an AIBinder object representing the Java binder object. If either parameter is null, or
@@ -54,12 +54,12 @@
/**
* Converts an AIBinder* object into an android.os.IBinder object.
*
- * If either env or the binder is null, null is returned. If this binder object was originally an
- * IBinder object, the original java object will be returned.
+ * If the binder is null, null is returned. If this binder object was originally an IBinder object,
+ * the original java object will be returned.
*
* Available since API level 29.
*
- * \param env Java environment.
+ * \param env Java environment. Must not be null.
* \param binder the object to convert.
*
* \return an android.os.IBinder object or null if the parameters were null.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
new file mode 100644
index 0000000..65e1704
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel_jni.h
+ * @brief Conversions between AParcel and android.os.Parcel
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= 30
+
+/**
+ * Converts an android.os.Parcel object into an AParcel* object.
+ *
+ * If the parcel is null, null is returned.
+ *
+ * Available since API level 30.
+ *
+ * \param env Java environment. Must not be null.
+ * \param parcel android.os.Parcel java object.
+ *
+ * \return an AParcel object representing the Java parcel object. If either parameter is null, this
+ * will return null. This must be deleted with AParcel_delete. This does not take ownership of the
+ * jobject and is only good for as long as the jobject is alive.
+ */
+__attribute__((warn_unused_result)) AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject parcel)
+ __INTRODUCED_IN(30);
+
+#endif //__ANDROID_API__ >= 30
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 71d8103..f3158d7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -105,6 +105,7 @@
AIBinder_setExtension;
AStatus_getDescription;
AStatus_deleteDescription;
+ AParcel_fromJavaParcel;
AIBinder_markSystemStability; # apex
AIBinder_markVendorStability; # llndk
diff --git a/libs/binder/ndk/parcel_jni.cpp b/libs/binder/ndk/parcel_jni.cpp
new file mode 100644
index 0000000..53b2d7c
--- /dev/null
+++ b/libs/binder/ndk/parcel_jni.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_parcel_jni.h>
+#include "parcel_internal.h"
+
+#include <android_os_Parcel.h>
+
+using ::android::Parcel;
+using ::android::parcelForJavaObject;
+
+AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject jbinder) {
+ if (jbinder == nullptr) {
+ return nullptr;
+ }
+
+ Parcel* parcel = parcelForJavaObject(env, jbinder);
+
+ if (parcel == nullptr) {
+ return nullptr;
+ }
+
+ return new AParcel(nullptr /*binder*/, parcel, false /*shouldOwn*/);
+}
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index e1693cf..00f7484 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -33,16 +33,16 @@
],
shared_libs: [
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
- "vintf-graphics-common-ndk_platform",
],
export_shared_lib_headers: [
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
- "vintf-graphics-common-ndk_platform",
],
export_include_dirs: [
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 354703b..f07c231 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -145,6 +145,12 @@
void GraphicsEnv::hintActivityLaunch() {
ATRACE_CALL();
+ {
+ std::lock_guard<std::mutex> lock(mStatsLock);
+ if (mActivityLaunched) return;
+ mActivityLaunched = true;
+ }
+
std::thread trySendGpuStatsThread([this]() {
// If there's already graphics driver preloaded in the process, just send
// the stats info to GpuStats directly through async binder.
@@ -228,12 +234,11 @@
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
- const bool doNotSend = mGpuStats.appPackageName.empty();
if (api == GpuStatsInfo::Api::API_GL) {
- if (doNotSend) mGpuStats.glDriverToSend = true;
+ mGpuStats.glDriverToSend = true;
mGpuStats.glDriverLoadingTime = driverLoadingTime;
} else {
- if (doNotSend) mGpuStats.vkDriverToSend = true;
+ mGpuStats.vkDriverToSend = true;
mGpuStats.vkDriverLoadingTime = driverLoadingTime;
}
@@ -250,10 +255,18 @@
return interface_cast<IGpuService>(binder);
}
+bool GraphicsEnv::readyToSendGpuStatsLocked() {
+ // Only send stats for processes having at least one activity launched and that process doesn't
+ // skip the GraphicsEnvironment setup.
+ return mActivityLaunched && !mGpuStats.appPackageName.empty();
+}
+
void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
+ if (!readyToSendGpuStatsLocked()) return;
+
const sp<IGpuService> gpuService = getGpuService();
if (gpuService) {
gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats,
@@ -265,8 +278,7 @@
int64_t driverLoadingTime) {
ATRACE_CALL();
- // Do not sendGpuStats for those skipping the GraphicsEnvironment setup
- if (mGpuStats.appPackageName.empty()) return;
+ if (!readyToSendGpuStatsLocked()) return;
ALOGV("sendGpuStats:\n"
"\tdriverPackageName[%s]\n"
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index c6dc1f8..2219074 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -131,6 +131,8 @@
void updateUseAngle();
// Link updatable driver namespace with llndk and vndk-sp libs.
bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
+ // Check whether this process is ready to send stats.
+ bool readyToSendGpuStatsLocked();
// Send the initial complete GpuStats to GpuService.
void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime);
@@ -141,6 +143,8 @@
std::string mSphalLibraries;
// This mutex protects mGpuStats and get gpuservice call.
std::mutex mStatsLock;
+ // Cache the activity launch info
+ bool mActivityLaunched = false;
// Information bookkept for GpuStats.
GpuStatsInfo mGpuStats;
// Path to ANGLE libs.
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 54f383e..8af1a1c 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,7 +36,10 @@
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::ConfigChanged configChanged)
- : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
+ : mLooper(looper),
+ mReceiver(vsyncSource, configChanged),
+ mWaitingForVsync(false),
+ mConfigChangeFlag(configChanged) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -47,17 +50,20 @@
return result;
}
- int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
- if (rc < 0) {
- return UNKNOWN_ERROR;
+ if (mLooper != nullptr) {
+ int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
+ if (rc < 0) {
+ return UNKNOWN_ERROR;
+ }
}
+
return OK;
}
void DisplayEventDispatcher::dispose() {
ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
- if (!mReceiver.initCheck()) {
+ if (!mReceiver.initCheck() && mLooper != nullptr) {
mLooper->removeFd(mReceiver.getFd());
}
}
@@ -86,6 +92,22 @@
return OK;
}
+void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+ if (mConfigChangeFlag == configChangeFlag) {
+ return;
+ }
+ status_t status = mReceiver.toggleConfigEvents(configChangeFlag);
+ if (status) {
+ ALOGW("Failed enable config events, status=%d", status);
+ return;
+ }
+ mConfigChangeFlag = configChangeFlag;
+}
+
+int DisplayEventDispatcher::getFd() {
+ return mReceiver.getFd();
+}
+
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
@@ -140,7 +162,7 @@
break;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
- ev.config.configId);
+ ev.config.configId, ev.config.vsyncPeriod);
break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index b8faa2d..fd6aaf8 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,6 +79,14 @@
return NO_INIT;
}
+status_t DisplayEventReceiver::toggleConfigEvents(
+ ISurfaceComposer::ConfigChanged configChangeFlag) {
+ if (mEventConnection != nullptr) {
+ mEventConnection->toggleConfigEvents(configChangeFlag);
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index c0e246f..dda5acf 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,7 +26,8 @@
STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
SET_VSYNC_RATE,
REQUEST_NEXT_VSYNC,
- LAST = REQUEST_NEXT_VSYNC,
+ TOGGLE_CONFIG_EVENTS,
+ LAST = TOGGLE_CONFIG_EVENTS,
};
} // Anonymous namespace
@@ -53,6 +54,12 @@
callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
Tag::REQUEST_NEXT_VSYNC);
}
+
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override {
+ callRemoteAsync<decltype(
+ &IDisplayEventConnection::toggleConfigEvents)>(Tag::TOGGLE_CONFIG_EVENTS,
+ configChangeFlag);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
@@ -74,6 +81,8 @@
return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
case Tag::REQUEST_NEXT_VSYNC:
return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
+ case Tag::TOGGLE_CONFIG_EVENTS:
+ return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents);
}
}
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f0b7ff5..679d572 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,6 +31,9 @@
status_t initialize();
void dispose();
status_t scheduleVsync();
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+ int getFd();
+ virtual int handleEvent(int receiveFd, int events, void* data);
protected:
virtual ~DisplayEventDispatcher() = default;
@@ -39,14 +42,14 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ ISurfaceComposer::ConfigChanged mConfigChangeFlag;
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) = 0;
+ int32_t configId, nsecs_t vsyncPeriod) = 0;
- virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
uint32_t* outCount);
};
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a558cf9..109e28b 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -73,6 +73,7 @@
struct Config {
int32_t configId;
+ nsecs_t vsyncPeriod;
};
Header header;
@@ -144,6 +145,11 @@
*/
status_t requestNextVsync();
+ /*
+ * toggleConfigEvents() toggles delivery of config change events.
+ */
+ status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index d783f74..8b35ef6 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -18,7 +18,7 @@
#include <binder/IInterface.h>
#include <binder/SafeInterface.h>
-
+#include <gui/ISurfaceComposer.h>
#include <utils/Errors.h>
#include <cstdint>
@@ -51,6 +51,13 @@
* requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
*/
virtual void requestNextVsync() = 0; // Asynchronous
+
+ /*
+ * togglesConfigEvents() configures whether or not display config changes
+ * should be propagated.
+ */
+ virtual void toggleConfigEvents(
+ ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous
};
class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 05ff93e..15d937e 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -17,11 +17,7 @@
#define LOG_TAG "Choreographer"
//#define LOG_NDEBUG 0
-#include <cinttypes>
-#include <queue>
-#include <thread>
-
-#include <android/choreographer.h>
+#include <apex/choreographer.h>
#include <gui/DisplayEventDispatcher.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -29,6 +25,11 @@
#include <utils/Mutex.h>
#include <utils/Timers.h>
+#include <cinttypes>
+#include <optional>
+#include <queue>
+#include <thread>
+
namespace android {
static inline const char* toString(bool value) {
@@ -48,11 +49,18 @@
}
};
+struct RefreshRateCallback {
+ AChoreographer_refreshRateCallback callback;
+ void* data;
+};
class Choreographer : public DisplayEventDispatcher, public MessageHandler {
public:
+ explicit Choreographer(const sp<Looper>& looper);
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
+ void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+ void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
enum {
MSG_SCHEDULE_CALLBACKS = 0,
@@ -61,28 +69,30 @@
virtual void handleMessage(const Message& message) override;
static Choreographer* getForThread();
-
-protected:
virtual ~Choreographer() = default;
private:
- explicit Choreographer(const sp<Looper>& looper);
Choreographer(const Choreographer&) = delete;
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
- void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
+ nsecs_t vsyncPeriod) override;
void scheduleCallbacks();
// Protected by mLock
- std::priority_queue<FrameCallback> mCallbacks;
+ std::priority_queue<FrameCallback> mFrameCallbacks;
+
+ // Protected by mLock
+ std::vector<RefreshRateCallback> mRefreshRateCallbacks;
+ nsecs_t mVsyncPeriod = 0;
mutable Mutex mLock;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
+ const std::optional<PhysicalDisplayId> mInternalDisplayId;
};
@@ -104,9 +114,11 @@
return gChoreographer;
}
-Choreographer::Choreographer(const sp<Looper>& looper) :
- DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
-}
+Choreographer::Choreographer(const sp<Looper>& looper)
+ : DisplayEventDispatcher(looper),
+ mLooper(looper),
+ mThreadId(std::this_thread::get_id()),
+ mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
void Choreographer::postFrameCallbackDelayed(
AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
@@ -114,25 +126,55 @@
FrameCallback callback{cb, cb64, data, now + delay};
{
AutoMutex _l{mLock};
- mCallbacks.push(callback);
+ mFrameCallbacks.push(callback);
}
if (callback.dueTime <= now) {
if (std::this_thread::get_id() != mThreadId) {
- Message m{MSG_SCHEDULE_VSYNC};
- mLooper->sendMessage(this, m);
+ if (mLooper != nullptr) {
+ Message m{MSG_SCHEDULE_VSYNC};
+ mLooper->sendMessage(this, m);
+ } else {
+ scheduleVsync();
+ }
} else {
scheduleVsync();
}
} else {
- Message m{MSG_SCHEDULE_CALLBACKS};
- mLooper->sendMessageDelayed(delay, this, m);
+ if (mLooper != nullptr) {
+ Message m{MSG_SCHEDULE_CALLBACKS};
+ mLooper->sendMessageDelayed(delay, this, m);
+ } else {
+ scheduleCallbacks();
+ }
+ }
+}
+
+void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
+ {
+ AutoMutex _l{mLock};
+ mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
+ toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
+ }
+}
+
+void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
+ {
+ AutoMutex _l{mLock};
+ mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
+ mRefreshRateCallbacks.end(),
+ [&](const RefreshRateCallback& callback) {
+ return cb == callback.callback;
+ }));
+ if (mRefreshRateCallbacks.empty()) {
+ toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
+ }
}
}
void Choreographer::scheduleCallbacks() {
AutoMutex _{mLock};
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mCallbacks.top().dueTime <= now) {
+ if (mFrameCallbacks.top().dueTime <= now) {
ALOGV("choreographer %p ~ scheduling vsync", this);
scheduleVsync();
return;
@@ -147,9 +189,9 @@
{
AutoMutex _l{mLock};
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
- callbacks.push_back(mCallbacks.top());
- mCallbacks.pop();
+ while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
+ callbacks.push_back(mFrameCallbacks.top());
+ mFrameCallbacks.pop();
}
}
for (const auto& cb : callbacks) {
@@ -167,11 +209,25 @@
this, displayId, toString(connected));
}
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
- int32_t configId) {
- ALOGV("choreographer %p ~ received config changed event (displayId=%"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
- this, displayId, toString(configId));
+// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
+// Choreographer only supports dispatching VSYNC events for the internal
+// display, so as such Choreographer does not support the notion of multiple
+// displays. When multi-display choreographer is properly supported, then
+// PhysicalDisplayId should no longer be ignored.
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
+ nsecs_t vsyncPeriod) {
+ {
+ AutoMutex _l{mLock};
+ for (const auto& cb : mRefreshRateCallbacks) {
+ // Only perform the callback when the old refresh rate is different
+ // from the new refresh rate, so that we don't dispatch the callback
+ // on every single configuration change.
+ if (mVsyncPeriod != vsyncPeriod) {
+ cb.callback(vsyncPeriod, cb.data);
+ mVsyncPeriod = vsyncPeriod;
+ }
+ }
+ }
}
void Choreographer::handleMessage(const Message& message) {
@@ -189,7 +245,7 @@
/* Glue for the NDK interface */
-using android::Choreographer;
+using namespace android;
static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
return reinterpret_cast<Choreographer*>(choreographer);
@@ -223,3 +279,41 @@
AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
nullptr, callback, data, ms2ns(delayMillis));
}
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
+}
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback) {
+ AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
+}
+
+AChoreographer* AChoreographer_create() {
+ Choreographer* choreographer = new Choreographer(nullptr);
+ status_t result = choreographer->initialize();
+ if (result != OK) {
+ ALOGW("Failed to initialize");
+ return nullptr;
+ }
+ return Choreographer_to_AChoreographer(choreographer);
+}
+
+void AChoreographer_destroy(AChoreographer* choreographer) {
+ if (choreographer == nullptr) {
+ return;
+ }
+
+ delete AChoreographer_to_Choreographer(choreographer);
+}
+
+int AChoreographer_getFd(AChoreographer* choreographer) {
+ return AChoreographer_to_Choreographer(choreographer)->getFd();
+}
+
+void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* data) {
+ // Pass dummy fd and events args to handleEvent, since the underlying
+ // DisplayEventDispatcher doesn't need them outside of validating that a
+ // Looper instance didn't break, but these args circumvent those checks.
+ AChoreographer_to_Choreographer(choreographer)->handleEvent(-1, Looper::EVENT_INPUT, data);
+}
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 7a497ea..d37b9a1 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
ndk_headers {
- name: "libachoreographer_ndk_headers",
+ name: "libnativedisplay_ndk_headers",
from: "include/android",
to: "android",
srcs: ["include/android/*.h"],
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
new file mode 100644
index 0000000..5251fd3
--- /dev/null
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/choreographer.h>
+#include <inttypes.h>
+
+__BEGIN_DECLS
+
+/**
+ * Prototype of the function that is called when the display refresh rate
+ * changes. It's passed the new vsync period in nanoseconds, as well as the data
+ * pointer provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
+
+/**
+ * Registers a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+
+/**
+ * Unregisters a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback);
+
+/**
+ * Creates an instance of AChoreographer.
+ *
+ * The key differences between this method and AChoreographer_getInstance are:
+ * 1. The returned AChoreographer instance is not a thread-local, and
+ * 2. This method does not require an existing ALooper attached to the thread.
+ */
+AChoreographer* AChoreographer_create();
+
+/**
+ * Destroys a choreographer instance created from AChoreographer_create.
+ */
+void AChoreographer_destroy(AChoreographer* choreographer);
+
+/**
+ * Returns the underlying file descriptor associated with this choreographer
+ * instance.
+ *
+ * The caller can listen to the file descriptor to respond to any AChoreographer
+ * events. One such way is registering the file descriptor to a Looper instance,
+ * although this is not a requirement.
+ */
+int AChoreographer_getFd(AChoreographer* choreographer);
+
+/**
+ * Provides a callback to handle all pending events emitted by this
+ * choreographer instance. Specifically, this delegates to the callbacks
+ * previously registered to choreographer.
+ *
+ * If the associated file descriptor is attached to a Looper instance, then the
+ * callback attached to that Looper is expected to handle exceptional Looper
+ * events.
+ */
+void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* data);
+
+__END_DECLS
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 3b29c18..3b6a241 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -5,6 +5,8 @@
AChoreographer_postFrameCallbackDelayed; # apex # introduced=30
AChoreographer_postFrameCallback64; # apex # introduced=30
AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
+ AChoreographer_registerRefreshRateCallback; # apex # introduced=30
+ AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
local:
*;
};
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 0ba01f4..842af18 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -138,6 +138,11 @@
static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
+ static_assert(static_cast<int>(ADATASPACE_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_ADOBE_RGB));
+ static_assert(static_cast<int>(ADATASPACE_BT2020) == static_cast<int>(HAL_DATASPACE_BT2020));
+ static_assert(static_cast<int>(ADATASPACE_BT709) == static_cast<int>(HAL_DATASPACE_V0_BT709));
+ static_assert(static_cast<int>(ADATASPACE_DCI_P3) == static_cast<int>(HAL_DATASPACE_DCI_P3));
+ static_assert(static_cast<int>(ADATASPACE_SRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SRGB_LINEAR));
if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
!isDataSpaceValid(window, dataSpace)) {
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 2899bcf..e759513 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -101,6 +101,56 @@
* Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
*/
ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+
+ /**
+ * Adobe RGB
+ *
+ * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.2 gamma encoding is not supported in HW.
+ */
+ ADATASPACE_ADOBE_RGB = 151715840, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
+
+ /**
+ * ITU-R Recommendation 2020 (BT.2020)
+ *
+ * Ultra High-definition television
+ *
+ * Use full range, BT.709 transfer and BT2020 standard
+ */
+ ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+ /**
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * Use limited range, BT.709 transfer and BT.709 standard.
+ */
+ ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+ /**
+ * SMPTE EG 432-1 and SMPTE RP 431-2.
+ *
+ * Digital Cinema DCI-P3
+ *
+ * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+ * Note: Application is responsible for gamma encoding the data as
+ * a 2.6 gamma encoding is not supported in HW.
+ */
+ ADATASPACE_DCI_P3 = 155844608, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
+
+ /**
+ * sRGB linear encoding:
+ *
+ * The red, green, and blue components are stored in sRGB space, but
+ * are linear, not gamma-encoded.
+ * The RGB primaries and the white point are the same as BT.709.
+ *
+ * The values are encoded using the full range ([0,255] for 8-bit) for all
+ * components.
+ */
+ ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
};
__END_DECLS
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 124bda2..043f2ca 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -82,6 +82,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -94,14 +95,13 @@
"libsync",
"libutils",
"liblog",
- "vintf-graphics-common-ndk_platform",
],
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
- "vintf-graphics-common-ndk_platform",
],
static_libs: [
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 0d3c821..246e735 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -109,8 +109,14 @@
uint32_t consumeSeq;
InputEvent* event;
+ std::chrono::time_point start = std::chrono::steady_clock::now();
status_t result = WOULD_BLOCK;
while (result == WOULD_BLOCK) {
+ std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
+ if (elapsed > 10ms) {
+ ALOGE("Waited too long for consumer to produce an event, giving up");
+ break;
+ }
result = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq,
&event);
}
@@ -282,12 +288,9 @@
dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
- MotionEvent event = generateMotionEvent();
-
for (auto _ : state) {
+ MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- event.setAction(AMOTION_EVENT_ACTION_DOWN);
- event.setDownTime(now());
dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4766bce..a3cb4f8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -252,6 +252,10 @@
return first->getToken() == second->getToken();
}
+static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+ return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
+}
+
// --- InputDispatcherThread ---
class InputDispatcher::InputDispatcherThread : public Thread {
@@ -743,10 +747,6 @@
#endif
}
-bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
- return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
-}
-
bool InputDispatcher::haveCommandsLocked() const {
return !mCommandQueue.empty();
}
@@ -1111,7 +1111,7 @@
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
+ prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
} else {
if (DEBUG_FOCUS) {
ALOGD("Dropping event delivery to target with channel '%s' because it "
@@ -2045,7 +2045,7 @@
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
- const InputTarget* inputTarget) {
+ const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
@@ -2056,9 +2056,9 @@
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
"windowScaleFactor=(%f, %f), pointerIds=0x%x",
- connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset,
- inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale,
- inputTarget->windowYScale, inputTarget->pointerIds.value);
+ connection->getInputChannelName().c_str(), inputTarget.flags, inputTarget.xOffset,
+ inputTarget.yOffset, inputTarget.globalScaleFactor, inputTarget.windowXScale,
+ inputTarget.windowYScale, inputTarget.pointerIds.value);
#endif
// Skip this event if the connection status is not normal.
@@ -2072,13 +2072,15 @@
}
// Split a motion event if needed.
- if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
- ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
+ if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
+ LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
+ "Entry type %s should not have FLAG_SPLIT",
+ EventEntry::typeToString(eventEntry->type));
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
- if (inputTarget->pointerIds.count() != originalMotionEntry.pointerCount) {
+ if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
MotionEntry* splitMotionEntry =
- splitMotionEvent(originalMotionEntry, inputTarget->pointerIds);
+ splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
if (!splitMotionEntry) {
return; // split event was dropped
}
@@ -2100,7 +2102,7 @@
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
- const InputTarget* inputTarget) {
+ const InputTarget& inputTarget) {
if (ATRACE_ENABLED()) {
std::string message =
StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32
@@ -2133,7 +2135,7 @@
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
- const InputTarget* inputTarget,
+ const InputTarget& inputTarget,
int32_t dispatchMode) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
@@ -2141,7 +2143,7 @@
dispatchModeToString(dispatchMode).c_str());
ATRACE_NAME(message.c_str());
}
- int32_t inputTargetFlags = inputTarget->flags;
+ int32_t inputTargetFlags = inputTarget.flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
}
@@ -2149,11 +2151,11 @@
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
- DispatchEntry* dispatchEntry =
- new DispatchEntry(eventEntry, // increments ref
- inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->globalScaleFactor, inputTarget->windowXScale,
- inputTarget->windowYScale);
+ std::unique_ptr<DispatchEntry> dispatchEntry =
+ std::make_unique<DispatchEntry>(eventEntry, // increments ref
+ inputTargetFlags, inputTarget.xOffset,
+ inputTarget.yOffset, inputTarget.globalScaleFactor,
+ inputTarget.windowXScale, inputTarget.windowYScale);
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
@@ -2168,7 +2170,6 @@
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
connection->getInputChannelName().c_str());
#endif
- delete dispatchEntry;
return; // skip the inconsistent event
}
break;
@@ -2215,12 +2216,11 @@
"event",
connection->getInputChannelName().c_str());
#endif
- delete dispatchEntry;
return; // skip the inconsistent event
}
dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
- inputTarget->inputChannel->getConnectionToken());
+ inputTarget.inputChannel->getConnectionToken());
break;
}
@@ -2238,7 +2238,7 @@
}
// Enqueue the dispatch entry.
- connection->outboundQueue.push_back(dispatchEntry);
+ connection->outboundQueue.push_back(dispatchEntry.release());
traceOutboundQueueLength(connection);
}
@@ -2625,7 +2625,7 @@
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
- &target, InputTarget::FLAG_DISPATCH_AS_IS);
+ target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 96a09e3..50b5250 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -168,9 +168,6 @@
bool isAppSwitchPendingLocked() REQUIRES(mLock);
void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
- // Stale event latency optimization.
- static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
-
// Blocked event latency optimization. Drops old events when the user intends
// to transfer focus to a new application.
EventEntry* mNextUnblockedEvent GUARDED_BY(mLock);
@@ -381,13 +378,13 @@
// with the mutex held makes it easier to ensure that connection invariants are maintained.
// If needed, the methods post commands to run later once the critical bits are done.
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget)
+ EventEntry* eventEntry, const InputTarget& inputTarget)
REQUIRES(mLock);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget)
+ EventEntry* eventEntry, const InputTarget& inputTarget)
REQUIRES(mLock);
void enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry,
- const InputTarget* inputTarget, int32_t dispatchMode)
+ const InputTarget& inputTarget, int32_t dispatchMode)
REQUIRES(mLock);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 2e9bca2..1ba5eff 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -108,7 +108,7 @@
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
- BitSet32 pointerIds{};
+ BitSet32 pointerIds;
};
std::string dispatchModeToString(int32_t dispatchMode);
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 945abd7..e4e4bc7 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -455,6 +455,10 @@
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
+
+ const int32_t layerId = getSequence();
+ mFlinger->mFrameTracer->traceTimestamp(layerId, item.mGraphicBuffer->getId(), item.mFrameNumber,
+ systemTime(), FrameTracer::FrameEvent::QUEUE);
mConsumer->onBufferAvailable(item);
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index ff800c3..5bdef58 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -103,10 +103,11 @@
}
DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId,
- HwcConfigIndexType configId) {
+ HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
event.config.configId = configId.value();
+ event.config.vsyncPeriod = vsyncPeriod;
return event;
}
@@ -116,7 +117,7 @@
ResyncCallback resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
- configChanged(configChanged),
+ mConfigChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -145,6 +146,18 @@
mEventThread->requestNextVsync(this);
}
+void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+ ATRACE_NAME("enableConfigEvents");
+ mConfigChanged = configChangeFlag;
+
+ // In principle it's possible for rapidly toggling config events to drop an
+ // event here, but it's unlikely in practice.
+ if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) {
+ mForcedConfigChangeDispatch = true;
+ mEventThread->requestLatestConfig();
+ }
+}
+
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -257,6 +270,24 @@
}
}
+void EventThread::requestLatestConfig() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ auto pendingConfigChange =
+ std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
+ [&](const DisplayEventReceiver::Event& event) {
+ return event.header.type ==
+ DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED;
+ });
+
+ // If we didn't find a pending config change event, then push out the
+ // latest one we've ever seen.
+ if (pendingConfigChange == std::end(mPendingEvents)) {
+ mPendingEvents.push_back(mLastConfigChangeEvent);
+ }
+
+ mCondition.notify_all();
+}
+
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
if (!mVSyncState || mVSyncState->synthetic) {
@@ -292,10 +323,11 @@
mCondition.notify_all();
}
-void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) {
+void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeConfigChanged(displayId, configId));
+ mPendingEvents.push_back(makeConfigChanged(displayId, configId, vsyncPeriod));
mCondition.notify_all();
}
@@ -325,6 +357,9 @@
mInterceptVSyncsCallback(event->header.timestamp);
}
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ mLastConfigChangeEvent = *event;
+ break;
}
}
@@ -398,8 +433,11 @@
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
return true;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
+ const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false);
+ return forcedDispatch ||
+ connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+ }
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a42546c..641b2a5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,12 +81,19 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override;
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- const ISurfaceComposer::ConfigChanged configChanged;
+ std::atomic<ISurfaceComposer::ConfigChanged> mConfigChanged =
+ ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
+ // Store whether we need to force dispatching a config change separately -
+ // if mConfigChanged ever changes before the config change is dispatched
+ // then we still need to propagate an initial config to the app if we
+ // haven't already.
+ std::atomic<bool> mForcedConfigChangeDispatch = false;
private:
virtual void onFirstRef();
@@ -110,7 +117,8 @@
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
// called when SF changes the active config and apps needs to be notified about the change
- virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) = 0;
+ virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) = 0;
virtual void dump(std::string& result) const = 0;
@@ -121,6 +129,11 @@
virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
// Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+
+ // Dispatches the most recent configuration
+ // Usage of this method assumes that only the primary internal display
+ // supports multiple display configurations.
+ virtual void requestLatestConfig() = 0;
};
namespace impl {
@@ -138,6 +151,7 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ void requestLatestConfig() override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -147,7 +161,8 @@
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
- void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) override;
+ void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) override;
void dump(std::string& result) const override;
@@ -182,6 +197,7 @@
std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+ DisplayEventReceiver::Event mLastConfigChangeEvent GUARDED_BY(mMutex);
// VSYNC state of connected display.
struct VSyncState {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 847e20c..692ded9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -126,7 +126,7 @@
return BAD_VALUE;
}
const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
- if (refreshRate.fps < minRefreshRate || refreshRate.fps > maxRefreshRate) {
+ if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
return BAD_VALUE;
}
mDefaultConfig = defaultConfigId;
@@ -180,8 +180,8 @@
group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- return refreshRate.configGroup == group && refreshRate.fps >= mMinRefreshRateFps &&
- refreshRate.fps <= mMaxRefreshRateFps;
+ return refreshRate.configGroup == group &&
+ refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
},
&mAvailableRefreshRates);
LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 1e740ca..0c3369a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -44,6 +44,9 @@
class RefreshRateConfigs {
public:
struct RefreshRate {
+ // The tolerance within which we consider FPS approximately equals.
+ static constexpr float FPS_EPSILON = 0.001f;
+
RefreshRate(HwcConfigIndexType configId, nsecs_t vsyncPeriod,
HwcConfigGroupType configGroup, std::string name, float fps)
: configId(configId),
@@ -63,6 +66,12 @@
// Refresh rate in frames per second
const float fps = 0;
+ // Checks whether the fps of this RefreshRate struct is within a given min and max refresh
+ // rate passed in. FPS_EPSILON is applied to the boundaries for approximation.
+ bool inPolicy(float minRefreshRate, float maxRefreshRate) const {
+ return (fps >= (minRefreshRate - FPS_EPSILON) && fps <= (maxRefreshRate + FPS_EPSILON));
+ }
+
bool operator!=(const RefreshRate& other) const {
return configId != other.configId || vsyncPeriod != other.vsyncPeriod ||
configGroup != other.configGroup;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index e845e8c..ff9cf86 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -222,9 +222,9 @@
}
void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- HwcConfigIndexType configId) {
+ HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onConfigChanged(displayId, configId);
+ mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
}
void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 2fa8b3f..2cdb757 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -74,7 +74,8 @@
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId);
+ void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index c471e49..a652053 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -154,7 +154,7 @@
mTracker->addVsyncTimestamp(signalTime);
}
- return false; // TODO(b/144707443): add policy for turning on HWVsync.
+ return mMoreSamplesNeeded;
}
void VSyncReactor::setIgnorePresentFences(bool ignoration) {
@@ -176,14 +176,9 @@
}
void VSyncReactor::setPeriod(nsecs_t period) {
- mTracker->setPeriod(period);
- {
- std::lock_guard<std::mutex> lk(mMutex);
- mPeriodChangeInProgress = true;
- for (auto& entry : mCallbacks) {
- entry.second->setPeriod(period);
- }
- }
+ std::lock_guard lk(mMutex);
+ mLastHwVsync.reset();
+ mPeriodTransitioningTo = period;
}
nsecs_t VSyncReactor::getPeriod() {
@@ -194,15 +189,40 @@
void VSyncReactor::endResync() {}
+bool VSyncReactor::periodChangeDetected(nsecs_t vsync_timestamp) {
+ if (!mLastHwVsync || !mPeriodTransitioningTo) {
+ return false;
+ }
+ auto const distance = vsync_timestamp - *mLastHwVsync;
+ return std::abs(distance - *mPeriodTransitioningTo) < std::abs(distance - getPeriod());
+}
+
bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
assert(periodFlushed);
- mTracker->addVsyncTimestamp(timestamp);
- {
- std::lock_guard<std::mutex> lk(mMutex);
- *periodFlushed = mPeriodChangeInProgress;
- mPeriodChangeInProgress = false;
+
+ std::lock_guard<std::mutex> lk(mMutex);
+ if (periodChangeDetected(timestamp)) {
+ mMoreSamplesNeeded = false;
+ *periodFlushed = true;
+
+ mTracker->setPeriod(*mPeriodTransitioningTo);
+ for (auto& entry : mCallbacks) {
+ entry.second->setPeriod(*mPeriodTransitioningTo);
+ }
+
+ mPeriodTransitioningTo.reset();
+ mLastHwVsync.reset();
+ } else if (mPeriodTransitioningTo) {
+ mLastHwVsync = timestamp;
+ mMoreSamplesNeeded = true;
+ *periodFlushed = false;
+ } else {
+ mMoreSamplesNeeded = false;
+ *periodFlushed = false;
}
- return false;
+
+ mTracker->addVsyncTimestamp(timestamp);
+ return mMoreSamplesNeeded;
}
status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase,
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 29a0a11..73a5e37 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -61,6 +61,8 @@
void reset() final;
private:
+ bool periodChangeDetected(nsecs_t vsync_timestamp) REQUIRES(mMutex);
+
std::unique_ptr<Clock> const mClock;
std::unique_ptr<VSyncTracker> const mTracker;
std::unique_ptr<VSyncDispatch> const mDispatch;
@@ -69,7 +71,11 @@
std::mutex mMutex;
bool mIgnorePresentFences GUARDED_BY(mMutex) = false;
std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex);
- bool mPeriodChangeInProgress GUARDED_BY(mMutex) = false;
+
+ bool mMoreSamplesNeeded GUARDED_BY(mMutex) = false;
+ std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
+ std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
+
std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
GUARDED_BY(mMutex);
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d02d783..8c1d168 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -953,8 +953,11 @@
ATRACE_INT("ActiveConfigFPS", refreshRate.fps);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId)
+ .vsyncPeriod;
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
- mUpcomingActiveConfig.configId);
+ mUpcomingActiveConfig.configId, vsyncPeriod);
}
}
@@ -2688,6 +2691,17 @@
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
RegionSamplingThread::EnvironmentTimingTunables());
+ // Dispatch a config change request for the primary display on scheduler
+ // initialization, so that the EventThreads always contain a reference to a
+ // prior configuration.
+ //
+ // This is a bit hacky, but this avoids a back-pointer into the main SF
+ // classes from EventThread, and there should be no run-time binder cost
+ // anyway since there are no connected apps at this point.
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).vsyncPeriod;
+ mScheduler->onConfigChanged(mAppConnectionHandle, primaryDisplayId.value, currentConfig,
+ vsyncPeriod);
}
void SurfaceFlinger::commitTransaction()
@@ -5577,7 +5591,10 @@
auto configId = HwcConfigIndexType(defaultConfig);
display->setActiveConfig(configId);
- mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(configId).vsyncPeriod;
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId,
+ vsyncPeriod);
return NO_ERROR;
}
@@ -5601,8 +5618,10 @@
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
// Giving current ActiveConfig so that most other listeners would just drop the event
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()).vsyncPeriod;
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
- display->getActiveConfig());
+ display->getActiveConfig(), vsyncPeriod);
if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
auto configId = mScheduler->getPreferredConfigId();
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index aea602b..d3942e8 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -2,6 +2,7 @@
class core animation
user system
group graphics drmrpc readproc
+ capabilities SYS_NICE
onrestart restart zygote
writepid /dev/stune/foreground/tasks
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index dcfc077..0403237 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -42,6 +42,7 @@
"libtrace_proto",
],
shared_libs: [
+ "android.hardware.graphics.common-ndk_platform",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"libandroid",
@@ -52,12 +53,15 @@
"libgui",
"liblayers_proto",
"liblog",
+ "libnativewindow",
"libprotobuf-cpp-full",
"libtimestats_proto",
"libui",
"libutils",
- "vintf-graphics-common-ndk_platform",
- ]
+ ],
+ header_libs: [
+ "libnativewindow_headers",
+ ],
}
cc_defaults {
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
index ab4af09..25b4615 100644
--- a/services/surfaceflinger/tests/CommonTypes_test.cpp
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -16,6 +16,7 @@
#include <aidl/android/hardware/graphics/common/BlendMode.h>
#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <android/data_space.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
@@ -34,6 +35,51 @@
static_assert(static_cast<uint32_t>(AidlBlendMode::COVERAGE) ==
static_cast<uint32_t>(HidlBlendMode::COVERAGE));
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+ static_cast<uint32_t>(AidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+ static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) == static_cast<uint32_t>(AidlDataspace::SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+ static_cast<uint32_t>(AidlDataspace::SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+ static_cast<uint32_t>(AidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+ static_cast<uint32_t>(AidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+ static_cast<uint32_t>(AidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+ static_cast<uint32_t>(AidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+ static_cast<uint32_t>(AidlDataspace::BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+ static_cast<uint32_t>(AidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+ static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR));
+
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+ static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+
static_assert(static_cast<uint32_t>(AidlDataspace::UNKNOWN) ==
static_cast<uint32_t>(HidlDataspace::UNKNOWN));
static_assert(static_cast<uint32_t>(AidlDataspace::ARBITRARY) ==
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 420fb29..d51b9a1 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -31,42 +31,40 @@
void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
sp<IBinder> mDisplayToken;
- int32_t defaultConfigId;
- float minRefreshRate;
- float maxRefreshRate;
};
-TEST_F(RefreshRateRangeTest, simpleSetAndGet) {
- status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
- EXPECT_EQ(res, NO_ERROR);
+TEST_F(RefreshRateRangeTest, setAllConfigs) {
+ int32_t initialDefaultConfig;
+ float initialMin;
+ float initialMax;
+ status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+ &initialDefaultConfig,
+ &initialMin, &initialMax);
+ ASSERT_EQ(res, NO_ERROR);
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 1);
- EXPECT_EQ(minRefreshRate, 45);
- EXPECT_EQ(maxRefreshRate, 75);
+ Vector<DisplayInfo> configs;
+ res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+ ASSERT_EQ(res, NO_ERROR);
+
+ for (size_t i = 0; i < configs.size(); i++) {
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, configs[i].fps,
+ configs[i].fps);
+ ASSERT_EQ(res, NO_ERROR);
+
+ int defaultConfig;
+ float minFps;
+ float maxFps;
+ res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &minFps, &maxFps);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(defaultConfig, i);
+ ASSERT_EQ(minFps, configs[i].fps);
+ ASSERT_EQ(maxFps, configs[i].fps);
+ }
+
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
+ initialMin, initialMax);
+ ASSERT_EQ(res, NO_ERROR);
}
-TEST_F(RefreshRateRangeTest, complexSetAndGet) {
- status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
- EXPECT_EQ(res, NO_ERROR);
-
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 1);
- EXPECT_EQ(minRefreshRate, 45);
- EXPECT_EQ(maxRefreshRate, 75);
-
- // Second call overrides the first one.
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 10, 145, 875);
- EXPECT_EQ(res, NO_ERROR);
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 10);
- EXPECT_EQ(minRefreshRate, 145);
- EXPECT_EQ(maxRefreshRate, 875);
-}
} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 7786638..2bedd7d 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "*:-RefreshRateRangeTest.*:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
+ "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
}
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80bca02..61d4f47 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -85,7 +85,8 @@
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
- int32_t expectedConfigId);
+ int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -209,13 +210,15 @@
}
void EventThreadTest::expectConfigChangedEventReceivedByConnection(
- PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+ PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConfigId, event.config.configId);
+ EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
}
namespace {
@@ -450,18 +453,18 @@
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7));
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5));
- expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+ mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5), 16666666);
+ expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7));
- expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+ mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
TEST_F(EventThreadTest, suppressConfigChanged) {
@@ -470,8 +473,8 @@
createConnection(suppressConnectionEventRecorder,
ISurfaceComposer::eConfigChangedSuppress);
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9));
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
ASSERT_FALSE(args.has_value());
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index ed620ef..cc3c985 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -39,6 +39,7 @@
static inline const HwcConfigGroupType HWC_GROUP_ID_0 = HwcConfigGroupType(0);
static inline const HwcConfigGroupType HWC_GROUP_ID_1 = HwcConfigGroupType(1);
static constexpr int64_t VSYNC_60 = 16666667;
+ static constexpr int64_t VSYNC_60_POINT_4 = 16666665;
static constexpr int64_t VSYNC_90 = 11111111;
RefreshRateConfigsTest();
@@ -238,6 +239,16 @@
ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f));
}
+TEST_F(RefreshRateConfigsTest, testInPolicy) {
+ RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60_POINT_4, HWC_GROUP_ID_0,
+ "60fps", 60};
+ ASSERT_TRUE(expectedDefaultConfig.inPolicy(60.000004, 60.000004));
+ ASSERT_TRUE(expectedDefaultConfig.inPolicy(59.0f, 60.1f));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(75.0, 90.0));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(60.0011, 90.0));
+ ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0, 59.998));
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 537cc80..72f8bb9 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -159,7 +159,6 @@
static constexpr nsecs_t mPhase = 3000;
static constexpr nsecs_t mAnotherPhase = 5200;
static constexpr nsecs_t period = 10000;
- static constexpr nsecs_t mAnotherPeriod = 23333;
static constexpr nsecs_t mFakeCbTime = 2093;
static constexpr nsecs_t mFakeNow = 2214;
static constexpr const char mName[] = "callbacky";
@@ -274,10 +273,38 @@
EXPECT_THAT(mReactor.getPeriod(), Eq(fakePeriod));
}
-TEST_F(VSyncReactorTest, setPeriod) {
- nsecs_t const fakePeriod = 4098;
- EXPECT_CALL(*mMockTracker, setPeriod(fakePeriod));
- mReactor.setPeriod(fakePeriod);
+TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) {
+ nsecs_t const newPeriod = 5000;
+ EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+ mReactor.setPeriod(newPeriod);
+
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(10000, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addResyncSample(20000, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+ EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+
+ EXPECT_FALSE(mReactor.addResyncSample(25000, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) {
+ nsecs_t const newPeriod = 5000;
+ EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+ mReactor.setPeriod(newPeriod);
+
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(5000, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+ EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+ EXPECT_FALSE(mReactor.addResyncSample(10000, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
}
TEST_F(VSyncReactorTest, addResyncSampleTypical) {
@@ -291,12 +318,43 @@
TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) {
bool periodFlushed = false;
- nsecs_t const fakeTimestamp = 4398;
- nsecs_t const newPeriod = 3490;
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp));
+ nsecs_t const newPeriod = 4000;
+
mReactor.setPeriod(newPeriod);
- EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, &periodFlushed));
+
+ auto time = 0;
+ auto constexpr numTimestampSubmissions = 10;
+ for (auto i = 0; i < numTimestampSubmissions; i++) {
+ time += period;
+ EXPECT_TRUE(mReactor.addResyncSample(time, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ }
+
+ time += newPeriod;
+ EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed));
EXPECT_TRUE(periodFlushed);
+
+ for (auto i = 0; i < numTimestampSubmissions; i++) {
+ time += newPeriod;
+ EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ }
+}
+
+TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
+ auto time = 0;
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+ mReactor.setPeriod(newPeriod);
+
+ time += period;
+ mReactor.addResyncSample(time, &periodFlushed);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+ time += newPeriod;
+ mReactor.addResyncSample(time, &periodFlushed);
+
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
}
static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
@@ -399,20 +457,26 @@
mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
}
-TEST_F(VSyncReactorTest, changingPeriodChangesOfsetsOnNextCb) {
+TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) {
+ static constexpr nsecs_t anotherPeriod = 23333;
Sequence seq;
EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
.InSequence(seq)
.WillOnce(Return(mFakeToken));
EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
.InSequence(seq);
- EXPECT_CALL(*mMockTracker, setPeriod(mAnotherPeriod));
+ EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod));
EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(mAnotherPeriod, mPhase), mFakeNow))
+ schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow))
.InSequence(seq);
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.setPeriod(mAnotherPeriod);
+
+ bool periodFlushed = false;
+ mReactor.setPeriod(anotherPeriod);
+ EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, &periodFlushed));
+
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index f7c3804..9bda095 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,13 +33,14 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType));
+ MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD0(requestLatestConfig, void());
MOCK_METHOD1(pauseVsyncCallback, void(bool));
};