Merge "Add isUidActiveOrForeground for camera/audio to use." into rvc-dev
diff --git a/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png
new file mode 100644
index 0000000..1acc59d
--- /dev/null
+++ b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png
new file mode 100644
index 0000000..4ab9ca4
--- /dev/null
+++ b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png
new file mode 100644
index 0000000..d74e673
--- /dev/null
+++ b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png
Binary files differ
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8ca178c..7ca9031 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -404,6 +404,13 @@
*/
bool hasPendingBatch() const;
+ /* Returns the source of first pending batch if exist.
+ *
+ * Should be called after calling consume() with consumeBatches == false to determine
+ * whether consume() should be called again later on with consumeBatches == true.
+ */
+ int32_t getPendingBatchSource() const;
+
private:
// True if touch resampling is enabled.
const bool mResampleTouch;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index bc541f4..e6cfeb4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -158,7 +158,9 @@
filegroup {
name: "libbinder_aidl",
srcs: [
+ "aidl/android/content/pm/IPackageChangeObserver.aidl",
"aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/content/pm/PackageChangeEvent.aidl",
"aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
new file mode 100644
index 0000000..6929a6c
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+import android.content.pm.PackageChangeEvent;
+
+/**
+ * This is a non-blocking notification when a package has changed.
+ *
+ * @hide
+ */
+oneway interface IPackageChangeObserver {
+ void onPackageChanged(in PackageChangeEvent event);
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 618f88c..dc8d74c 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -17,6 +17,8 @@
package android.content.pm;
+import android.content.pm.IPackageChangeObserver;
+
/**
* Parallel implementation of certain {@link PackageManager} APIs that need to
* be exposed to native code.
@@ -90,4 +92,13 @@
/* Returns the names of all packages. */
@utf8InCpp String[] getAllPackages();
+
+ /** Register an extra package change observer to receive the multi-cast. */
+ void registerPackageChangeObserver(in IPackageChangeObserver observer);
+
+ /**
+ * Unregister an existing package change observer.
+ * This does nothing if this observer was not already registered.
+ */
+ void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
}
diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl
new file mode 100644
index 0000000..e30e907
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+/**
+ * This event is designed for notification to native code listener about
+ * any changes on a package including update, deletion and etc.
+ *
+ * @hide
+ */
+parcelable PackageChangeEvent {
+ @utf8InCpp String packageName;
+ long version;
+ long lastUpdateTimeMillis;
+ boolean newInstalled;
+ boolean dataRemoved;
+ boolean isDeleted;
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 5b65c95..b2b74dc 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -75,6 +75,7 @@
"android.hardware.automotive.audiocontrol@1.0::IAudioControl",
"android.hardware.automotive.vehicle@2.0::IVehicle",
"android.hardware.automotive.evs@1.0::IEvsCamera",
+ "android.hardware.neuralnetworks@1.0::IDevice",
NULL,
};
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 7335b30..ef7cc7d 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -1130,6 +1130,16 @@
return !mBatches.isEmpty();
}
+int32_t InputConsumer::getPendingBatchSource() const {
+ if (mBatches.isEmpty()) {
+ return AINPUT_SOURCE_CLASS_NONE;
+ }
+
+ const Batch& batch = mBatches.itemAt(0);
+ const InputMessage& head = batch.samples.itemAt(0);
+ return head.body.motion.source;
+}
+
ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
for (size_t i = 0; i < mBatches.size(); i++) {
const Batch& batch = mBatches.itemAt(i);
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index 8ff0711..c3da216 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -40,4 +40,8 @@
cflags: [
"-DLOG_TAG=\"AutomotiveDisplayService\""
],
+
+ vintf_fragments: [
+ "manifest_android.frameworks.automotive.display@1.0.xml",
+ ],
}
diff --git a/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml
new file mode 100644
index 0000000..464dcac
--- /dev/null
+++ b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.automotive.display</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IAutomotiveDisplayProxyService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 4ec4e25..f67c9d0 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -52,7 +52,6 @@
"libstatslog",
"libutils",
"libui",
- "server_configurable_flags",
],
}
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 8ba1f7f..77a0716 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -27,7 +27,6 @@
#if defined(__linux__)
#include <pthread.h>
#endif
-#include <server_configurable_flags/get_flags.h>
#include <unordered_set>
#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
@@ -46,11 +45,6 @@
namespace android {
-// Category (=namespace) name for the input settings that are applied at boot time
-static const char* INPUT_NATIVE_BOOT = "input_native_boot";
-// Feature flag name for the deep press feature
-static const char* DEEP_PRESS_ENABLED = "deep_press_enabled";
-
//Max number of elements to store in mEvents.
static constexpr size_t MAX_EVENTS = 5;
@@ -77,20 +71,6 @@
return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN;
}
-// Check if the "deep touch" feature is on.
-static bool deepPressEnabled() {
- std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
- INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
- std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
- if (flag_value == "1" || flag_value == "true") {
- ALOGI("Deep press feature enabled.");
- return true;
- }
- ALOGI("Deep press feature is not enabled.");
- return false;
-}
-
-
// --- ClassifierEvent ---
ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -157,12 +137,6 @@
std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
sp<android::hardware::hidl_death_recipient> deathRecipient) {
- if (!deepPressEnabled()) {
- // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work.
- // When MotionClassifier is null, InputClassifier will forward all events
- // to the next InputListener, unmodified.
- return nullptr;
- }
sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
classifier::V1_0::IInputClassifier::getService();
if (!service) {
@@ -372,14 +346,25 @@
// --- InputClassifier ---
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener)
- : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {
- mInitializeMotionClassifierThread = std::thread(
- [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
+ : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
+
+void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+ if (enabled) {
+ ALOGI("Enabling motion classifier");
+ if (mInitializeMotionClassifierThread.joinable()) {
+ mInitializeMotionClassifierThread.join();
+ }
+ mInitializeMotionClassifierThread = std::thread(
+ [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
#if defined(__linux__)
- // Set the thread name for debugging
- pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
- "Create MotionClassifier");
+ // Set the thread name for debugging
+ pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
+ "Create MotionClassifier");
#endif
+ } else {
+ ALOGI("Disabling motion classifier");
+ setMotionClassifier(nullptr);
+ }
}
void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
@@ -429,8 +414,6 @@
void InputClassifier::dump(std::string& dump) {
std::scoped_lock lock(mLock);
dump += "Input Classifier State:\n";
- dump += StringPrintf(INDENT1 "Deep press: %s\n", deepPressEnabled() ? "enabled" : "disabled");
-
dump += INDENT1 "Motion Classifier:\n";
if (mMotionClassifier) {
mMotionClassifier->dump(dump);
@@ -441,7 +424,9 @@
}
InputClassifier::~InputClassifier() {
- mInitializeMotionClassifierThread.join();
+ if (mInitializeMotionClassifierThread.joinable()) {
+ mInitializeMotionClassifierThread.join();
+ }
}
} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 8f58695..03510a6 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -90,6 +90,7 @@
*/
class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
public:
+ virtual void setMotionClassifierEnabled(bool enabled) = 0;
/**
* Dump the state of the input classifier.
* This method may be called on any thread (usually by the input manager).
@@ -234,6 +235,9 @@
~InputClassifier();
+ // Called from InputManager
+ virtual void setMotionClassifierEnabled(bool enabled) override;
+
private:
// Protect access to mMotionClassifier, since it may become null via a hidl callback
std::mutex mLock;
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index c7c61cf..fc771a2 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -132,4 +132,8 @@
mDispatcher->unregisterInputChannel(channel);
}
+void InputManager::setMotionClassifierEnabled(bool enabled) {
+ mClassifier->setMotionClassifierEnabled(enabled);
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 586097f..0158441 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -100,6 +100,8 @@
virtual void registerInputChannel(const sp<InputChannel>& channel);
virtual void unregisterInputChannel(const sp<InputChannel>& channel);
+ void setMotionClassifierEnabled(bool enabled);
+
private:
sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index b4e755a..ab74a04 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -135,6 +135,28 @@
ASSERT_EQ(args, outArgs);
}
+TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) {
+ mClassifier->setMotionClassifierEnabled(true);
+}
+
+TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) {
+ mClassifier->setMotionClassifierEnabled(false);
+}
+
+/**
+ * Try to break it by calling setMotionClassifierEnabled multiple times.
+ */
+TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) {
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(false);
+ mClassifier->setMotionClassifierEnabled(false);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+}
+
/**
* A minimal implementation of IInputClassifier.
*/
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
index acaaf4e..2d9f01b 100644
--- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -35,7 +35,8 @@
return lhs.geometry == rhs.geometry && lhs.alpha == rhs.alpha &&
lhs.sourceDataspace == rhs.sourceDataspace &&
lhs.colorTransform == rhs.colorTransform &&
- lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow;
+ lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow &&
+ lhs.backgroundBlurRadius == rhs.backgroundBlurRadius;
}
inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index e740b13..b738096 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -29,6 +29,7 @@
PowerAdvisor();
~PowerAdvisor() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
MOCK_METHOD0(notifyDisplayUpdateImminent, void());
};
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 06e0cbb..1d8179c 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -72,6 +72,10 @@
}
}
+void PowerAdvisor::onBootFinished() {
+ mBootFinished.store(true);
+}
+
void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
if (expected) {
mExpensiveDisplays.insert(displayId);
@@ -97,6 +101,12 @@
}
void PowerAdvisor::notifyDisplayUpdateImminent() {
+ // Only start sending this notification once the system has booted so we don't introduce an
+ // early-boot dependency on Power HAL
+ if (!mBootFinished.load()) {
+ return;
+ }
+
if (mSendUpdateImminent.load()) {
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper == nullptr) {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 957d289..4a90acb 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -35,6 +35,7 @@
public:
virtual ~PowerAdvisor();
+ virtual void onBootFinished() = 0;
virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
virtual void notifyDisplayUpdateImminent() = 0;
};
@@ -56,12 +57,14 @@
PowerAdvisor();
~PowerAdvisor() override;
+ void onBootFinished() override;
void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
void notifyDisplayUpdateImminent() override;
private:
HalWrapper* getPowerHal();
+ std::atomic_bool mBootFinished = false;
bool mReconnectPowerHal = false;
std::unordered_set<DisplayId> mExpensiveDisplays;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 776e984..4e3f85f 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -30,6 +30,7 @@
#include "EventThread.h"
namespace android {
+using base::StringAppendF;
DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name)
@@ -107,6 +108,12 @@
}
}
+void DispSyncSource::dump(std::string& result) const {
+ std::lock_guard lock(mVsyncMutex);
+ StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
+ mDispSync->dump(result);
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 328b8c1..f278712 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -36,6 +36,8 @@
void setCallback(VSyncSource::Callback* callback) override;
void setPhaseOffset(nsecs_t phaseOffset) override;
+ void dump(std::string&) const override;
+
private:
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
@@ -52,7 +54,7 @@
std::mutex mCallbackMutex;
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
- std::mutex mVsyncMutex;
+ mutable std::mutex mVsyncMutex;
TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index acab5a6..0d6a92e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -425,7 +425,12 @@
// display is off, keep feeding clients at 60 Hz.
const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms;
if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
- ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall");
+ if (mState == State::VSync) {
+ ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
+ std::string debugInfo = "VsyncSource debug info:\n";
+ mVSyncSource->dump(debugInfo);
+ ALOGW("%s", debugInfo.c_str());
+ }
LOG_FATAL_IF(!mVSyncState);
mPendingEvents.push_back(makeVSync(mVSyncState->displayId,
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 466234d..98b1876 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -66,6 +66,8 @@
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(Callback* callback) = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+
+ virtual void dump(std::string& result) const = 0;
};
class EventThreadConnection : public BnDisplayEventConnection {
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index fa46e6f..31da588 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -45,6 +45,7 @@
const char* getName() const override { return "inject"; }
void setVSyncEnabled(bool) override {}
void setPhaseOffset(nsecs_t) override {}
+ void dump(std::string&) const override {}
private:
std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index c04447d..43883fb 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -36,6 +36,19 @@
return std::abs(fpsA - fpsB) <= MARGIN;
}
+std::vector<float> getRefreshRatesFromConfigs(
+ const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
+ const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
+ std::vector<float> refreshRates;
+ refreshRates.reserve(allRefreshRates.size());
+
+ for (const auto& [ignored, refreshRate] : allRefreshRates) {
+ refreshRates.emplace_back(refreshRate->fps);
+ }
+
+ return refreshRates;
+}
+
} // namespace
namespace android::scheduler {
@@ -45,14 +58,21 @@
namespace impl {
PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
- : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
- // for the N+2 vsync instead of N+1. This means that:
- // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
- // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
- mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
- .value_or(std::numeric_limits<nsecs_t>::max())),
- mOffsets(initializeOffsets(refreshRateConfigs)),
- mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
+ : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
+ refreshRateConfigs.getCurrentRefreshRate().fps,
+ // Below defines the threshold when an offset is considered to be negative,
+ // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
+ // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
+ // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
+ // vsync.
+ getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max())) {}
+
+PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
+ nsecs_t thresholdForNextVsync)
+ : mThresholdForNextVsync(thresholdForNextVsync),
+ mOffsets(initializeOffsets(refreshRates)),
+ mRefreshRateFps(currentFps) {}
void PhaseOffsets::dump(std::string& result) const {
const auto [early, earlyGl, late] = getCurrentOffsets();
@@ -67,19 +87,24 @@
}
std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
- const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
+ const std::vector<float>& refreshRates) const {
std::unordered_map<float, Offsets> offsets;
- for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
- if (refreshRate->fps > 65.0f) {
- offsets.emplace(refreshRate->fps, getHighFpsOffsets(refreshRate->vsyncPeriod));
- } else {
- offsets.emplace(refreshRate->fps, getDefaultOffsets(refreshRate->vsyncPeriod));
- }
+ for (const auto& refreshRate : refreshRates) {
+ offsets.emplace(refreshRate,
+ getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate)));
}
return offsets;
}
+PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const {
+ if (fps > 65.0f) {
+ return getHighFpsOffsets(vsyncPeriod);
+ } else {
+ return getDefaultOffsets(vsyncPeriod);
+ }
+}
+
PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
@@ -159,8 +184,15 @@
[&fps](const std::pair<float, Offsets>& candidateFps) {
return fpsEqualsWithMargin(fps, candidateFps.first);
});
- LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
- return iter->second;
+
+ if (iter != mOffsets.end()) {
+ return iter->second;
+ }
+
+ // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
+ // In this case just construct the offset.
+ ALOGW("Can't find offset for %.2f fps", fps);
+ return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
}
static void validateSysprops() {
@@ -231,19 +263,6 @@
};
}
-static std::vector<float> getRefreshRatesFromConfigs(
- const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
- const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
- std::vector<float> refreshRates;
- refreshRates.reserve(allRefreshRates.size());
-
- for (const auto& [ignored, refreshRate] : allRefreshRates) {
- refreshRates.emplace_back(refreshRate->fps);
- }
-
- return refreshRates;
-}
-
std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
const std::vector<float>& refreshRates) const {
std::unordered_map<float, Offsets> offsets;
@@ -288,8 +307,7 @@
return iter->second;
}
- // Unknown refresh rate. This might happen if we get a hotplug event for the default display.
- // This happens only during tests and not during regular device operation.
+ // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
// In this case just construct the offset.
ALOGW("Can't find offset for %.2f fps", fps);
return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index b7d4eae..fa8011d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -66,11 +66,15 @@
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
-private:
+protected:
+ // Used for unit tests
+ PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
+ nsecs_t thresholdForNextVsync);
std::unordered_map<float, Offsets> initializeOffsets(
- const scheduler::RefreshRateConfigs&) const;
- Offsets getDefaultOffsets(nsecs_t vsyncDuration) const;
- Offsets getHighFpsOffsets(nsecs_t vsyncDuration) const;
+ const std::vector<float>& refreshRates) const;
+ Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const;
+ Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const;
+ Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const;
const nsecs_t mThresholdForNextVsync;
const std::unordered_map<float, Offsets> mOffsets;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 920f0ec..cd6075f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -419,20 +419,6 @@
mRefreshRateConfigs.getMaxRefreshRate().fps,
scheduler::LayerHistory::LayerVoteType::Heuristic);
}
-
- // TODO(146935143): Simulate youtube app vote. This should be removed once youtube calls the
- // API to set desired rate
- {
- const auto vote = property_get_int32("experimental.sf.force_youtube_vote", 0);
- if (vote != 0 &&
- layer->getName() ==
- "SurfaceView - "
- "com.google.android.youtube/"
- "com.google.android.apps.youtube.app.WatchWhileActivity#0") {
- layer->setFrameRate(
- Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple));
- }
- }
}
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index a6fb3a4..2a2d7c5 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -108,6 +108,8 @@
*/
virtual CancelResult cancel(CallbackToken token) = 0;
+ virtual void dump(std::string& result) const = 0;
+
protected:
VSyncDispatch() = default;
VSyncDispatch(VSyncDispatch const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index d0f18ab..460d4a5 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -15,6 +15,7 @@
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <android-base/stringprintf.h>
#include <utils/Trace.h>
#include <vector>
@@ -23,6 +24,7 @@
#include "VSyncTracker.h"
namespace android::scheduler {
+using base::StringAppendF;
VSyncDispatch::~VSyncDispatch() = default;
VSyncTracker::~VSyncTracker() = default;
@@ -122,6 +124,28 @@
mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
}
+void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
+ std::lock_guard<std::mutex> lk(mRunningMutex);
+ std::string armedInfo;
+ if (mArmedInfo) {
+ StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]",
+ (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
+ (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
+ }
+
+ StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
+ mRunning ? "(in callback function)" : "", armedInfo.c_str());
+ StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n",
+ mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f);
+
+ if (mLastDispatchTime) {
+ StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
+ (systemTime() - *mLastDispatchTime) / 1e6f);
+ } else {
+ StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
+ }
+}
+
VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
VSyncTracker& tracker, nsecs_t timerSlack,
nsecs_t minVsyncDistance)
@@ -296,6 +320,18 @@
return CancelResult::TooLate;
}
+void VSyncDispatchTimerQueue::dump(std::string& result) const {
+ std::lock_guard<decltype(mMutex)> lk(mMutex);
+ StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
+ mMinVsyncDistance / 1e6f);
+ StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
+ (mIntendedWakeupTime - systemTime()) / 1e6f);
+ StringAppendF(&result, "\tCallbacks:\n");
+ for (const auto& [token, entry] : mCallbacks) {
+ entry->dump(result);
+ }
+}
+
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
VSyncDispatch::Callback const& callbackFn,
std::string const& callbackName)
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index fd0a034..390e0c4 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -71,6 +71,8 @@
// Block calling thread while the callback is executing.
void ensureNotRunning();
+ void dump(std::string& result) const;
+
private:
std::string const mName;
VSyncDispatch::Callback const mCallback;
@@ -86,7 +88,7 @@
std::optional<ArmingInfo> mArmedInfo;
std::optional<nsecs_t> mLastDispatchTime;
- std::mutex mRunningMutex;
+ mutable std::mutex mRunningMutex;
std::condition_variable mCv;
bool mRunning GUARDED_BY(mRunningMutex) = false;
};
@@ -112,6 +114,7 @@
void unregisterCallback(CallbackToken token) final;
ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
CancelResult cancel(CallbackToken token) final;
+ void dump(std::string& result) const final;
private:
VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 257b8b1..a3cb772 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -22,6 +22,7 @@
//#define LOG_NDEBUG 0
#include "VSyncPredictor.h"
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <utils/Log.h>
@@ -31,6 +32,7 @@
#include <sstream>
namespace android::scheduler {
+using base::StringAppendF;
static auto constexpr kMaxPercent = 100u;
@@ -263,6 +265,18 @@
clearTimestamps();
}
+void VSyncPredictor::dump(std::string& result) const {
+ std::lock_guard<std::mutex> lk(mMutex);
+ StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f);
+ StringAppendF(&result, "\tRefresh Rate Map:\n");
+ for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) {
+ StringAppendF(&result,
+ "\t\tFor ideal period %.2fms: period = %.2fms, intercept = %" PRId64 "\n",
+ idealPeriod / 1e6f, std::get<0>(periodInterceptTuple) / 1e6f,
+ std::get<1>(periodInterceptTuple));
+ }
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index ef1d88a..3ca878d 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -60,6 +60,8 @@
std::tuple<nsecs_t /* slope */, nsecs_t /* intercept */> getVSyncPredictionModel() const;
+ void dump(std::string& result) const final;
+
private:
VSyncPredictor(VSyncPredictor const&) = delete;
VSyncPredictor& operator=(VSyncPredictor const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 8987dcd..892ae62 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -28,6 +28,7 @@
#include "VSyncTracker.h"
namespace android::scheduler {
+using base::StringAppendF;
Clock::~Clock() = default;
nsecs_t SystemClock::now() const {
@@ -73,11 +74,12 @@
public:
CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name,
nsecs_t period, nsecs_t offset, nsecs_t notBefore)
- : mCallback(cb),
+ : mName(name),
+ mCallback(cb),
mRegistration(dispatch,
std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
std::placeholders::_2),
- std::string(name)),
+ mName),
mPeriod(period),
mOffset(offset),
mLastCallTime(notBefore) {}
@@ -112,6 +114,13 @@
mRegistration.cancel();
}
+ void dump(std::string& result) const {
+ std::lock_guard<std::mutex> lk(mMutex);
+ StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n",
+ mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f,
+ mStopped ? "stopped" : "running");
+ }
+
private:
void callback(nsecs_t vsynctime, nsecs_t wakeupTime) {
{
@@ -137,6 +146,7 @@
// Note change in sign between the two defnitions.
nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; }
+ const std::string mName;
DispSync::Callback* const mCallback;
std::mutex mutable mMutex;
@@ -349,7 +359,35 @@
}
void VSyncReactor::dump(std::string& result) const {
- result += "VsyncReactor in use\n"; // TODO (b/144927823): add more information!
+ std::lock_guard<std::mutex> lk(mMutex);
+ StringAppendF(&result, "VsyncReactor in use\n");
+ StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size());
+ StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n",
+ mInternalIgnoreFences, mExternalIgnoreFences);
+ StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n",
+ mMoreSamplesNeeded, mPeriodConfirmationInProgress);
+ if (mPeriodTransitioningTo) {
+ StringAppendF(&result, "mPeriodTransitioningTo=%" PRId64 "\n", *mPeriodTransitioningTo);
+ } else {
+ StringAppendF(&result, "mPeriodTransitioningTo=nullptr\n");
+ }
+
+ if (mLastHwVsync) {
+ StringAppendF(&result, "Last HW vsync was %.2fms ago\n",
+ (mClock->now() - *mLastHwVsync) / 1e6f);
+ } else {
+ StringAppendF(&result, "No Last HW vsync\n");
+ }
+
+ StringAppendF(&result, "CallbackRepeaters:\n");
+ for (const auto& [callback, repeater] : mCallbacks) {
+ repeater->dump(result);
+ }
+
+ StringAppendF(&result, "VSyncTracker:\n");
+ mTracker->dump(result);
+ StringAppendF(&result, "VSyncDispatch:\n");
+ mDispatch->dump(result);
}
void VSyncReactor::reset() {}
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 7d8a8e3..5ee29f8 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -75,7 +75,7 @@
std::unique_ptr<VSyncDispatch> const mDispatch;
size_t const mPendingLimit;
- std::mutex mMutex;
+ mutable std::mutex mMutex;
bool mInternalIgnoreFences GUARDED_BY(mMutex) = false;
bool mExternalIgnoreFences GUARDED_BY(mMutex) = false;
std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index a25b8a9..05a6fc3 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -66,6 +66,8 @@
/* Inform the tracker that the samples it has are not accurate for prediction. */
virtual void resetModel() = 0;
+ virtual void dump(std::string& result) const = 0;
+
protected:
VSyncTracker(VSyncTracker const&) = delete;
VSyncTracker& operator=(VSyncTracker const&) = delete;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cfaabfc..2da92b3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -567,6 +567,7 @@
postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
readPersistentProperties();
+ mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
@@ -1028,7 +1029,7 @@
ATRACE_CALL();
ALOGV("performSetActiveConfig");
if (mCheckPendingFence) {
- if (previousFrameMissed()) {
+ if (previousFramePending()) {
// fence has not signaled yet. wait for the next invalidate
mEventQueue->invalidate();
return true;
@@ -1775,13 +1776,17 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
-bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS {
- ATRACE_CALL();
+sp<Fence> SurfaceFlinger::previousFrameFence() NO_THREAD_SAFETY_ANALYSIS {
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
- const sp<Fence>& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
- : mPreviousPresentFences[1];
+ return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
+}
+
+bool SurfaceFlinger::previousFramePending(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_CALL();
+ const sp<Fence>& fence = previousFrameFence();
if (fence == Fence::NO_FENCE) {
return false;
@@ -1794,6 +1799,16 @@
return (fence->getStatus() == Fence::Status::Unsignaled);
}
+nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS {
+ const sp<Fence>& fence = previousFrameFence();
+
+ if (fence == Fence::NO_FENCE) {
+ return Fence::SIGNAL_TIME_INVALID;
+ }
+
+ return fence->getSignalTime();
+}
+
void SurfaceFlinger::populateExpectedPresentTime() {
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
@@ -1811,6 +1826,7 @@
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
+ const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
populateExpectedPresentTime();
// When Backpressure propagation is enabled we want to give a small grace period
@@ -1821,12 +1837,32 @@
(mPropagateBackpressureClientComposition || !mHadClientComposition))
? 1
: 0;
- const TracedOrdinal<bool> frameMissed = {"FrameMissed",
- previousFrameMissed(
- graceTimeForPresentFenceMs)};
- const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",
+
+ // Pending frames may trigger backpressure propagation.
+ const TracedOrdinal<bool> framePending = {"PrevFramePending",
+ previousFramePending(
+ graceTimeForPresentFenceMs)};
+
+ // Frame missed counts for metrics tracking.
+ // A frame is missed if the prior frame is still pending. If no longer pending,
+ // then we still count the frame as missed if the predicted present time
+ // was further in the past than when the fence actually fired.
+
+ // Add some slop to correct for drift. This should generally be
+ // smaller than a typical frame duration, but should not be so small
+ // that it reports reasonable drift as a missed frame.
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats);
+ const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
+ const nsecs_t previousPresentTime = previousFramePresentTime();
+ const TracedOrdinal<bool> frameMissed =
+ {"PrevFrameMissed",
+ framePending ||
+ (previousPresentTime >= 0 &&
+ (lastExpectedPresentTime < previousPresentTime - frameMissedSlop))};
+ const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
mHadDeviceComposition && frameMissed};
- const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
+ const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
mHadClientComposition && frameMissed};
if (frameMissed) {
@@ -1846,7 +1882,7 @@
mGpuFrameMissedCount++;
}
- if (frameMissed && mPropagateBackpressure) {
+ if (framePending && mPropagateBackpressure) {
if ((hwcFrameMissed && !gpuFrameMissed) ||
mPropagateBackpressureClientComposition) {
signalLayerUpdate();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 44e18a7..6ab1fcf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -844,7 +844,21 @@
bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock);
- bool previousFrameMissed(int graceTimeMs = 0);
+ // Gets the fence for the previous frame.
+ // Must be called on the main thread.
+ sp<Fence> previousFrameFence();
+
+ // Whether the previous frame has not yet been presented to the display.
+ // If graceTimeMs is positive, this method waits for at most the provided
+ // grace period before reporting if the frame missed.
+ // Must be called on the main thread.
+ bool previousFramePending(int graceTimeMs = 0);
+
+ // Returns the previous time that the frame was presented. If the frame has
+ // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there
+ // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID.
+ // Must be called on the main thread.
+ nsecs_t previousFramePresentTime();
// Populates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 65b3e35..ba5c0c2 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -48,6 +48,7 @@
MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index 910e73b..8d49201 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -42,25 +42,25 @@
appEarlyGlDuration) {}
};
-class PhaseOffsetsTest : public testing::Test {
+class PhaseDurationTest : public testing::Test {
protected:
- PhaseOffsetsTest()
- : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000,
- 38'000'000) {}
+ PhaseDurationTest()
+ : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000,
+ 38'000'000) {}
- ~PhaseOffsetsTest() = default;
+ ~PhaseDurationTest() = default;
- TestablePhaseOffsetsAsDurations mPhaseOffsets;
+ TestablePhaseOffsetsAsDurations mPhaseDurations;
};
namespace {
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) {
- mPhaseOffsets.setRefreshRateFps(60.0f);
- auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
- auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f);
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) {
+ mPhaseDurations.setRefreshRateFps(60.0f);
+ auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f);
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sf, 6'166'667);
@@ -76,10 +76,10 @@
EXPECT_EQ(offsets.earlyGl.app, 15'166'668);
}
-TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) {
- mPhaseOffsets.setRefreshRateFps(90.0f);
- auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
- auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f);
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
+ mPhaseDurations.setRefreshRateFps(90.0f);
+ auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f);
EXPECT_EQ(currentOffsets, offsets);
EXPECT_EQ(offsets.late.sf, 611'111);
@@ -95,7 +95,7 @@
EXPECT_EQ(offsets.earlyGl.app, 4'055'555);
}
-TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) {
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
auto validateOffsets = [](auto& offsets) {
@@ -125,6 +125,54 @@
validateOffsets(offsets);
}
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f);
+
+ EXPECT_EQ(offsets.late.sf, 57'527'208);
+
+ EXPECT_EQ(offsets.late.app, 37'027'208);
+
+ EXPECT_EQ(offsets.early.sf, 52'027'208);
+
+ EXPECT_EQ(offsets.early.app, 18'527'208);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 54'527'208);
+
+ EXPECT_EQ(offsets.earlyGl.app, 16'527'208);
+}
+
+} // namespace
+
+class TestablePhaseOffsets : public impl::PhaseOffsets {
+public:
+ TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {}
+};
+
+class PhaseOffsetsTest : public testing::Test {
+protected:
+ PhaseOffsetsTest() = default;
+ ~PhaseOffsetsTest() = default;
+
+ TestablePhaseOffsets mPhaseOffsets;
+};
+
+namespace {
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f);
+
+ EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.late.app, 1'000'000);
+
+ EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.early.app, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index caac61d..be49ef3 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -51,6 +51,7 @@
void setPeriod(nsecs_t) final {}
void resetModel() final {}
+ void dump(std::string&) const final {}
private:
nsecs_t const mPeriod;
@@ -85,6 +86,7 @@
void setPeriod(nsecs_t) final {}
void resetModel() final {}
+ void dump(std::string&) const final {}
private:
std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 3ab38e4..3543361 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -47,6 +47,7 @@
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
if (timePoint % mPeriod == 0) {
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index ac95938..4f150ef 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -41,6 +41,7 @@
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
class VSyncTrackerWrapper : public VSyncTracker {
@@ -56,6 +57,7 @@
nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
void resetModel() final { mTracker->resetModel(); }
+ void dump(std::string& result) const final { mTracker->dump(result); }
private:
std::shared_ptr<VSyncTracker> const mTracker;
@@ -83,6 +85,7 @@
MOCK_METHOD1(unregisterCallback, void(CallbackToken));
MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
class VSyncDispatchWrapper : public VSyncDispatch {
@@ -102,6 +105,8 @@
CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
+ void dump(std::string& result) const final { return mDispatch->dump(result); }
+
private:
std::shared_ptr<VSyncDispatch> const mDispatch;
};
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index fe57c98..e22d0cf 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,6 +29,7 @@
PowerAdvisor();
~PowerAdvisor() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
MOCK_METHOD0(notifyDisplayUpdateImminent, void());
};