Merge changes I34af02d4,Ifc222d84,I74c8cffa into main
* changes:
SF: Apply color matrix to newly connected displays
SF: Extract CommitAndCompositeTest helper
SF: Replace futureOf with ftl::yield in tests
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 481c28e..5ee6b15 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1563,6 +1563,13 @@
RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
+
+ printf("========================================================\n");
+ printf("== ANR Traces\n");
+ printf("========================================================\n");
+
+ AddAnrTraceFiles();
+
printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
ds.progress_->GetMax(), ds.progress_->GetInitialMax());
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index d97ba89..37f41be 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -16,44 +16,83 @@
#pragma once
+#include <condition_variable>
#include <chrono>
-#include <future>
+#include <functional>
+#include <mutex>
+#include <thread>
#include <hidl/Status.h>
-#include <utils/Errors.h>
namespace android {
namespace lshal {
-// Call function on interfaceObject and wait for result until the given timeout has reached.
-// Callback functions pass to timeoutIPC() may be executed after the this function
-// has returned, especially if deadline has been reached. Hence, care must be taken when passing
-// data between the background thread and the main thread. See b/311143089.
+class BackgroundTaskState {
+public:
+ explicit BackgroundTaskState(std::function<void(void)> &&func)
+ : mFunc(std::forward<decltype(func)>(func)) {}
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mFinished = true;
+ lock.unlock();
+ mCondVar.notify_all();
+ }
+ template<class C, class D>
+ bool wait(std::chrono::time_point<C, D> end) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
+ return mFinished;
+ }
+ void operator()() {
+ mFunc();
+ }
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondVar;
+ bool mFinished = false;
+ std::function<void(void)> mFunc;
+};
+
+void *callAndNotify(void *data) {
+ BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+ state();
+ state.notify();
+ return nullptr;
+}
+
+template<class R, class P>
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
+ auto now = std::chrono::system_clock::now();
+ BackgroundTaskState state{std::forward<decltype(func)>(func)};
+ pthread_t thread;
+ if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
+ std::cerr << "FATAL: could not create background thread." << std::endl;
+ return false;
+ }
+ bool success = state.wait(now + delay);
+ if (!success) {
+ pthread_kill(thread, SIGINT);
+ }
+ pthread_join(thread, nullptr);
+ return success;
+}
+
template<class R, class P, class Function, class I, class... Args>
typename std::invoke_result<Function, I *, Args...>::type
timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
Args &&... args) {
using ::android::hardware::Status;
-
- // Execute on a background thread but do not defer execution.
- auto future =
- std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...);
- auto status = future.wait_for(wait);
- if (status == std::future_status::ready) {
- return future.get();
- }
-
- // This future belongs to a background thread that we no longer care about.
- // Putting this in the global list avoids std::future::~future() that may wait for the
- // result to come back.
- // This leaks memory, but lshal is a debugging tool, so this is fine.
- static std::vector<decltype(future)> gDeadPool{};
- gDeadPool.emplace_back(std::move(future));
-
- if (status == std::future_status::timeout) {
+ typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
+ auto boundFunc = std::bind(std::forward<Function>(func),
+ interfaceObject.get(), std::forward<Args>(args)...);
+ bool success = timeout(wait, [&ret, &boundFunc] {
+ ret = std::move(boundFunc());
+ });
+ if (!success) {
return Status::fromStatusT(TIMED_OUT);
}
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status");
+ return ret;
}
-} // namespace lshal
-} // namespace android
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
index bd5fa32..366c938 100644
--- a/cmds/lshal/main.cpp
+++ b/cmds/lshal/main.cpp
@@ -18,6 +18,5 @@
int main(int argc, char **argv) {
using namespace ::android::lshal;
- // Use _exit() to force terminate background threads in Timeout.h
- _exit(Lshal{}.main(Arg{argc, argv}));
+ return Lshal{}.main(Arg{argc, argv});
}
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index c24f827..cba7c4b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#include <chrono>
-#include <future>
-#include <mutex>
-#include "android/hidl/base/1.0/IBase.h"
#define LOG_TAG "Lshal"
#include <android-base/logging.h>
@@ -40,8 +36,6 @@
using namespace testing;
-using std::chrono_literals::operator""ms;
-
using ::android::hidl::base::V1_0::DebugInfo;
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
@@ -940,9 +934,12 @@
return hardware::Void();
}));
EXPECT_CALL(*serviceManager, get(_, _))
- .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
- return sp<IBase>(service);
- }));
+ .WillRepeatedly(
+ Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
+ int id = getIdFromInstanceName(instance);
+ if (id > inheritanceLevel) return nullptr;
+ return sp<IBase>(service);
+ }));
const std::string expected = "[fake description 0]\n"
"Interface\n"
@@ -960,110 +957,6 @@
EXPECT_EQ("", err.str());
}
-// In SlowService, everything goes slooooooow. Each IPC call will wait for
-// the specified time before calling the callback function or returning.
-class SlowService : public IBase {
-public:
- explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {}
- android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
- std::this_thread::sleep_for(mWait);
- cb(getInterfaceName(1));
- storeHistory("interfaceDescriptor");
- return hardware::Void();
- }
- android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
- std::this_thread::sleep_for(mWait);
- std::vector<hidl_string> ret;
- ret.push_back(getInterfaceName(1));
- ret.push_back(IBase::descriptor);
- cb(ret);
- storeHistory("interfaceChain");
- return hardware::Void();
- }
- android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
- std::this_thread::sleep_for(mWait);
- std::vector<hidl_hash> ret;
- ret.push_back(getHashFromId(0));
- ret.push_back(getHashFromId(0xff));
- cb(ret);
- storeHistory("getHashChain");
- return hardware::Void();
- }
- android::hardware::Return<void> debug(const hidl_handle&,
- const hidl_vec<hidl_string>&) override {
- std::this_thread::sleep_for(mWait);
- storeHistory("debug");
- return Void();
- }
-
- template <class R, class P, class Pred>
- bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) {
- std::unique_lock<std::mutex> lock(mLock);
- return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); });
- }
-
-private:
- void storeHistory(std::string hist) {
- {
- std::lock_guard<std::mutex> lock(mLock);
- mCallHistory.emplace_back(std::move(hist));
- }
- mCv.notify_all();
- }
-
- const std::chrono::milliseconds mWait;
- std::mutex mLock;
- std::condition_variable mCv;
- // List of functions that have finished being called on this interface.
- std::vector<std::string> mCallHistory;
-};
-
-class TimeoutTest : public ListTest {
-public:
- void setMockServiceManager(sp<IBase> service) {
- EXPECT_CALL(*serviceManager, list(_))
- .WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
- std::vector<hidl_string> ret;
- ret.push_back(getInterfaceName(1) + "/default");
- cb(ret);
- return hardware::Void();
- }));
- EXPECT_CALL(*serviceManager, get(_, _))
- .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
- return service;
- }));
- }
-};
-
-TEST_F(TimeoutTest, BackgroundThreadIsKept) {
- auto lshalIpcTimeout = 100ms;
- auto serviceIpcTimeout = 200ms;
- lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
- sp<SlowService> service = new SlowService(serviceIpcTimeout);
- setMockServiceManager(service);
-
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
- EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\""));
- EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) {
- return hist.size() == 1 && hist[0] == "interfaceChain";
- })) << "The background thread should continue after the main thread moves on, but it is killed";
-}
-
-TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) {
- auto lshalIpcTimeout = 100ms;
- auto serviceIpcTimeout = 2000ms;
- auto start = std::chrono::system_clock::now();
- lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
- sp<SlowService> service = new SlowService(serviceIpcTimeout);
- setMockServiceManager(service);
-
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
- EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout)
- << "The main thread should not be blocked by the background task";
-}
-
class ListVintfTest : public ListTest {
public:
virtual void SetUp() override {
@@ -1186,6 +1079,5 @@
int main(int argc, char **argv) {
::testing::InitGoogleMock(&argc, argv);
- // Use _exit() to force terminate background threads in Timeout.h
- _exit(RUN_ALL_TESTS());
+ return RUN_ALL_TESTS();
}
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index b7751f7..57b659d 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -75,6 +75,17 @@
bool operator!=(const InputDeviceIdentifier&) const = default;
};
+/**
+ * Holds View related behaviors for an InputDevice.
+ */
+struct InputDeviceViewBehavior {
+ /**
+ * The smooth scroll behavior that applies for all source/axis, if defined by the device.
+ * Empty optional if the device has not specified the default smooth scroll behavior.
+ */
+ std::optional<bool> shouldSmoothScroll;
+};
+
/* Types of input device sensors. Keep sync with core/java/android/hardware/Sensor.java */
enum class InputDeviceSensorType : int32_t {
ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER,
@@ -266,7 +277,8 @@
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, const std::string& alias,
- bool isExternal, bool hasMic, int32_t associatedDisplayId);
+ bool isExternal, bool hasMic, int32_t associatedDisplayId,
+ InputDeviceViewBehavior viewBehavior = {{}});
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -298,6 +310,8 @@
return mKeyboardLayoutInfo;
}
+ inline const InputDeviceViewBehavior& getViewBehavior() const { return mViewBehavior; }
+
inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) {
mKeyCharacterMap = value;
}
@@ -359,6 +373,8 @@
std::unordered_map<int32_t, InputDeviceLightInfo> mLights;
/* Map from battery ID to battery info */
std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries;
+ /** The View related behaviors for the device. */
+ InputDeviceViewBehavior mViewBehavior;
};
/* Types of input device configuration files. */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8b1c2a3..d53e8c6 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -333,7 +333,7 @@
~InputPublisher();
/* Gets the underlying input channel. */
- inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
+ inline std::shared_ptr<InputChannel> getChannel() const { return mChannel; }
/* Publishes a key event to the input channel.
*
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index 7d37fd3..4518b67 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -116,7 +116,7 @@
std::lock_guard<std::mutex> _l(gChoreographers.lock);
gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(),
gChoreographers.ptrs.end(),
- [=](Choreographer* c) { return c == this; }),
+ [=, this](Choreographer* c) { return c == this; }),
gChoreographers.ptrs.end());
// Only poke DisplayManagerGlobal to unregister if we previously registered
// callbacks.
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 38fab9c..7564c26 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -199,7 +199,7 @@
SAFE_PARCEL(output.writeParcelable, trustedPresentationListener);
SAFE_PARCEL(output.writeFloat, currentHdrSdrRatio);
SAFE_PARCEL(output.writeFloat, desiredHdrSdrRatio);
- SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint))
+ SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint));
return NO_ERROR;
}
@@ -484,6 +484,12 @@
flags &= ~eLayerIsDisplayDecoration;
ALOGE("Stripped attempt to set LayerIsDisplayDecoration in sanitize");
}
+ if ((mask & eCanOccludePresentation) &&
+ !(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+ flags &= ~eCanOccludePresentation;
+ mask &= ~eCanOccludePresentation;
+ ALOGE("Stripped attempt to set eCanOccludePresentation in sanitize");
+ }
}
if (what & layer_state_t::eInputInfoChanged) {
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 95b2641..9429d2c 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -109,7 +109,8 @@
info.inputConfig == inputConfig && info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
- info.layoutParamsFlags == layoutParamsFlags;
+ info.layoutParamsFlags == layoutParamsFlags &&
+ info.canOccludePresentation == canOccludePresentation;
}
status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -158,8 +159,9 @@
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
- parcel->writeStrongBinder(windowToken);
- parcel->writeStrongBinder(focusTransferTarget);
+ parcel->writeStrongBinder(windowToken) ?:
+ parcel->writeStrongBinder(focusTransferTarget) ?:
+ parcel->writeBool(canOccludePresentation);
// clang-format on
return status;
}
@@ -210,7 +212,8 @@
parcel->readBool(&replaceTouchableRegionWithCrop) ?:
parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
parcel->readNullableStrongBinder(&windowToken) ?:
- parcel->readNullableStrongBinder(&focusTransferTarget);
+ parcel->readNullableStrongBinder(&focusTransferTarget) ?:
+ parcel->readBool(&canOccludePresentation);
// clang-format on
@@ -273,6 +276,7 @@
<< "ms, token=" << info.token.get()
<< ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode) << "\n"
<< transform;
+ if (info.canOccludePresentation) out << " canOccludePresentation";
return out;
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 6b8e824..920310e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -161,6 +161,9 @@
// See SurfaceView scaling behavior for more details.
eIgnoreDestinationFrame = 0x400,
eLayerIsRefreshRateIndicator = 0x800, // REFRESH_RATE_INDICATOR
+ // Sets a property on this layer indicating that its visible region should be considered
+ // when computing TrustedPresentation Thresholds.
+ eCanOccludePresentation = 0x1000,
};
enum {
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index e72fd59..32d60be 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -246,6 +246,10 @@
// any other window.
sp<IBinder> focusTransferTarget;
+ // Sets a property on this window indicating that its visible region should be considered when
+ // computing TrustedPresentation Thresholds.
+ bool canOccludePresentation = false;
+
void setInputConfig(ftl::Flags<InputConfig> config, bool value);
void addTouchableRegion(const Rect& region);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 8eaff00..0d29b4d 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -374,7 +374,7 @@
out << ", deviceId=" << event.getDeviceId();
out << ", source=" << inputEventSourceToString(event.getSource());
out << ", displayId=" << event.getDisplayId();
- out << ", eventId=" << event.getId();
+ out << ", eventId=0x" << std::hex << event.getId() << std::dec;
out << "}";
return out;
}
@@ -1051,7 +1051,7 @@
out << ", deviceId=" << event.getDeviceId();
out << ", source=" << inputEventSourceToString(event.getSource());
out << ", displayId=" << event.getDisplayId();
- out << ", eventId=" << event.getId();
+ out << ", eventId=0x" << std::hex << event.getId() << std::dec;
out << "}";
return out;
}
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 9c7c0c1..d4dbc45 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -190,14 +190,16 @@
mHasSensor(other.mHasSensor),
mMotionRanges(other.mMotionRanges),
mSensors(other.mSensors),
- mLights(other.mLights) {}
+ mLights(other.mLights),
+ mViewBehavior(other.mViewBehavior) {}
InputDeviceInfo::~InputDeviceInfo() {
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, const std::string& alias,
- bool isExternal, bool hasMic, int32_t associatedDisplayId) {
+ bool isExternal, bool hasMic, int32_t associatedDisplayId,
+ InputDeviceViewBehavior viewBehavior) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -212,6 +214,7 @@
mHasBattery = false;
mHasButtonUnderPad = false;
mHasSensor = false;
+ mViewBehavior = viewBehavior;
mUsiVersion.reset();
mMotionRanges.clear();
mSensors.clear();
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 174464d..ec7a284 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -111,3 +111,10 @@
description: "Move user-activity poke rate-limiting from PowerManagerService to InputDispatcher."
bug: "320499729"
}
+
+flag {
+ name: "input_device_view_behavior_api"
+ namespace: "input"
+ description: "Controls the API to provide InputDevice view behavior."
+ bug: "246946631"
+}
diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs
index 867af79..b1d7760 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -79,7 +79,7 @@
logger::init(
logger::Config::default()
.with_tag_on_device("InputVerifier")
- .with_min_level(log::Level::Trace),
+ .with_max_level(log::LevelFilter::Trace),
);
Self {
name: name.to_owned(),
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index 5cf0310..bff12ce 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -34,6 +34,7 @@
#include <cstdint>
#include <memory>
+#include <sstream>
#include <string>
#include <vector>
@@ -195,32 +196,33 @@
const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
const std::vector<std::byte>& vendorBinaryData) {
VulkanInterface* interface = static_cast<VulkanInterface*>(callbackContext);
- const string protectedStr = interface->isProtected ? "protected" : "non-protected";
+ const std::string protectedStr = interface->isProtected ? "protected" : "non-protected";
// The final crash string should contain as much differentiating info as possible, up to 1024
// bytes. As this final message is constructed, the same information is also dumped to the logs
// but in a more verbose format. Building the crash string is unsightly, so the clearer logging
// statement is always placed first to give context.
ALOGE("VK_ERROR_DEVICE_LOST (%s context): %s", protectedStr.c_str(), description.c_str());
- string crashStr = "VK_ERROR_DEVICE_LOST (" + protectedStr;
+ std::stringstream crashMsg;
+ crashMsg << "VK_ERROR_DEVICE_LOST (" << protectedStr;
if (!addressInfos.empty()) {
ALOGE("%zu VkDeviceFaultAddressInfoEXT:", addressInfos.size());
- crashStr += ", " + std::to_string(addressInfos.size()) + " address info (";
+ crashMsg << ", " << addressInfos.size() << " address info (";
for (VkDeviceFaultAddressInfoEXT addressInfo : addressInfos) {
ALOGE(" addressType: %d", (int)addressInfo.addressType);
ALOGE(" reportedAddress: %" PRIu64, addressInfo.reportedAddress);
ALOGE(" addressPrecision: %" PRIu64, addressInfo.addressPrecision);
- crashStr += std::to_string(addressInfo.addressType) + ":" +
- std::to_string(addressInfo.reportedAddress) + ":" +
- std::to_string(addressInfo.addressPrecision) + ", ";
+ crashMsg << addressInfo.addressType << ":"
+ << addressInfo.reportedAddress << ":"
+ << addressInfo.addressPrecision << ", ";
}
- crashStr.resize(crashStr.size() - 2); // Remove trailing ", "
- crashStr += ")";
+ crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
+ crashMsg << ")";
}
if (!vendorInfos.empty()) {
ALOGE("%zu VkDeviceFaultVendorInfoEXT:", vendorInfos.size());
- crashStr += ", " + std::to_string(vendorInfos.size()) + " vendor info (";
+ crashMsg << ", " << vendorInfos.size() << " vendor info (";
for (VkDeviceFaultVendorInfoEXT vendorInfo : vendorInfos) {
ALOGE(" description: %s", vendorInfo.description);
ALOGE(" vendorFaultCode: %" PRIu64, vendorInfo.vendorFaultCode);
@@ -230,11 +232,11 @@
// isn't worth it. Additionally, vendors may just set the general description field of
// the overall fault to the description of the first element in this list, and that
// overall description will be placed at the end of the crash string.
- crashStr += std::to_string(vendorInfo.vendorFaultCode) + ":" +
- std::to_string(vendorInfo.vendorFaultData) + ", ";
+ crashMsg << vendorInfo.vendorFaultCode << ":"
+ << vendorInfo.vendorFaultData << ", ";
}
- crashStr.resize(crashStr.size() - 2); // Remove trailing ", "
- crashStr += ")";
+ crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
+ crashMsg << ")";
}
if (!vendorBinaryData.empty()) {
@@ -242,11 +244,11 @@
ALOGE("%zu bytes of vendor-specific binary data (please notify Android's Core Graphics"
" Stack team if you observe this message).",
vendorBinaryData.size());
- crashStr += ", " + std::to_string(vendorBinaryData.size()) + " bytes binary";
+ crashMsg << ", " << vendorBinaryData.size() << " bytes binary";
}
- crashStr += "): " + description;
- LOG_ALWAYS_FATAL("%s", crashStr.c_str());
+ crashMsg << "): " << description;
+ LOG_ALWAYS_FATAL("%s", crashMsg.str().c_str());
};
} // anonymous namespace
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 7fd9c3a..f73fa5d 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -22,8 +22,10 @@
mkdir -p out/javax/microedition/khronos/opengles
mkdir -p out/com/google/android/gles_jni
+mkdir -p out/android/annotation
mkdir -p out/android/app
mkdir -p out/android/graphics
+mkdir -p out/android/hardware
mkdir -p out/android/view
mkdir -p out/android/opengl
mkdir -p out/android/content
@@ -34,18 +36,20 @@
echo "package android.graphics;" > out/android/graphics/Canvas.java
echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
+echo "package android.annotation; public @interface NonNull {}" > out/android/annotation/NonNull.java
echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
-echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;}; }" > out/android/os/Build.java
+echo "package android.hardware; import android.os.ParcelFileDescriptor; public class SyncFence { public static SyncFence create(ParcelFileDescriptor w) { return null; } public static SyncFence createEmpty() { return null; } }" > out/android/hardware/SyncFence.java
+echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 0; public static final int R = 0; }; }" > out/android/os/Build.java
+echo "package android.os; public class ParcelFileDescriptor { public static ParcelFileDescriptor adoptFd(int fd) { return null; } }" > out/android/os/ParcelFileDescriptor.java
echo "package android.os; public class UserHandle {public static String myUserId() { return \"\"; } }" > out/android/os/UserHandle.java
echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java
-echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
+echo "package android.util; public class Log {public static void d(String a, String b) {} public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java
-
echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java
echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java
echo "package android.view;" > out/android/view/SurfaceView.java
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index 951ecff..695b571 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -20,6 +20,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
+import android.os.Build;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index b2ea041..ea55179 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 6dffac5..8e452fb 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
index 523bc57..75e1704 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
@@ -18,6 +18,11 @@
package android.opengl;
+import android.annotation.NonNull;
+import android.hardware.SyncFence;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
/**
* EGL Extensions
*/
@@ -30,8 +35,44 @@
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
public static final int EGL_RECORDABLE_ANDROID = 0x3142;
+ // EGL_ANDROID_native_fence_sync
+ public static final int EGL_SYNC_NATIVE_FENCE_ANDROID = 0x3144;
+ public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID = 0x3145;
+ public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 0x3146;
+ public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID = -1;
+
native private static void _nativeClassInit();
static {
_nativeClassInit();
}
+ /**
+ * Retrieves the SyncFence for an EGLSync created with EGL_SYNC_NATIVE_FENCE_ANDROID
+ *
+ * See <a href="https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt">
+ * EGL_ANDROID_native_fence_sync</a> extension for more details
+ * @param display The EGLDisplay connection
+ * @param sync The EGLSync to fetch the SyncFence from
+ * @return A SyncFence representing the native fence.
+ * * If <sync> is not a valid sync object for <display>,
+ * an {@link SyncFence#isValid() invalid} SyncFence is returned and an EGL_BAD_PARAMETER
+ * error is generated.
+ * * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
+ * EGL_NO_NATIVE_FENCE_FD_ANDROID, an {@link SyncFence#isValid() invalid} SyncFence is
+ * returned and an EGL_BAD_PARAMETER error is generated.
+ * * If <display> does not match the display passed to eglCreateSync
+ * when <sync> was created, the behaviour is undefined.
+ */
+ public static @NonNull SyncFence eglDupNativeFenceFDANDROID(@NonNull EGLDisplay display,
+ @NonNull EGLSync sync) {
+ int fd = eglDupNativeFenceFDANDROIDImpl(display, sync);
+ Log.d("EGL", "eglDupNativeFence returned " + fd);
+ if (fd >= 0) {
+ return SyncFence.create(ParcelFileDescriptor.adoptFd(fd));
+ } else {
+ return SyncFence.createEmpty();
+ }
+ }
+
+ private static native int eglDupNativeFenceFDANDROIDImpl(EGLDisplay display, EGLSync sync);
+
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index be8b3e3..f1f0ac5 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
@@ -37,25 +38,12 @@
#include <ui/ANativeObjectBase.h>
static jclass egldisplayClass;
-static jclass eglcontextClass;
static jclass eglsurfaceClass;
-static jclass eglconfigClass;
+static jclass eglsyncClass;
static jmethodID egldisplayGetHandleID;
-static jmethodID eglcontextGetHandleID;
static jmethodID eglsurfaceGetHandleID;
-static jmethodID eglconfigGetHandleID;
-
-static jmethodID egldisplayConstructor;
-static jmethodID eglcontextConstructor;
-static jmethodID eglsurfaceConstructor;
-static jmethodID eglconfigConstructor;
-
-static jobject eglNoContextObject;
-static jobject eglNoDisplayObject;
-static jobject eglNoSurfaceObject;
-
-
+static jmethodID eglsyncGetHandleID;
/* Cache method IDs each time the class is loaded. */
@@ -64,37 +52,14 @@
{
jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
- jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
- eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
- jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
- eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
+ jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+ eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
- eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
- eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
-
-
- egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
- eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
- eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
- eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
-
-
- jclass eglClass = _env->FindClass("android/opengl/EGL14");
- jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
- jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID);
- eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-
- jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
- jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID);
- eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-
- jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
- jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID);
- eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
}
static void *
@@ -108,24 +73,12 @@
return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
}
-static jobject
-toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
- if (cls == eglcontextClass &&
- (EGLContext)handle == EGL_NO_CONTEXT) {
- return eglNoContextObject;
- }
+// TODO: this should be generated from the .spec file, but needs to be renamed and made private
+static jint android_eglDupNativeFenceFDANDROID(JNIEnv *env, jobject, jobject dpy, jobject sync) {
+ EGLDisplay dpy_native = (EGLDisplay)fromEGLHandle(env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync)fromEGLHandle(env, eglsyncGetHandleID, sync);
- if (cls == egldisplayClass &&
- (EGLDisplay)handle == EGL_NO_DISPLAY) {
- return eglNoDisplayObject;
- }
-
- if (cls == eglsurfaceClass &&
- (EGLSurface)handle == EGL_NO_SURFACE) {
- return eglNoSurfaceObject;
- }
-
- return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
+ return eglDupNativeFenceFDANDROID(dpy_native, sync_native);
}
// --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
index 85f743d..78b0819 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -7,7 +7,7 @@
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static native EGLDisplay eglGetDisplay(
long display_id
);
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index dd17ca4..1fa9275 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index b2bbdf6..4004a7d 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES2/gl2.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
index b039bc9..c5bdf32 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp
@@ -18,6 +18,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl3.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
index dd00e92..2260a80 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl31.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
index 88e00be..130612d 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
index 3e7ec8b..5446fc2 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 9cab1d6..c3534bf 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -17,6 +17,7 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index f304712..c7963c0 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -23,19 +23,12 @@
Connection::Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
const IdGenerator& idGenerator)
: status(Status::NORMAL),
- inputChannel(inputChannel),
monitor(monitor),
inputPublisher(inputChannel),
inputState(idGenerator) {}
-const std::string Connection::getWindowName() const {
- if (inputChannel != nullptr) {
- return inputChannel->getName();
- }
- if (monitor) {
- return "monitor";
- }
- return "?";
-}
+sp<IBinder> Connection::getToken() const {
+ return inputPublisher.getChannel()->getConnectionToken();
+};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index c17baea..8d7f182 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -42,7 +42,6 @@
};
Status status;
- std::shared_ptr<InputChannel> inputChannel; // never null
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
@@ -62,9 +61,11 @@
Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
const IdGenerator& idGenerator);
- inline const std::string getInputChannelName() const { return inputChannel->getName(); }
+ inline const std::string getInputChannelName() const {
+ return inputPublisher.getChannel()->getName();
+ }
- const std::string getWindowName() const;
+ sp<IBinder> getToken() const;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index bc090cf..264dc03 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -282,7 +282,7 @@
volatile int32_t DispatchEntry::sNextSeqAtomic;
DispatchEntry::DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
- ftl::Flags<InputTarget::Flags> targetFlags,
+ ftl::Flags<InputTargetFlags> targetFlags,
const ui::Transform& transform, const ui::Transform& rawTransform,
float globalScaleFactor, gui::Uid targetUid, int64_t vsyncId,
std::optional<int32_t> windowId)
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 9e5d346..1298b5d 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -17,7 +17,7 @@
#pragma once
#include "InjectionState.h"
-#include "InputTarget.h"
+#include "InputTargetFlags.h"
#include "trace/EventTrackerInterface.h"
#include <gui/InputApplication.h>
@@ -215,7 +215,7 @@
const uint32_t seq; // unique sequence number, never 0
std::shared_ptr<const EventEntry> eventEntry; // the event to dispatch
- const ftl::Flags<InputTarget::Flags> targetFlags;
+ const ftl::Flags<InputTargetFlags> targetFlags;
ui::Transform transform;
ui::Transform rawTransform;
float globalScaleFactor;
@@ -237,17 +237,17 @@
std::optional<int32_t> windowId;
DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
- ftl::Flags<InputTarget::Flags> targetFlags, const ui::Transform& transform,
+ ftl::Flags<InputTargetFlags> targetFlags, const ui::Transform& transform,
const ui::Transform& rawTransform, float globalScaleFactor, gui::Uid targetUid,
int64_t vsyncId, std::optional<int32_t> windowId);
DispatchEntry(const DispatchEntry&) = delete;
DispatchEntry& operator=(const DispatchEntry&) = delete;
inline bool hasForegroundTarget() const {
- return targetFlags.test(InputTarget::Flags::FOREGROUND);
+ return targetFlags.test(InputTargetFlags::FOREGROUND);
}
- inline bool isSplit() const { return targetFlags.test(InputTarget::Flags::SPLIT); }
+ inline bool isSplit() const { return targetFlags.test(InputTargetFlags::SPLIT); }
private:
static volatile int32_t sNextSeqAtomic;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d706c4d..a62e23a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -728,7 +728,7 @@
// TODO(b/282025641): simplify this code once InputTargets are being identified
// separately from TouchedWindows.
std::erase_if(targets, [&](const InputTarget& target) {
- return target.inputChannel->getConnectionToken() == window.windowHandle->getToken();
+ return target.connection->getToken() == window.windowHandle->getToken();
});
return true;
}
@@ -870,7 +870,7 @@
while (!mConnectionsByToken.empty()) {
std::shared_ptr<Connection> connection = mConnectionsByToken.begin()->second;
- removeInputChannelLocked(connection->inputChannel->getConnectionToken(), /*notify=*/false);
+ removeInputChannelLocked(connection->getToken(), /*notify=*/false);
}
}
@@ -990,7 +990,7 @@
}
connection->responsive = false;
// Stop waking up for this unresponsive connection
- mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
+ mAnrTracker.eraseToken(connection->getToken());
onAnrLocked(connection);
return LLONG_MIN;
}
@@ -1000,8 +1000,7 @@
if (connection->monitor) {
return mMonitorDispatchingTimeout;
}
- const sp<WindowInfoHandle> window =
- getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ const sp<WindowInfoHandle> window = getWindowHandleLocked(connection->getToken());
if (window != nullptr) {
return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
}
@@ -1623,15 +1622,15 @@
void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime,
std::shared_ptr<const FocusEntry> entry) {
- std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
- if (channel == nullptr) {
- return; // Window has gone away
+ std::shared_ptr<Connection> connection = getConnectionLocked(entry->connectionToken);
+ if (connection == nullptr) {
+ return; // Connection has gone away
}
InputTarget target;
- target.inputChannel = channel;
+ target.connection = connection;
entry->dispatchInProgress = true;
std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
- channel->getName();
+ connection->getInputChannelName();
std::string reason = std::string("reason=").append(entry->reason);
android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
dispatchEventLocked(currentTime, entry, {target});
@@ -1691,8 +1690,8 @@
}
}
- auto channel = getInputChannelLocked(token);
- if (channel == nullptr) {
+ auto connection = getConnectionLocked(token);
+ if (connection == nullptr) {
// Window has gone away, clean up Pointer Capture state.
mWindowTokenWithPointerCapture = nullptr;
if (mCurrentPointerCaptureRequest.enable) {
@@ -1701,7 +1700,7 @@
return;
}
InputTarget target;
- target.inputChannel = channel;
+ target.connection = connection;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
@@ -1732,12 +1731,12 @@
if (token == nullptr) {
continue;
}
- std::shared_ptr<InputChannel> channel = getInputChannelLocked(token);
- if (channel == nullptr) {
- continue; // Window has gone away
+ std::shared_ptr<Connection> connection = getConnectionLocked(token);
+ if (connection == nullptr) {
+ continue; // Connection has gone away
}
InputTarget target;
- target.inputChannel = channel;
+ target.connection = connection;
inputTargets.push_back(target);
}
return inputTargets;
@@ -2015,12 +2014,12 @@
void InputDispatcher::dispatchDragLocked(nsecs_t currentTime,
std::shared_ptr<const DragEntry> entry) {
- std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
- if (channel == nullptr) {
- return; // Window has gone away
+ std::shared_ptr<Connection> connection = getConnectionLocked(entry->connectionToken);
+ if (connection == nullptr) {
+ return; // Connection has gone away
}
InputTarget target;
- target.inputChannel = channel;
+ target.connection = connection;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
}
@@ -2073,17 +2072,8 @@
pokeUserActivityLocked(*eventEntry);
for (const InputTarget& inputTarget : inputTargets) {
- std::shared_ptr<Connection> connection =
- getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
- if (connection != nullptr) {
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
- } else {
- if (DEBUG_DROPPED_EVENTS_VERBOSE) {
- LOG(INFO) << "Dropping event delivery to target with channel "
- << inputTarget.inputChannel->getName()
- << " because it is no longer registered with the input dispatcher.";
- }
- }
+ std::shared_ptr<Connection> connection = inputTarget.connection;
+ prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
}
}
@@ -2094,7 +2084,7 @@
// sending new pointers to the connection when it blocked, but focused events will continue to
// pile up.
ALOGW("Canceling events for %s because it is unresponsive",
- connection->inputChannel->getName().c_str());
+ connection->getInputChannelName().c_str());
if (connection->status == Connection::Status::NORMAL) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS,
"application not responding");
@@ -2277,17 +2267,11 @@
const std::vector<Monitor>& monitors) const {
std::vector<Monitor> responsiveMonitors;
std::copy_if(monitors.begin(), monitors.end(), std::back_inserter(responsiveMonitors),
- [this](const Monitor& monitor) REQUIRES(mLock) {
- std::shared_ptr<Connection> connection =
- getConnectionLocked(monitor.inputChannel->getConnectionToken());
- if (connection == nullptr) {
- ALOGE("Could not find connection for monitor %s",
- monitor.inputChannel->getName().c_str());
- return false;
- }
+ [](const Monitor& monitor) REQUIRES(mLock) {
+ std::shared_ptr<Connection> connection = monitor.connection;
if (!connection->responsive) {
ALOGW("Unresponsive monitor %s will not get the new gesture",
- connection->inputChannel->getName().c_str());
+ connection->getInputChannelName().c_str());
return false;
}
return true;
@@ -2664,7 +2648,7 @@
for (InputTarget& target : targets) {
if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
sp<WindowInfoHandle> targetWindow =
- getWindowHandleLocked(target.inputChannel->getConnectionToken());
+ getWindowHandleLocked(target.connection->getToken());
if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) {
target.flags |= InputTarget::Flags::ZERO_COORDS;
}
@@ -2862,13 +2846,13 @@
const sp<android::gui::WindowInfoHandle>& windowHandle,
InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
std::optional<nsecs_t> firstDownTimeInTarget) const {
- std::shared_ptr<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
- if (inputChannel == nullptr) {
+ std::shared_ptr<Connection> connection = getConnectionLocked(windowHandle->getToken());
+ if (connection == nullptr) {
ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str());
return {};
}
InputTarget inputTarget;
- inputTarget.inputChannel = inputChannel;
+ inputTarget.connection = connection;
inputTarget.windowHandle = windowHandle;
inputTarget.dispatchMode = dispatchMode;
inputTarget.flags = targetFlags;
@@ -2892,8 +2876,7 @@
std::vector<InputTarget>::iterator it =
std::find_if(inputTargets.begin(), inputTargets.end(),
[&windowHandle](const InputTarget& inputTarget) {
- return inputTarget.inputChannel->getConnectionToken() ==
- windowHandle->getToken();
+ return inputTarget.connection->getToken() == windowHandle->getToken();
});
const WindowInfo* windowInfo = windowHandle->getInfo();
@@ -2933,8 +2916,7 @@
std::vector<InputTarget>::iterator it =
std::find_if(inputTargets.begin(), inputTargets.end(),
[&windowHandle](const InputTarget& inputTarget) {
- return inputTarget.inputChannel->getConnectionToken() ==
- windowHandle->getToken();
+ return inputTarget.connection->getToken() == windowHandle->getToken();
});
// This is a hack, because the actual entry could potentially be an ACTION_DOWN event that
@@ -2984,7 +2966,7 @@
for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
InputTarget target;
- target.inputChannel = monitor.inputChannel;
+ target.connection = monitor.connection;
// target.firstDownTimeInTarget is not set for global monitors. It is only required in split
// touch and global monitoring works as intended even without setting firstDownTimeInTarget
if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
@@ -3499,7 +3481,7 @@
}
dispatchPointerDownOutsideFocus(resolvedMotion->source, resolvedMotion->action,
- inputTarget.inputChannel->getConnectionToken());
+ inputTarget.connection->getToken());
break;
}
@@ -3582,13 +3564,9 @@
continue; // Skip windows that receive ACTION_OUTSIDE
}
- sp<IBinder> token = target.inputChannel->getConnectionToken();
- std::shared_ptr<Connection> connection = getConnectionLocked(token);
- if (connection == nullptr) {
- continue;
- }
+ sp<IBinder> token = target.connection->getToken();
newConnectionTokens.insert(std::move(token));
- newConnections.emplace_back(connection);
+ newConnections.emplace_back(target.connection);
if (target.windowHandle) {
interactionUids.emplace(target.windowHandle->getInfo()->ownerUid);
}
@@ -3608,7 +3586,7 @@
std::string targetList;
for (const std::shared_ptr<Connection>& connection : newConnections) {
- targetList += connection->getWindowName() + ", ";
+ targetList += connection->getInputChannelName() + ", ";
}
std::string message = "Interaction with: " + targetList;
if (targetList.empty()) {
@@ -3822,7 +3800,7 @@
connection->outboundQueue.erase(connection->outboundQueue.begin());
traceOutboundQueueLength(*connection);
if (connection->responsive) {
- mAnrTracker.insert(timeoutTime, connection->inputChannel->getConnectionToken());
+ mAnrTracker.insert(timeoutTime, connection->getToken());
}
traceWaitQueueLength(*connection);
}
@@ -3912,7 +3890,7 @@
auto command = [this, connection]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
- mPolicy.notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
+ mPolicy.notifyInputChannelBroken(connection->getToken());
};
postCommandLocked(std::move(command));
}
@@ -3970,10 +3948,9 @@
if (shouldReportMetricsForConnection(*connection)) {
const InputPublisher::Timeline& timeline =
std::get<InputPublisher::Timeline>(*result);
- mLatencyTracker
- .trackGraphicsLatency(timeline.inputEventId,
- connection->inputChannel->getConnectionToken(),
- std::move(timeline.graphicsTimeline));
+ mLatencyTracker.trackGraphicsLatency(timeline.inputEventId,
+ connection->getToken(),
+ std::move(timeline.graphicsTimeline));
}
}
gotOne = true;
@@ -3994,8 +3971,7 @@
} else {
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn about them.
- const bool stillHaveWindowHandle =
- getWindowHandleLocked(connection->inputChannel->getConnectionToken()) != nullptr;
+ const bool stillHaveWindowHandle = getWindowHandleLocked(connection->getToken()) != nullptr;
notify = !connection->monitor && stillHaveWindowHandle;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. events=0x%x",
@@ -4004,7 +3980,7 @@
}
// Remove the channel.
- removeInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
+ removeInputChannelLocked(connection->getToken(), notify);
return 0; // remove the callback
}
@@ -4019,21 +3995,11 @@
const CancelationOptions& options) {
for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) {
for (const Monitor& monitor : monitors) {
- synthesizeCancelationEventsForInputChannelLocked(monitor.inputChannel, options);
+ synthesizeCancelationEventsForConnectionLocked(monitor.connection, options);
}
}
}
-void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
- const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options) {
- std::shared_ptr<Connection> connection = getConnectionLocked(channel->getConnectionToken());
- if (connection == nullptr) {
- return;
- }
-
- synthesizeCancelationEventsForConnectionLocked(connection, options);
-}
-
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
const std::shared_ptr<Connection>& connection, const CancelationOptions& options) {
if (connection->status != Connection::Status::NORMAL) {
@@ -4062,8 +4028,8 @@
const bool wasEmpty = connection->outboundQueue.empty();
// The target to use if we don't find a window associated with the channel.
- const InputTarget fallbackTarget{.inputChannel = connection->inputChannel};
- const auto& token = connection->inputChannel->getConnectionToken();
+ const InputTarget fallbackTarget{.connection = connection};
+ const auto& token = connection->getToken();
for (size_t i = 0; i < cancelationEvents.size(); i++) {
std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]);
@@ -4164,8 +4130,7 @@
connection->getInputChannelName().c_str(), downEvents.size());
}
- sp<WindowInfoHandle> windowHandle =
- getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+ sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(connection->getToken());
const bool wasEmpty = connection->outboundQueue.empty();
for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -4183,8 +4148,8 @@
targetFlags, pointerIds, motionEntry.downTime,
targets);
} else {
- targets.emplace_back(InputTarget{.inputChannel = connection->inputChannel,
- .flags = targetFlags});
+ targets.emplace_back(
+ InputTarget{.connection = connection, .flags = targetFlags});
const auto it = mDisplayInfos.find(motionEntry.displayId);
if (it != mDisplayInfos.end()) {
targets.back().displayTransform = it->second.transform;
@@ -5141,15 +5106,6 @@
return true;
}
-std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked(
- const sp<IBinder>& token) const {
- auto connectionIt = mConnectionsByToken.find(token);
- if (connectionIt == mConnectionsByToken.end()) {
- return nullptr;
- }
- return connectionIt->second->inputChannel;
-}
-
void InputDispatcher::updateWindowHandlesForDisplayLocked(
const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
if (windowInfoHandles.empty()) {
@@ -5169,7 +5125,7 @@
std::vector<sp<WindowInfoHandle>> newHandles;
for (const sp<WindowInfoHandle>& handle : windowInfoHandles) {
const WindowInfo* info = handle->getInfo();
- if (getInputChannelLocked(handle->getToken()) == nullptr) {
+ if (getConnectionLocked(handle->getToken()) == nullptr) {
const bool noInputChannel =
info->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
const bool canReceiveInput =
@@ -5268,12 +5224,12 @@
if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) {
LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName()
<< " in display %" << displayId;
- std::shared_ptr<InputChannel> touchedInputChannel =
- getInputChannelLocked(touchedWindow.windowHandle->getToken());
- if (touchedInputChannel != nullptr) {
+ std::shared_ptr<Connection> touchedConnection =
+ getConnectionLocked(touchedWindow.windowHandle->getToken());
+ if (touchedConnection != nullptr) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
"touched window was removed");
- synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);
+ synthesizeCancelationEventsForConnectionLocked(touchedConnection, options);
// Since we are about to drop the touch, cancel the events for the wallpaper as
// well.
if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) &&
@@ -5378,14 +5334,13 @@
sp<IBinder> oldFocusedWindowToken =
mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
if (oldFocusedWindowToken != nullptr) {
- std::shared_ptr<InputChannel> inputChannel =
- getInputChannelLocked(oldFocusedWindowToken);
- if (inputChannel != nullptr) {
+ std::shared_ptr<Connection> connection = getConnectionLocked(oldFocusedWindowToken);
+ if (connection != nullptr) {
CancelationOptions
options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
"The display which contains this window no longer has focus.");
options.displayId = ADISPLAY_ID_NONE;
- synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
mFocusedDisplayId = displayId;
@@ -5848,11 +5803,10 @@
if (!mConnectionsByToken.empty()) {
dump += INDENT "Connections:\n";
for (const auto& [token, connection] : mConnectionsByToken) {
- dump += StringPrintf(INDENT2 "%i: channelName='%s', windowName='%s', "
+ dump += StringPrintf(INDENT2 "%i: channelName='%s', "
"status=%s, monitor=%s, responsive=%s\n",
- connection->inputChannel->getFd(),
+ connection->inputPublisher.getChannel()->getFd(),
connection->getInputChannelName().c_str(),
- connection->getWindowName().c_str(),
ftl::enum_string(connection->status).c_str(),
toString(connection->monitor), toString(connection->responsive));
@@ -5906,8 +5860,8 @@
const size_t numMonitors = monitors.size();
for (size_t i = 0; i < numMonitors; i++) {
const Monitor& monitor = monitors[i];
- const std::shared_ptr<InputChannel>& channel = monitor.inputChannel;
- dump += StringPrintf(INDENT2 "%zu: '%s', ", i, channel->getName().c_str());
+ const std::shared_ptr<Connection>& connection = monitor.connection;
+ dump += StringPrintf(INDENT2 "%zu: '%s', ", i, connection->getInputChannelName().c_str());
dump += "\n";
}
}
@@ -5942,10 +5896,10 @@
std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
mIdGenerator);
- if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
+ auto [_, inserted] = mConnectionsByToken.try_emplace(token, connection);
+ if (!inserted) {
ALOGE("Created a new connection, but the token %p is already known", token.get());
}
- mConnectionsByToken.emplace(token, connection);
std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
this, std::placeholders::_1, token);
@@ -5982,14 +5936,15 @@
const sp<IBinder>& token = serverChannel->getConnectionToken();
const int fd = serverChannel->getFd();
- if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
+ auto [_, inserted] = mConnectionsByToken.emplace(token, connection);
+ if (!inserted) {
ALOGE("Created a new connection, but the token %p is already known", token.get());
}
- mConnectionsByToken.emplace(token, connection);
+
std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
this, std::placeholders::_1, token);
- mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid);
+ mGlobalMonitorsByDisplay[displayId].emplace_back(connection, pid);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
nullptr);
@@ -6030,7 +5985,7 @@
removeMonitorChannelLocked(connectionToken);
}
- mLooper->removeFd(connection->inputChannel->getFd());
+ mLooper->removeFd(connection->inputPublisher.getChannel()->getFd());
nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -6043,7 +5998,7 @@
for (auto it = mGlobalMonitorsByDisplay.begin(); it != mGlobalMonitorsByDisplay.end();) {
auto& [displayId, monitors] = *it;
std::erase_if(monitors, [connectionToken](const Monitor& monitor) {
- return monitor.inputChannel->getConnectionToken() == connectionToken;
+ return monitor.connection->getToken() == connectionToken;
});
if (monitors.empty()) {
@@ -6060,8 +6015,8 @@
}
status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) {
- const std::shared_ptr<InputChannel> requestingChannel = getInputChannelLocked(token);
- if (!requestingChannel) {
+ const std::shared_ptr<Connection> requestingConnection = getConnectionLocked(token);
+ if (!requestingConnection) {
LOG(WARNING)
<< "Attempted to pilfer pointers from an un-registered channel or invalid token";
return BAD_VALUE;
@@ -6094,16 +6049,16 @@
std::string canceledWindows;
for (const TouchedWindow& w : state.windows) {
- const std::shared_ptr<InputChannel> channel =
- getInputChannelLocked(w.windowHandle->getToken());
- if (channel != nullptr && channel->getConnectionToken() != token) {
- synthesizeCancelationEventsForInputChannelLocked(channel, options);
+ const std::shared_ptr<Connection> connection =
+ getConnectionLocked(w.windowHandle->getToken());
+ if (connection != nullptr && connection->getToken() != token) {
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
canceledWindows += canceledWindows.empty() ? "[" : ", ";
- canceledWindows += channel->getName();
+ canceledWindows += connection->getInputChannelName();
}
}
canceledWindows += canceledWindows.empty() ? "[]" : "]";
- LOG(INFO) << "Channel " << requestingChannel->getName()
+ LOG(INFO) << "Channel " << requestingConnection->getInputChannelName()
<< " is stealing input gesture for device " << deviceId << " from "
<< canceledWindows;
@@ -6169,7 +6124,7 @@
std::optional<gui::Pid> InputDispatcher::findMonitorPidByTokenLocked(const sp<IBinder>& token) {
for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) {
for (const Monitor& monitor : monitors) {
- if (monitor.inputChannel->getConnectionToken() == token) {
+ if (monitor.connection->getToken() == token) {
return monitor.pid;
}
}
@@ -6201,8 +6156,8 @@
}
void InputDispatcher::removeConnectionLocked(const std::shared_ptr<Connection>& connection) {
- mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
- mConnectionsByToken.erase(connection->inputChannel->getConnectionToken());
+ mAnrTracker.eraseToken(connection->getToken());
+ mConnectionsByToken.erase(connection->getToken());
}
void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
@@ -6224,12 +6179,11 @@
const nsecs_t eventDuration = finishTime - dispatchEntry.deliveryTime;
if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
+ ALOGI("%s spent %" PRId64 "ms processing %s", connection->getInputChannelName().c_str(),
ns2ms(eventDuration), dispatchEntry.eventEntry->getDescription().c_str());
}
if (shouldReportFinishedEvent(dispatchEntry, *connection)) {
- mLatencyTracker.trackFinishedEvent(dispatchEntry.eventEntry->id,
- connection->inputChannel->getConnectionToken(),
+ mLatencyTracker.trackFinishedEvent(dispatchEntry.eventEntry->id, connection->getToken(),
dispatchEntry.deliveryTime, consumeTime, finishTime);
}
@@ -6250,7 +6204,7 @@
std::unique_ptr<DispatchEntry> dispatchEntry = std::move(*entryIt);
connection->waitQueue.erase(entryIt);
- const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
+ const sp<IBinder>& connectionToken = connection->getToken();
mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
if (!connection->responsive) {
connection->responsive = isConnectionResponsive(*connection);
@@ -6261,8 +6215,7 @@
}
traceWaitQueueLength(*connection);
if (fallbackKeyEntry && connection->status == Connection::Status::NORMAL) {
- const InputTarget target{.inputChannel = connection->inputChannel,
- .flags = dispatchEntry->targetFlags};
+ const InputTarget target{.connection = connection, .flags = dispatchEntry->targetFlags};
enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry), target);
}
releaseDispatchEntry(std::move(dispatchEntry));
@@ -6297,7 +6250,7 @@
// is already healthy again. Don't raise ANR in this situation
if (connection->waitQueue.empty()) {
ALOGI("Not raising ANR because the connection %s has recovered",
- connection->inputChannel->getName().c_str());
+ connection->getInputChannelName().c_str());
return;
}
/**
@@ -6312,10 +6265,10 @@
const nsecs_t currentWait = now() - oldestEntry.deliveryTime;
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
- connection->inputChannel->getName().c_str(),
+ connection->getInputChannelName().c_str(),
ns2ms(currentWait),
oldestEntry.eventEntry->getDescription().c_str());
- sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
+ sp<IBinder> connectionToken = connection->getToken();
updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
processConnectionUnresponsiveLocked(*connection, std::move(reason));
@@ -6414,15 +6367,15 @@
*/
void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
std::string reason) {
- const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+ const sp<IBinder>& connectionToken = connection.getToken();
std::optional<gui::Pid> pid;
if (connection.monitor) {
- ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+ ALOGW("Monitor %s is unresponsive: %s", connection.getInputChannelName().c_str(),
reason.c_str());
pid = findMonitorPidByTokenLocked(connectionToken);
} else {
// The connection is a window
- ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+ ALOGW("Window %s is unresponsive: %s", connection.getInputChannelName().c_str(),
reason.c_str());
const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
if (handle != nullptr) {
@@ -6436,7 +6389,7 @@
* Tell the policy that a connection has become responsive so that it can stop ANR.
*/
void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) {
- const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+ const sp<IBinder>& connectionToken = connection.getToken();
std::optional<gui::Pid> pid;
if (connection.monitor) {
pid = findMonitorPidByTokenLocked(connectionToken);
@@ -6487,8 +6440,8 @@
mLock.unlock();
if (const auto unhandledKeyFallback =
- mPolicy.dispatchUnhandledKey(connection->inputChannel->getConnectionToken(),
- event, keyEntry.policyFlags);
+ mPolicy.dispatchUnhandledKey(connection->getToken(), event,
+ keyEntry.policyFlags);
unhandledKeyFallback) {
event = *unhandledKeyFallback;
}
@@ -6532,8 +6485,8 @@
mLock.unlock();
bool fallback = false;
- if (auto fb = mPolicy.dispatchUnhandledKey(connection->inputChannel->getConnectionToken(),
- event, keyEntry.policyFlags);
+ if (auto fb = mPolicy.dispatchUnhandledKey(connection->getToken(), event,
+ keyEntry.policyFlags);
fb) {
fallback = true;
event = *fb;
@@ -6641,7 +6594,8 @@
void InputDispatcher::traceOutboundQueueLength(const Connection& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
- snprintf(counterName, sizeof(counterName), "oq:%s", connection.getWindowName().c_str());
+ snprintf(counterName, sizeof(counterName), "oq:%s",
+ connection.getInputChannelName().c_str());
ATRACE_INT(counterName, connection.outboundQueue.size());
}
}
@@ -6649,7 +6603,8 @@
void InputDispatcher::traceWaitQueueLength(const Connection& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
- snprintf(counterName, sizeof(counterName), "wq:%s", connection.getWindowName().c_str());
+ snprintf(counterName, sizeof(counterName), "wq:%s",
+ connection.getInputChannelName().c_str());
ATRACE_INT(counterName, connection.waitQueue.size());
}
}
@@ -6720,11 +6675,11 @@
void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& changes) {
if (changes.oldFocus) {
- std::shared_ptr<InputChannel> focusedInputChannel = getInputChannelLocked(changes.oldFocus);
- if (focusedInputChannel) {
+ std::shared_ptr<Connection> focusedConnection = getConnectionLocked(changes.oldFocus);
+ if (focusedConnection) {
CancelationOptions options(CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS,
"focus left window");
- synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
+ synthesizeCancelationEventsForConnectionLocked(focusedConnection, options);
enqueueFocusEventLocked(changes.oldFocus, /*hasFocus=*/false, changes.reason);
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e635852..155d485 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -369,8 +369,6 @@
REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
- std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
- REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(int displayId) const
REQUIRES(mLock);
bool canWindowReceiveMotionLocked(const sp<android::gui::WindowInfoHandle>& window,
@@ -617,9 +615,6 @@
REQUIRES(mLock);
void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options)
REQUIRES(mLock);
- void synthesizeCancelationEventsForInputChannelLocked(
- const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options)
- REQUIRES(mLock);
void synthesizeCancelationEventsForConnectionLocked(
const std::shared_ptr<Connection>& connection, const CancelationOptions& options)
REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index c02c5d6..28e3c6d 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -83,9 +83,9 @@
}
std::ostream& operator<<(std::ostream& out, const InputTarget& target) {
- out << "{inputChannel=";
- if (target.inputChannel != nullptr) {
- out << target.inputChannel->getName();
+ out << "{connection=";
+ if (target.connection != nullptr) {
+ out << target.connection->getInputChannelName();
} else {
out << "<null>";
}
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index aef866b..5728bdf 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -19,10 +19,11 @@
#include <ftl/flags.h>
#include <gui/WindowInfo.h>
#include <gui/constants.h>
-#include <input/InputTransport.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
#include <bitset>
+#include "Connection.h"
+#include "InputTargetFlags.h"
namespace android::inputdispatcher {
@@ -33,29 +34,7 @@
* window area.
*/
struct InputTarget {
- enum class Flags : uint32_t {
- /* This flag indicates that the event is being delivered to a foreground application. */
- FOREGROUND = 1 << 0,
-
- /* This flag indicates that the MotionEvent falls within the area of the target
- * obscured by another visible window above it. The motion event should be
- * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
- WINDOW_IS_OBSCURED = 1 << 1,
-
- /* This flag indicates that a motion event is being split across multiple windows. */
- SPLIT = 1 << 2,
-
- /* This flag indicates that the pointer coordinates dispatched to the application
- * will be zeroed out to avoid revealing information to an application. This is
- * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
- * the same UID from watching all touches. */
- ZERO_COORDS = 1 << 3,
-
- /* This flag indicates that the target of a MotionEvent is partly or wholly
- * obscured by another visible window above it. The motion event should be
- * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
- WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
- };
+ using Flags = InputTargetFlags;
enum class DispatchMode {
/* This flag indicates that the event should be sent as is.
@@ -85,8 +64,8 @@
ftl_last = SLIPPERY_ENTER,
};
- // The input channel to be targeted.
- std::shared_ptr<InputChannel> inputChannel;
+ // The input connection to be targeted.
+ std::shared_ptr<Connection> connection;
// Flags for the input target.
ftl::Flags<Flags> flags;
diff --git a/services/inputflinger/dispatcher/InputTargetFlags.h b/services/inputflinger/dispatcher/InputTargetFlags.h
new file mode 100644
index 0000000..7497543
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputTargetFlags.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2024 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 <ftl/flags.h>
+
+namespace android::inputdispatcher {
+
+enum class InputTargetFlags : uint32_t {
+ /* This flag indicates that the event is being delivered to a foreground application. */
+ FOREGROUND = 1 << 0,
+
+ /* This flag indicates that the MotionEvent falls within the area of the target
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
+ WINDOW_IS_OBSCURED = 1 << 1,
+
+ /* This flag indicates that a motion event is being split across multiple windows. */
+ SPLIT = 1 << 2,
+
+ /* This flag indicates that the pointer coordinates dispatched to the application
+ * will be zeroed out to avoid revealing information to an application. This is
+ * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
+ * the same UID from watching all touches. */
+ ZERO_COORDS = 1 << 3,
+
+ /* This flag indicates that the target of a MotionEvent is partly or wholly
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
+ WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
+};
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp
index 204791e..4e77d90 100644
--- a/services/inputflinger/dispatcher/Monitor.cpp
+++ b/services/inputflinger/dispatcher/Monitor.cpp
@@ -19,7 +19,7 @@
namespace android::inputdispatcher {
// --- Monitor ---
-Monitor::Monitor(const std::shared_ptr<InputChannel>& inputChannel, gui::Pid pid)
- : inputChannel(inputChannel), pid(pid) {}
+Monitor::Monitor(const std::shared_ptr<Connection>& connection, gui::Pid pid)
+ : connection(connection), pid(pid) {}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
index 1b1eb3a..d15a222 100644
--- a/services/inputflinger/dispatcher/Monitor.h
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -17,16 +17,16 @@
#pragma once
#include <gui/PidUid.h>
-#include <input/InputTransport.h>
+#include "Connection.h"
namespace android::inputdispatcher {
struct Monitor {
- std::shared_ptr<InputChannel> inputChannel; // never null
+ std::shared_ptr<Connection> connection; // never null
gui::Pid pid;
- explicit Monitor(const std::shared_ptr<InputChannel>& inputChannel, gui::Pid pid);
+ explicit Monitor(const std::shared_ptr<Connection>& connection, gui::Pid pid);
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index a41064b..f3f15df 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -251,6 +251,7 @@
mAssociatedDeviceType =
getValueByKey(readerConfig.deviceTypeAssociations, mIdentifier.location);
mIsWaking = mConfiguration.getBool("device.wake").value_or(false);
+ mShouldSmoothScroll = mConfiguration.getBool("device.viewBehavior_smoothScroll");
}
if (!changes.any() || changes.test(Change::DEVICE_ALIAS)) {
@@ -401,7 +402,8 @@
InputDeviceInfo InputDevice::getDeviceInfo() {
InputDeviceInfo outDeviceInfo;
outDeviceInfo.initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
- mHasMic, getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE));
+ mHasMic, getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE),
+ {mShouldSmoothScroll});
for_each_mapper(
[&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index ba7234b..0719b0c 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -199,6 +199,7 @@
std::optional<DisplayViewport> mAssociatedViewport;
bool mHasMic;
bool mDropUntilNextSync;
+ std::optional<bool> mShouldSmoothScroll;
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
diff --git a/services/inputflinger/rust/lib.rs b/services/inputflinger/rust/lib.rs
index da72134..25dfb03 100644
--- a/services/inputflinger/rust/lib.rs
+++ b/services/inputflinger/rust/lib.rs
@@ -70,7 +70,9 @@
/// incremented using `AIBinder_incStrong`. See `binder::unstable_api::new_spibinder`.
unsafe fn create_inputflinger_rust(callback: *mut ffi::IInputFlingerRustBootstrapCallbackAIBinder) {
logger::init(
- logger::Config::default().with_tag_on_device(LOG_TAG).with_min_level(log::Level::Trace),
+ logger::Config::default()
+ .with_tag_on_device(LOG_TAG)
+ .with_max_level(log::LevelFilter::Trace),
);
let callback = callback as *mut AIBinder;
diff --git a/services/inputflinger/tests/FakeInputTracingBackend.cpp b/services/inputflinger/tests/FakeInputTracingBackend.cpp
index 77d35fb..1d27107 100644
--- a/services/inputflinger/tests/FakeInputTracingBackend.cpp
+++ b/services/inputflinger/tests/FakeInputTracingBackend.cpp
@@ -23,7 +23,11 @@
namespace {
-constexpr auto TRACE_TIMEOUT = std::chrono::milliseconds(100);
+// Use a larger timeout while waiting for events to be traced, compared to the timeout used while
+// waiting to receive events through the input channel. Events are traced from a separate thread,
+// which does not have the same high thread priority as the InputDispatcher's thread, so the tracer
+// is expected to lag behind the Dispatcher at times.
+constexpr auto TRACE_TIMEOUT = std::chrono::seconds(5);
base::ResultError<> error(const std::ostringstream& ss) {
return base::ResultError(ss.str(), BAD_VALUE);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 460a7b1..c1dc7ff 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2706,6 +2706,31 @@
ASSERT_NO_FATAL_FAILURE(mapper2.assertProcessWasCalled());
}
+TEST_F(InputDeviceTest, Configure_SmoothScrollViewBehaviorNotSet) {
+ // Set some behavior to force the configuration to be update.
+ mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.wake", "1");
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(),
+ AINPUT_SOURCE_KEYBOARD);
+
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ /*changes=*/{});
+
+ ASSERT_FALSE(mDevice->getDeviceInfo().getViewBehavior().shouldSmoothScroll.has_value());
+}
+
+TEST_F(InputDeviceTest, Configure_SmoothScrollViewBehaviorEnabled) {
+ mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.viewBehavior_smoothScroll", "1");
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(),
+ AINPUT_SOURCE_KEYBOARD);
+
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ /*changes=*/{});
+
+ ASSERT_TRUE(mDevice->getDeviceInfo().getViewBehavior().shouldSmoothScroll.value_or(false));
+}
+
TEST_F(InputDeviceTest, WakeDevice_AddsWakeFlagToProcessNotifyArgs) {
mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.wake", "1");
FakeInputMapper& mapper =
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 38974a2..3ef9e69 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -315,6 +315,7 @@
if (obj.hasInputInfo()) {
out << "\n input{"
<< "(" << obj.inputInfo.inputConfig.string() << ")";
+ if (obj.inputInfo.canOccludePresentation) out << " canOccludePresentation";
if (obj.touchCropId != UNASSIGNED_LAYER_ID) out << " touchCropId=" << obj.touchCropId;
if (obj.inputInfo.replaceTouchableRegionWithCrop) out << " replaceTouchableRegionWithCrop";
auto touchableRegion = obj.inputInfo.touchableRegion.getBounds();
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 8df5d8c..0966fe0 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1044,6 +1044,8 @@
snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
? requested.windowInfoHandle->getInfo()->touchOcclusionMode
: parentSnapshot.inputInfo.touchOcclusionMode;
+ snapshot.inputInfo.canOccludePresentation = parentSnapshot.inputInfo.canOccludePresentation ||
+ (requested.flags & layer_state_t::eCanOccludePresentation);
if (requested.dropInputMode == gui::DropInputMode::ALL ||
parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
snapshot.dropInputMode = gui::DropInputMode::ALL;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 209df79..2cf4c1b 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -170,6 +170,9 @@
if ((oldFlags ^ flags) & layer_state_t::eIgnoreDestinationFrame) {
changes |= RequestedLayerState::Changes::Geometry;
}
+ if ((oldFlags ^ flags) & layer_state_t::eCanOccludePresentation) {
+ changes |= RequestedLayerState::Changes::Input;
+ }
}
if (clientState.what & layer_state_t::eBufferChanged) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index c80c8fd..ccd1c0f 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -404,6 +404,9 @@
}();
generateFrameTimeline(vsyncEventData, frameInterval.ns(), systemTime(SYSTEM_TIME_MONOTONIC),
presentTime, deadline);
+ if (FlagManager::getInstance().vrr_config()) {
+ mCallback.onExpectedPresentTimePosted(TimePoint::fromNs(presentTime));
+ }
return vsyncEventData;
}
@@ -721,6 +724,11 @@
removeDisplayEventConnectionLocked(consumer);
}
}
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
+ FlagManager::getInstance().vrr_config()) {
+ mCallback.onExpectedPresentTimePosted(
+ TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()));
+ }
}
void EventThread::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 8970103..90e61a9 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -142,6 +142,7 @@
virtual bool throttleVsync(TimePoint, uid_t) = 0;
virtual Period getVsyncPeriod(uid_t) = 0;
virtual void resync() = 0;
+ virtual void onExpectedPresentTimePosted(TimePoint) = 0;
};
namespace impl {
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index 3b61de7..9f4f5b6 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -30,6 +30,8 @@
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
virtual void onChoreographerAttached() = 0;
+ virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>,
+ Fps renderRate) = 0;
protected:
~ISchedulerCallback() = default;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c76d4bd..6979f03 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -71,15 +71,13 @@
namespace android::scheduler {
Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features,
- surfaceflinger::Factory& factory, Fps activeRefreshRate, TimeStats& timeStats,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ surfaceflinger::Factory& factory, Fps activeRefreshRate, TimeStats& timeStats)
: android::impl::MessageQueue(compositor),
mFeatures(features),
mVsyncConfiguration(factory.createVsyncConfiguration(activeRefreshRate)),
mVsyncModulator(sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs())),
mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate)),
- mSchedulerCallback(callback),
- mVsyncTrackerCallback(vsyncTrackerCallback) {}
+ mSchedulerCallback(callback) {}
Scheduler::~Scheduler() {
// MessageQueue depends on VsyncSchedule, so first destroy it.
@@ -134,10 +132,11 @@
}
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
- auto schedulePtr = std::make_shared<VsyncSchedule>(
- selectorPtr->getActiveMode().modePtr, mFeatures,
- [this](PhysicalDisplayId id, bool enable) { onHardwareVsyncRequest(id, enable); },
- mVsyncTrackerCallback);
+ auto schedulePtr =
+ std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
+ [this](PhysicalDisplayId id, bool enable) {
+ onHardwareVsyncRequest(id, enable);
+ });
registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
}
@@ -222,7 +221,12 @@
targets.try_emplace(id, &targeter.target());
}
- if (!compositor.commit(pacesetterPtr->displayId, targets)) return;
+ if (!compositor.commit(pacesetterPtr->displayId, targets)) {
+ if (FlagManager::getInstance().vrr_config()) {
+ compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
+ }
+ return;
+ }
}
// The pacesetter may have changed or been registered anew during commit.
@@ -263,6 +267,9 @@
}
const auto resultsPerDisplay = compositor.composite(pacesetterPtr->displayId, targeters);
+ if (FlagManager::getInstance().vrr_config()) {
+ compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
+ }
compositor.sample();
for (const auto& [id, targeter] : targeters) {
@@ -323,6 +330,19 @@
// behaviour.
return Period::fromNs(currentPeriod.ns() * divisor);
}
+void Scheduler::onExpectedPresentTimePosted(TimePoint expectedPresentTime) {
+ const auto frameRateMode = [this] {
+ std::scoped_lock lock(mDisplayLock);
+ const auto pacesetterOpt = pacesetterDisplayLocked();
+ const Display& pacesetter = *pacesetterOpt;
+ return pacesetter.selectorPtr->getActiveMode();
+ }();
+
+ if (frameRateMode.modePtr->getVrrConfig()) {
+ mSchedulerCallback.onExpectedPresentTimePosted(expectedPresentTime, frameRateMode.modePtr,
+ frameRateMode.fps);
+ }
+}
ConnectionHandle Scheduler::createEventThread(Cycle cycle,
frametimeline::TokenManager* tokenManager,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9912622..9f29e9f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -111,7 +111,7 @@
public:
Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags, surfaceflinger::Factory&,
- Fps activeRefreshRate, TimeStats&, IVsyncTrackerCallback&);
+ Fps activeRefreshRate, TimeStats&);
virtual ~Scheduler();
void startTimers();
@@ -458,6 +458,7 @@
bool throttleVsync(TimePoint, uid_t) override;
Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock);
void resync() override EXCLUDES(mDisplayLock);
+ void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock);
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
@@ -497,8 +498,6 @@
ISchedulerCallback& mSchedulerCallback;
- IVsyncTrackerCallback& mVsyncTrackerCallback;
-
// mDisplayLock may be locked while under mPolicyLock.
mutable std::mutex mPolicyLock;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 6e12b33..8697696 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -48,14 +48,12 @@
VSyncPredictor::~VSyncPredictor() = default;
VSyncPredictor::VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize,
- size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent,
- IVsyncTrackerCallback& callback)
+ size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent)
: mId(modePtr->getPhysicalDisplayId()),
mTraceOn(property_get_bool("debug.sf.vsp_trace", false)),
kHistorySize(historySize),
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
- mVsyncTrackerCallback(callback),
mDisplayModePtr(modePtr) {
resetModel();
}
@@ -312,13 +310,7 @@
FlagManager::getInstance().vrr_config() && !lastFrameMissed && lastVsyncOpt
? std::max(timePoint, *lastVsyncOpt + minFramePeriod - threshold)
: timePoint;
- const auto vsyncTime = snapToVsyncAlignedWithRenderRate(baseTime);
- if (FlagManager::getInstance().vrr_config() && mDisplayModePtr->getVrrConfig()) {
- const auto vsyncTimePoint = TimePoint::fromNs(vsyncTime);
- const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps();
- mVsyncTrackerCallback.onVsyncGenerated(vsyncTimePoint, mDisplayModePtr, renderRate);
- }
- return vsyncTime;
+ return snapToVsyncAlignedWithRenderRate(baseTime);
}
nsecs_t VSyncPredictor::snapToVsyncAlignedWithRenderRate(nsecs_t timePoint) const {
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 9191003..8fd7e60 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -37,11 +37,9 @@
* \param [in] minimumSamplesForPrediction The minimum number of samples to collect before
* predicting. \param [in] outlierTolerancePercent a number 0 to 100 that will be used to filter
* samples that fall outlierTolerancePercent from an anticipated vsync event.
- * \param [in] IVsyncTrackerCallback The callback for the VSyncTracker.
*/
VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize,
- size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent,
- IVsyncTrackerCallback&);
+ size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent);
~VSyncPredictor();
bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex);
@@ -106,7 +104,6 @@
size_t const kHistorySize;
size_t const kMinimumSamplesForPrediction;
size_t const kOutlierTolerancePercent;
- IVsyncTrackerCallback& mVsyncTrackerCallback;
std::mutex mutable mMutex;
std::optional<nsecs_t> mKnownTimestamp GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 417163f..37bd4b4 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -26,12 +26,6 @@
namespace android::scheduler {
-struct IVsyncTrackerCallback {
- virtual ~IVsyncTrackerCallback() = default;
- virtual void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
- Fps renderRate) = 0;
-};
-
/*
* VSyncTracker is an interface for providing estimates on future Vsync signal times based on
* historical vsync timing data.
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index 3491600..001938c 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -57,11 +57,10 @@
};
VsyncSchedule::VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags features,
- RequestHardwareVsync requestHardwareVsync,
- IVsyncTrackerCallback& callback)
+ RequestHardwareVsync requestHardwareVsync)
: mId(modePtr->getPhysicalDisplayId()),
mRequestHardwareVsync(std::move(requestHardwareVsync)),
- mTracker(createTracker(modePtr, callback)),
+ mTracker(createTracker(modePtr)),
mDispatch(createDispatch(mTracker)),
mController(createController(modePtr->getPhysicalDisplayId(), *mTracker, features)),
mTracer(features.test(Feature::kTracePredictedVsync)
@@ -115,15 +114,14 @@
mDispatch->dump(out);
}
-VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull<DisplayModePtr> modePtr,
- IVsyncTrackerCallback& callback) {
+VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull<DisplayModePtr> modePtr) {
// TODO(b/144707443): Tune constants.
constexpr size_t kHistorySize = 20;
constexpr size_t kMinSamplesForPrediction = 6;
constexpr uint32_t kDiscardOutlierPercent = 20;
return std::make_unique<VSyncPredictor>(modePtr, kHistorySize, kMinSamplesForPrediction,
- kDiscardOutlierPercent, callback);
+ kDiscardOutlierPercent);
}
VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(TrackerPtr tracker) {
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 6f656d2..85cd3e7 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -57,8 +57,7 @@
public:
using RequestHardwareVsync = std::function<void(PhysicalDisplayId, bool enabled)>;
- VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags, RequestHardwareVsync,
- IVsyncTrackerCallback&);
+ VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags, RequestHardwareVsync);
~VsyncSchedule();
// IVsyncSource overrides:
@@ -128,7 +127,7 @@
friend class android::VsyncScheduleTest;
friend class android::fuzz::SchedulerFuzzer;
- static TrackerPtr createTracker(ftl::NonNull<DisplayModePtr> modePtr, IVsyncTrackerCallback&);
+ static TrackerPtr createTracker(ftl::NonNull<DisplayModePtr> modePtr);
static DispatchPtr createDispatch(TrackerPtr);
static ControllerPtr createController(PhysicalDisplayId, VsyncTracker&, FeatureFlags);
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
index 12ee36e..8673a22 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -47,6 +47,9 @@
virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
const scheduler::FrameTargeters&) = 0;
+ // Sends a hint about the expected present time
+ virtual void sendNotifyExpectedPresentHint(PhysicalDisplayId) = 0;
+
// Samples the composited frame via RegionSamplingThread.
virtual void sample() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8512219..ffda2c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2753,23 +2753,11 @@
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime();
// TODO(b/255601557) Update frameInterval per display
- refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime);
+ refreshArgs.frameInterval =
+ mScheduler->getNextFrameInterval(pacesetterId, pacesetterTarget.expectedPresentTime());
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
- {
- auto& notifyExpectedPresentData = mNotifyExpectedPresentMap[pacesetterId];
- auto lastExpectedPresentTimestamp = TimePoint::fromNs(
- notifyExpectedPresentData.lastExpectedPresentTimestamp.load().ns());
- if (expectedPresentTime > lastExpectedPresentTimestamp) {
- // If the values are not same, then hint is sent with newer value.
- // And because composition always follows the notifyExpectedPresentIfRequired, we can
- // skip updating the lastExpectedPresentTimestamp in this case.
- notifyExpectedPresentData.lastExpectedPresentTimestamp
- .compare_exchange_weak(lastExpectedPresentTimestamp, expectedPresentTime);
- }
- }
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
@@ -2833,6 +2821,7 @@
scheduleComposite(FrameHint::kNone);
}
+ mNotifyExpectedPresentMap[pacesetterId].hintStatus = NotifyExpectedPresentHintStatus::Start;
onCompositionPresented(pacesetterId, frameTargeters, presentTime);
const bool hadGpuComposited =
@@ -4114,8 +4103,9 @@
}
}
-void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime,
- ftl::NonNull<DisplayModePtr> modePtr, Fps renderRate) {
+void SurfaceFlinger::onExpectedPresentTimePosted(TimePoint expectedPresentTime,
+ ftl::NonNull<DisplayModePtr> modePtr,
+ Fps renderRate) {
const auto vsyncPeriod = modePtr->getVsyncRate().getPeriod();
const auto timeoutOpt = [&]() -> std::optional<Period> {
const auto vrrConfig = modePtr->getVrrConfig();
@@ -4136,45 +4126,91 @@
TimePoint expectedPresentTime,
Fps frameInterval,
std::optional<Period> timeoutOpt) {
- {
- auto& data = mNotifyExpectedPresentMap[displayId];
- const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp.load();
- const auto lastFrameInterval = data.lastFrameInterval;
- data.lastFrameInterval = frameInterval;
- const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2);
+ auto& data = mNotifyExpectedPresentMap[displayId];
+ const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp;
+ const auto lastFrameInterval = data.lastFrameInterval;
+ data.lastFrameInterval = frameInterval;
+ data.lastExpectedPresentTimestamp = expectedPresentTime;
+ const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2);
- const constexpr nsecs_t kOneSecondNs =
- std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
- const auto timeout = Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns()
- : kOneSecondNs);
- const bool frameIntervalIsOnCadence =
- isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp,
- lastFrameInterval, timeout, threshold);
+ const constexpr nsecs_t kOneSecondNs =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+ const auto timeout =
+ Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns() : kOneSecondNs);
+ const bool frameIntervalIsOnCadence =
+ isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp,
+ lastFrameInterval, timeout, threshold);
- const bool expectedPresentWithinTimeout =
- isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp,
- timeoutOpt, threshold);
+ const bool expectedPresentWithinTimeout =
+ isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp,
+ timeoutOpt, threshold);
+ if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) {
+ return;
+ }
- using fps_approx_ops::operator!=;
- if (frameIntervalIsOnCadence && frameInterval != lastFrameInterval) {
- data.lastExpectedPresentTimestamp = expectedPresentTime;
- }
-
- if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) {
+ auto hintStatus = data.hintStatus.load();
+ if (!expectedPresentWithinTimeout) {
+ if (hintStatus != NotifyExpectedPresentHintStatus::Sent ||
+ (timeoutOpt && timeoutOpt->ns() == 0)) {
+ // Send the hint immediately if timeout, as the hint gets
+ // delayed otherwise, as the frame is scheduled close
+ // to the actual present.
+ if (data.hintStatus
+ .compare_exchange_strong(hintStatus,
+ NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
+ scheduleNotifyExpectedPresentHint(displayId);
+ }
return;
}
- data.lastExpectedPresentTimestamp = expectedPresentTime;
+ }
+
+ if (hintStatus != NotifyExpectedPresentHintStatus::Start) {
+ return;
+ }
+ data.hintStatus.store(NotifyExpectedPresentHintStatus::ScheduleOnPresent);
+ mScheduler->scheduleFrame();
+}
+
+void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ auto itr = mNotifyExpectedPresentMap.find(displayId);
+ if (itr == mNotifyExpectedPresentMap.end()) {
+ return;
}
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
- const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
- frameInterval);
+ const auto sendHint = [=, this]() {
+ auto& data = mNotifyExpectedPresentMap.at(displayId);
+ data.hintStatus.store(NotifyExpectedPresentHintStatus::Sent);
+ const auto status =
+ getHwComposer().notifyExpectedPresent(displayId, data.lastExpectedPresentTimestamp,
+ data.lastFrameInterval);
if (status != NO_ERROR) {
ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
displayId.value);
}
- }));
+ };
+
+ if (itr->second.hintStatus == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
+ return static_cast<void>(mScheduler->schedule([=,
+ this]() FTL_FAKE_GUARD(kMainThreadContext) {
+ auto& data = mNotifyExpectedPresentMap.at(displayId);
+ auto scheduleHintOnTx = NotifyExpectedPresentHintStatus::ScheduleOnTx;
+ if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx,
+ NotifyExpectedPresentHintStatus::Sent)) {
+ sendHint();
+ }
+ }));
+ }
+ sendHint();
+}
+
+void SurfaceFlinger::sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ if (auto itr = mNotifyExpectedPresentMap.find(displayId);
+ itr == mNotifyExpectedPresentMap.end() ||
+ itr->second.hintStatus != NotifyExpectedPresentHintStatus::ScheduleOnPresent) {
+ return;
+ }
+ scheduleNotifyExpectedPresentHint(displayId);
}
void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
@@ -4216,8 +4252,7 @@
mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this),
static_cast<ISchedulerCallback&>(*this), features,
- getFactory(), activeRefreshRate, *mTimeStats,
- static_cast<IVsyncTrackerCallback&>(*this));
+ getFactory(), activeRefreshRate, *mTimeStats);
mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
if (FlagManager::getInstance().vrr_config()) {
mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c8e2a4d..992bc00 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -199,8 +199,7 @@
private HWC2::ComposerCallback,
private ICompositor,
private scheduler::ISchedulerCallback,
- private compositionengine::ICEPowerCallback,
- private scheduler::IVsyncTrackerCallback {
+ private compositionengine::ICEPowerCallback {
public:
struct SkipInitializationTag {};
@@ -686,14 +685,12 @@
void kernelTimerChanged(bool expired) override;
void triggerOnFrameRateOverridesChanged() override;
void onChoreographerAttached() override;
+ void onExpectedPresentTimePosted(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
+ Fps renderRate) override;
// ICEPowerCallback overrides:
void notifyCpuLoadUp() override;
- // IVsyncTrackerCallback overrides
- void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
- Fps renderRate) override;
-
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
void toggleKernelIdleTimer() REQUIRES(mStateLock);
@@ -1482,14 +1479,28 @@
ftl::SmallMap<int64_t, sp<SurfaceControl>, 3> mMirrorMapForDebug;
// NotifyExpectedPresentHint
+ enum class NotifyExpectedPresentHintStatus {
+ // Represents that framework can start sending hint if required.
+ Start,
+ // Represents that the hint is already sent.
+ Sent,
+ // Represents that the hint will be scheduled with a new frame.
+ ScheduleOnPresent,
+ // Represents that a hint will be sent instantly by scheduling on the main thread.
+ ScheduleOnTx
+ };
struct NotifyExpectedPresentData {
- // lastExpectedPresentTimestamp is read and write from multiple threads such as
- // main thread, EventThread, MessageQueue. And is atomic for that reason.
- std::atomic<TimePoint> lastExpectedPresentTimestamp{};
+ TimePoint lastExpectedPresentTimestamp{};
Fps lastFrameInterval{};
+ // hintStatus is read and write from multiple threads such as
+ // main thread, EventThread. And is atomic for that reason.
+ std::atomic<NotifyExpectedPresentHintStatus> hintStatus =
+ NotifyExpectedPresentHintStatus::Start;
};
std::unordered_map<PhysicalDisplayId, NotifyExpectedPresentData> mNotifyExpectedPresentMap;
-
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) override
+ REQUIRES(kMainThreadContext);
+ void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId);
void notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod,
TimePoint expectedPresentTime, Fps frameInterval,
std::optional<Period> timeoutOpt);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index fa79956..0d15f62 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -228,9 +228,9 @@
VsyncSchedule::TrackerPtr tracker,
std::shared_ptr<RefreshRateSelector> selectorPtr,
surfaceflinger::Factory& factory, TimeStats& timeStats,
- ISchedulerCallback& callback, IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& callback)
: Scheduler(*this, callback, Feature::kContentDetection, factory,
- selectorPtr->getActiveMode().fps, timeStats, vsyncTrackerCallback) {
+ selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplayInternal(displayId, std::move(selectorPtr),
std::shared_ptr<VsyncSchedule>(
@@ -289,6 +289,8 @@
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
+
// MessageQueue overrides:
void scheduleFrame() override {}
void postMessage(sp<MessageHandler>&& handler) override { handler->handleMessage(Message()); }
@@ -396,8 +398,7 @@
} // namespace surfaceflinger::test
// TODO(b/189053744) : Create a common test/mock library for surfaceflinger
-class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback,
- private scheduler::IVsyncTrackerCallback {
+class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback {
public:
using HotplugEvent = SurfaceFlinger::HotplugEvent;
@@ -660,7 +661,6 @@
std::unique_ptr<EventThread> appEventThread,
std::unique_ptr<EventThread> sfEventThread,
scheduler::ISchedulerCallback* callback = nullptr,
- scheduler::IVsyncTrackerCallback* vsyncTrackerCallback = nullptr,
bool hasMultipleModes = false) {
constexpr DisplayModeId kModeId60{0};
DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz));
@@ -675,8 +675,7 @@
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
std::move(vsyncTracker), mRefreshRateSelector,
mFactory, *mFlinger->mTimeStats,
- *(callback ?: this),
- *(vsyncTrackerCallback ?: this));
+ *(callback ?: this));
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -796,9 +795,7 @@
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
void onChoreographerAttached() override {}
-
- // IVsyncTrackerCallback overrides
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
+ void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger =
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index a6b12d0..8cd6e1b 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -103,6 +103,7 @@
bool throttleVsync(TimePoint, uid_t) override { return false; }
Period getVsyncPeriod(uid_t) override { return kSyncPeriod; }
void resync() override {}
+ void onExpectedPresentTimePosted(TimePoint) override {}
};
void SchedulerFuzzer::fuzzEventThread() {
@@ -180,21 +181,15 @@
dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp);
}
-struct VsyncTrackerCallback : public scheduler::IVsyncTrackerCallback {
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
-};
-
void SchedulerFuzzer::fuzzVSyncPredictor() {
uint16_t now = mFdp.ConsumeIntegral<uint16_t>();
uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
nsecs_t idealPeriod = mFdp.ConsumeIntegralInRange<nsecs_t>(1, UINT32_MAX);
- VsyncTrackerCallback callback;
const auto mode = ftl::as_non_null(
mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(idealPeriod)));
scheduler::VSyncPredictor tracker{mode, historySize, minimumSamplesForPrediction,
- mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/,
- callback};
+ mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/};
uint16_t period = mFdp.ConsumeIntegral<uint16_t>();
tracker.setDisplayModePtr(ftl::as_non_null(
mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(period))));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 1379665..fa31643 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -80,8 +80,7 @@
std::unique_ptr<EventThread>(mEventThread),
std::unique_ptr<EventThread>(mSFEventThread),
TestableSurfaceFlinger::DefaultDisplayMode{displayId},
- TestableSurfaceFlinger::SchedulerCallbackImpl::kMock,
- TestableSurfaceFlinger::VsyncTrackerCallbackImpl::kMock);
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kMock);
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 45db0c5..d5ec654 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -85,6 +85,7 @@
bool throttleVsync(TimePoint, uid_t) override;
Period getVsyncPeriod(uid_t) override;
void resync() override;
+ void onExpectedPresentTimePosted(TimePoint) override;
void setupEventThread();
sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
@@ -107,6 +108,7 @@
int32_t expectedConfigId,
nsecs_t expectedVsyncPeriod);
void expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t);
+ void expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime);
void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
std::vector<FrameRateOverride>);
@@ -131,6 +133,7 @@
mVSyncCallbackUnregisterRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t, uid_t)> mThrottleVsyncCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t)> mOnExpectedPresentTimePostedRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
ConnectionEventRecorder mThrottledConnectionEventCallRecorder{0};
@@ -190,6 +193,10 @@
mResyncCallRecorder.recordCall();
}
+void EventThreadTest::onExpectedPresentTimePosted(TimePoint expectedPresentTime) {
+ mOnExpectedPresentTimePostedRecorder.recordCall(expectedPresentTime.ns());
+}
+
void EventThreadTest::setupEventThread() {
mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
mThread = std::make_unique<impl::EventThread>("EventThreadTest", mVsyncSchedule,
@@ -244,6 +251,12 @@
EXPECT_EQ(uid, std::get<1>(args.value()));
}
+void EventThreadTest::expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime) {
+ auto args = mOnExpectedPresentTimePostedRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ EXPECT_EQ(expectedPresentTime, std::get<0>(args.value()));
+}
+
void EventThreadTest::expectVsyncEventReceivedByConnection(
const char* name, ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount) {
@@ -410,6 +423,7 @@
onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
+ expectOnExpectedPresentTimePosted(456);
// EventThread is requesting one more callback due to VsyncRequest::SingleSuppressCallback
expectVSyncCallbackScheduleReceived(true);
@@ -562,16 +576,19 @@
onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
+ expectOnExpectedPresentTimePosted(456);
// A second event should go to the same places.
onVSyncEvent(456, 123, 0);
expectThrottleVsyncReceived(123, mConnectionUid);
expectVsyncEventReceivedByConnection(456, 2u);
+ expectOnExpectedPresentTimePosted(123);
// A third event should go to the same places.
onVSyncEvent(789, 777, 111);
expectThrottleVsyncReceived(777, mConnectionUid);
expectVsyncEventReceivedByConnection(789, 3u);
+ expectOnExpectedPresentTimePosted(777);
}
TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index 734fddb..01762c1 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -165,12 +165,8 @@
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
-
TestableSurfaceFlinger mFlinger;
-
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 9456e37..bc06a31 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -146,11 +146,8 @@
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
-
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index 22cfbd8..9fe9ee8 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -64,10 +64,8 @@
HI_FPS)),
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 13b47ff..3baa48d 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1237,4 +1237,25 @@
EXPECT_TRUE(foundInputLayer);
}
+TEST_F(LayerSnapshotTest, canOccludePresentation) {
+ setFlags(12, layer_state_t::eCanOccludePresentation, layer_state_t::eCanOccludePresentation);
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .displayChanges = false,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(getSnapshot(1)->inputInfo.canOccludePresentation, false);
+
+ // ensure we can set the property on the window info for layer and all its children
+ EXPECT_EQ(getSnapshot(12)->inputInfo.canOccludePresentation, true);
+ EXPECT_EQ(getSnapshot(121)->inputInfo.canOccludePresentation, true);
+ EXPECT_EQ(getSnapshot(1221)->inputInfo.canOccludePresentation, true);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 249ed40..f5661fc 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -41,6 +41,7 @@
return {};
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) {}
} gNoOpCompositor;
class TestableMessageQueue : public impl::MessageQueue {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 6986689..10c5848 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -95,10 +95,8 @@
kDisplay1Mode60->getId());
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler{mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback};
+ TestableScheduler* mScheduler = new TestableScheduler{mSelector, mFlinger, mSchedulerCallback};
surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder;
ConnectionHandle mConnectionHandle;
@@ -516,6 +514,7 @@
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
} compositor(*mScheduler);
mScheduler->doFrameSignal(compositor, VsyncId(42));
@@ -568,7 +567,7 @@
frameRate.getPeriodNsecs())}));
std::shared_ptr<VSyncPredictor> vrrTracker =
std::make_shared<VSyncPredictor>(kMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback);
+ kOutlierTolerancePercent);
std::shared_ptr<RefreshRateSelector> vrrSelectorPtr =
std::make_shared<RefreshRateSelector>(makeModes(kMode), kMode->getId());
TestableScheduler scheduler{std::make_unique<android::mock::VsyncController>(),
@@ -576,8 +575,7 @@
vrrSelectorPtr,
mFlinger.getFactory(),
mFlinger.getTimeStats(),
- mSchedulerCallback,
- mVsyncTrackerCallback};
+ mSchedulerCallback};
scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index 93c2829..19f8deb 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -17,11 +17,15 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
#include "DualDisplayTransactionTest.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+using namespace com::android::graphics::surfaceflinger;
+
namespace android {
namespace {
@@ -163,6 +167,7 @@
}
TEST_F(FoldableTest, requestVsyncOnPowerOn) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
.Times(1);
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
@@ -173,6 +178,7 @@
}
TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
// When the device boots, the inner display should be the pacesetter.
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
index 7206e29..91b9018 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
@@ -17,31 +17,81 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <gui/SurfaceComposerClient.h>
#include "DisplayTransactionTestHelpers.h"
namespace android {
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using android::hardware::graphics::composer::V2_1::Error;
class NotifyExpectedPresentTest : public DisplayTransactionTest {
public:
void SetUp() override {
- mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject();
- FakeHwcDisplayInjector(mDisplay->getPhysicalId(), hal::DisplayType::PHYSICAL, kIsPrimary)
+ const auto display = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject();
+ mPhysicalDisplayId = display->getPhysicalId();
+ FakeHwcDisplayInjector(mPhysicalDisplayId, hal::DisplayType::PHYSICAL, /*isPrimary=*/true)
.setPowerMode(hal::PowerMode::ON)
.inject(&mFlinger, mComposer);
+
+ ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
+ TimePoint::fromNs(0),
+ kFps60Hz));
+ mCompositor = std::make_unique<Compositor>(mPhysicalDisplayId, mFlinger);
}
protected:
- sp<DisplayDevice> mDisplay;
- static constexpr bool kIsPrimary = true;
- static constexpr hal::HWDisplayId HWC_DISPLAY_ID =
- FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
-};
+ struct Compositor final : ICompositor {
+ explicit Compositor(PhysicalDisplayId displayId, TestableSurfaceFlinger& surfaceFlinger)
+ : displayId(displayId), surfaceFlinger(surfaceFlinger) {}
-TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
- const auto physicDisplayId = mDisplay->getPhysicalId();
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId id) override {
+ surfaceFlinger.sendNotifyExpectedPresentHint(id);
+ }
+
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override {
+ return committed;
+ }
+
+ CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters& targeters) override {
+ pacesetterIds.composite = pacesetterId;
+ CompositeResultsPerDisplay results;
+
+ for (const auto& [id, targeter] : targeters) {
+ vsyncIds.composite.emplace_back(id, targeter->target().vsyncId());
+ surfaceFlinger.resetNotifyExpectedPresentHintState(pacesetterId);
+ results.try_emplace(id,
+ CompositeResult{.compositionCoverage =
+ CompositionCoverage::Hwc});
+ }
+
+ return results;
+ }
+
+ void sample() override {}
+ void configure() override {}
+
+ struct {
+ PhysicalDisplayId commit;
+ PhysicalDisplayId composite;
+ } pacesetterIds;
+
+ using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
+ struct {
+ VsyncIds commit;
+ VsyncIds composite;
+ } vsyncIds;
+
+ bool committed = true;
+ PhysicalDisplayId displayId;
+ TestableSurfaceFlinger& surfaceFlinger;
+ };
+
+ PhysicalDisplayId mPhysicalDisplayId;
+ std::unique_ptr<Compositor> mCompositor;
+ static constexpr hal::HWDisplayId kHwcDisplayId =
+ FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
static constexpr Fps kFps60Hz = 60_Hz;
static constexpr int32_t kFrameInterval5HzNs = static_cast<Fps>(5_Hz).getPeriodNsecs();
static constexpr int32_t kFrameInterval60HzNs = kFps60Hz.getPeriodNsecs();
@@ -49,89 +99,171 @@
static constexpr Period kVsyncPeriod =
Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs());
static constexpr Period kTimeoutNs = Period::fromNs(kFrameInterval5HzNs);
- static constexpr auto kLastExpectedPresentTimestamp = TimePoint::fromNs(0);
+};
- ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId,
- kLastExpectedPresentTimestamp,
- kFps60Hz));
-
- {
- // Very first ExpectedPresent after idle, no previous timestamp
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
- .WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime), kFps60Hz,
- kTimeoutNs);
- }
- {
- // Absent timeoutNs
+TEST_F(NotifyExpectedPresentTest, noNotifyExpectedPresentHintCall_absentTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
+ ASSERT_NO_FATAL_FAILURE(
+ mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
+ TimePoint::fromNs(expectedPresentTime),
+ kFps60Hz));
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ for (int i = 0; i < 5; i++) {
expectedPresentTime += 2 * kFrameInterval5HzNs;
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
/*timeoutOpt*/ std::nullopt);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
+}
+
+TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentHint_zeroTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
{
- // Timeout is 0
- expectedPresentTime += kFrameInterval60HzNs;
+ // Very first ExpectedPresent after idle, no previous timestamp.
EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime), kFps60Hz,
- Period::fromNs(0));
- }
- {
- // ExpectedPresent is after the timeoutNs
- expectedPresentTime += 2 * kFrameInterval5HzNs;
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
- .WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+
+ // Present frame
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Present happens and NotifyExpectedPresentHintStatus is start.
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ }
+ {
+ mCompositor->committed = false;
+ expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ Period::fromNs(0));
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Hint sent
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ {
+ expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ Period::fromNs(0));
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ // Hint is executed
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+}
+
+TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
+ {
+ // Very first ExpectedPresent after idle, no previous timestamp
+ mCompositor->committed = false;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ {
+ // ExpectedPresentTime is after the timeoutNs
+ mCompositor->committed = true;
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Present happens notifyExpectedPresentHintStatus is Start
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+
+ // Another expectedPresent after timeout
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
// ExpectedPresent has not changed
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
- // ExpectedPresent is after the last reported ExpectedPresent.
+ // ExpectedPresent is after the last reported ExpectedPresent and within timeout.
expectedPresentTime += kFrameInterval60HzNs;
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
// ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs,
// representing we changed our decision and want to present earlier than previously
// reported.
+ mCompositor->committed = false;
expectedPresentTime -= kFrameInterval120HzNs;
EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
- const auto physicDisplayId = mDisplay->getPhysicalId();
const auto now = systemTime();
auto expectedPresentTime = now;
static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs());
- ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId,
+ ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
TimePoint::fromNs(now),
Fps::fromValue(0)));
static constexpr int32_t kFrameIntervalNs120Hz = static_cast<Fps>(120_Hz).getPeriodNsecs();
@@ -147,7 +279,7 @@
struct FrameRateIntervalTestData {
int32_t frameIntervalNs;
- bool callExpectedPresent;
+ bool callNotifyExpectedPresentHint;
};
const std::vector<FrameRateIntervalTestData> frameIntervals = {
{kFrameIntervalNs60Hz, true}, {kFrameIntervalNs96Hz, true},
@@ -159,21 +291,35 @@
{kFrameIntervalNs20Hz, false}, {kFrameIntervalNs120Hz, true},
};
- for (const auto& [frameIntervalNs, callExpectedPresent] : frameIntervals) {
- {
- expectedPresentTime += frameIntervalNs;
- if (callExpectedPresent) {
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- frameIntervalNs))
- .WillOnce(Return(Error::NONE));
- } else {
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- }
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime),
- Fps::fromPeriodNsecs(frameIntervalNs),
- kTimeoutNs);
+ for (size_t i = 0; i < frameIntervals.size(); i++) {
+ const auto& [frameIntervalNs, callNotifyExpectedPresentHint] = frameIntervals[i];
+ expectedPresentTime += frameIntervalNs;
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime),
+ Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs);
+
+ if (callNotifyExpectedPresentHint) {
+ mCompositor->committed = false;
+ ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId))
+ << "Hint not scheduled for frameInterval " << frameIntervalNs << " at index "
+ << i;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
+ .WillOnce(Return(Error::NONE));
+ } else {
+ // Only lastExpectedPresentTime is updated
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime))
+ << "LastExpectedPresentTime for frameInterval " << frameIntervalNs
+ << "at index " << i << " did not match for frameInterval " << frameIntervalNs;
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ }
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+
+ if (callNotifyExpectedPresentHint) {
+ // Present resumes the calls to the notifyExpectedPresentHint.
+ mCompositor->committed = true;
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
}
}
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 15fe600..83e2f98 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -17,11 +17,15 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
#include "DisplayTransactionTestHelpers.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+using namespace com::android::graphics::surfaceflinger;
+
namespace android {
namespace {
@@ -453,6 +457,7 @@
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
}
@@ -461,6 +466,7 @@
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
}
@@ -473,6 +479,7 @@
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
}
@@ -481,10 +488,12 @@
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
}
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.cpp b/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
index e0b7366..7b92a5b 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
@@ -21,11 +21,10 @@
TestableScheduler::TestableScheduler(RefreshRateSelectorPtr selectorPtr,
TestableSurfaceFlinger& testableSurfaceFlinger,
- ISchedulerCallback& callback,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& callback)
: TestableScheduler(std::make_unique<android::mock::VsyncController>(),
std::make_shared<android::mock::VSyncTracker>(), std::move(selectorPtr),
testableSurfaceFlinger.getFactory(),
- testableSurfaceFlinger.getTimeStats(), callback, vsyncTrackerCallback) {}
+ testableSurfaceFlinger.getTimeStats(), callback) {}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 6213713..25a85df 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -41,18 +41,16 @@
class TestableScheduler : public Scheduler, private ICompositor {
public:
TestableScheduler(RefreshRateSelectorPtr selectorPtr,
- TestableSurfaceFlinger& testableSurfaceFlinger, ISchedulerCallback& callback,
- IVsyncTrackerCallback& vsyncTrackerCallback);
+ TestableSurfaceFlinger& testableSurfaceFlinger, ISchedulerCallback& callback);
TestableScheduler(std::unique_ptr<VsyncController> controller,
std::shared_ptr<VSyncTracker> tracker, RefreshRateSelectorPtr selectorPtr,
surfaceflinger::Factory& factory, TimeStats& timeStats,
- ISchedulerCallback& schedulerCallback,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& schedulerCallback)
: Scheduler(*this, schedulerCallback,
(FeatureFlags)Feature::kContentDetection |
Feature::kSmallDirtyContentDetection,
- factory, selectorPtr->getActiveMode().fps, timeStats, vsyncTrackerCallback) {
+ factory, selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
std::move(tracker));
@@ -210,6 +208,7 @@
return {};
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9ef0749..46a079c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -53,7 +53,6 @@
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
#include "mock/MockSchedulerCallback.h"
-#include "mock/MockVsyncTrackerCallback.h"
#include "mock/system/window/MockNativeWindow.h"
#include "Scheduler/VSyncTracker.h"
@@ -205,8 +204,6 @@
enum class SchedulerCallbackImpl { kNoOp, kMock };
- enum class VsyncTrackerCallbackImpl { kNoOp, kMock };
-
struct DefaultDisplayMode {
// The ID of the injected RefreshRateSelector and its default display mode.
PhysicalDisplayId displayId;
@@ -220,14 +217,13 @@
TimeStats& getTimeStats() { return *mFlinger->mTimeStats; }
- void setupScheduler(
- std::unique_ptr<scheduler::VsyncController> vsyncController,
- std::shared_ptr<scheduler::VSyncTracker> vsyncTracker,
- std::unique_ptr<EventThread> appEventThread, std::unique_ptr<EventThread> sfEventThread,
- DisplayModesVariant modesVariant,
- SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
- VsyncTrackerCallbackImpl vsyncTrackerCallbackImpl = VsyncTrackerCallbackImpl::kNoOp,
- bool useNiceMock = false) {
+ void setupScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
+ std::shared_ptr<scheduler::VSyncTracker> vsyncTracker,
+ std::unique_ptr<EventThread> appEventThread,
+ std::unique_ptr<EventThread> sfEventThread,
+ DisplayModesVariant modesVariant,
+ SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
+ bool useNiceMock = false) {
RefreshRateSelectorPtr selectorPtr = ftl::match(
modesVariant,
[](DefaultDisplayMode arg) {
@@ -245,12 +241,6 @@
? static_cast<ISchedulerCallback&>(mNoOpSchedulerCallback)
: static_cast<ISchedulerCallback&>(mSchedulerCallback);
- using VsyncTrackerCallback = scheduler::IVsyncTrackerCallback;
- VsyncTrackerCallback& vsyncTrackerCallback =
- vsyncTrackerCallbackImpl == VsyncTrackerCallbackImpl::kNoOp
- ? static_cast<VsyncTrackerCallback&>(mNoOpVsyncTrackerCallback)
- : static_cast<VsyncTrackerCallback&>(mVsyncTrackerCallback);
-
if (useNiceMock) {
mScheduler =
new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController),
@@ -258,14 +248,12 @@
std::move(selectorPtr),
mFactory,
*mFlinger->mTimeStats,
- schedulerCallback,
- vsyncTrackerCallback);
+ schedulerCallback);
} else {
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
std::move(vsyncTracker),
std::move(selectorPtr), mFactory,
- *mFlinger->mTimeStats, schedulerCallback,
- vsyncTrackerCallback);
+ *mFlinger->mTimeStats, schedulerCallback);
}
mScheduler->initVsync(*mTokenManager, 0ms);
@@ -307,8 +295,7 @@
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0));
setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread),
std::move(sfEventThread), DefaultDisplayMode{options.displayId},
- SchedulerCallbackImpl::kNoOp, VsyncTrackerCallbackImpl::kNoOp,
- options.useNiceMock);
+ SchedulerCallbackImpl::kNoOp, options.useNiceMock);
}
void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
@@ -698,6 +685,36 @@
frameInterval, timeoutOpt);
}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ mFlinger->sendNotifyExpectedPresentHint(displayId);
+ }
+
+ bool verifyHintIsScheduledOnPresent(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnPresent;
+ }
+
+ bool verifyHintIsSent(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Sent;
+ }
+
+ bool verifyHintStatusIsStart(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Start;
+ }
+
+ bool verifyHintStatusIsScheduledOnTx(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnTx;
+ }
+
+ bool verifyLastExpectedPresentTime(PhysicalDisplayId displayId, nsecs_t expectedPresentTime) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId)
+ .lastExpectedPresentTimestamp.ns() == expectedPresentTime;
+ }
+
void setNotifyExpectedPresentData(PhysicalDisplayId displayId,
TimePoint lastExpectedPresentTimestamp,
Fps lastFrameInterval) {
@@ -706,6 +723,11 @@
displayData.lastFrameInterval = lastFrameInterval;
}
+ void resetNotifyExpectedPresentHintState(PhysicalDisplayId displayId) {
+ mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus =
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Start;
+ }
+
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
// not report a leaked object, since the SurfaceFlinger instance may
@@ -1099,8 +1121,6 @@
sp<SurfaceFlinger> mFlinger;
scheduler::mock::SchedulerCallback mSchedulerCallback;
scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
- scheduler::mock::VsyncTrackerCallback mVsyncTrackerCallback;
- scheduler::mock::NoOpVsyncTrackerCallback mNoOpVsyncTrackerCallback;
std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
scheduler::TestableScheduler* mScheduler = nullptr;
Hwc2::mock::PowerAdvisor mPowerAdvisor;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index d952b70..b9f3d70 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -26,7 +26,6 @@
#include <common/test/FlagUtils.h>
#include "Scheduler/VSyncPredictor.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
-#include "mock/MockVsyncTrackerCallback.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -82,14 +81,13 @@
nsecs_t mNow = 0;
nsecs_t mPeriod = 1000;
ftl::NonNull<DisplayModePtr> mMode = displayMode(mPeriod);
- scheduler::mock::VsyncTrackerCallback mVsyncTrackerCallback;
static constexpr size_t kHistorySize = 10;
static constexpr size_t kMinimumSamplesForPrediction = 6;
static constexpr size_t kOutlierTolerancePercent = 25;
static constexpr nsecs_t mMaxRoundingError = 100;
VSyncPredictor tracker{mMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback};
+ kOutlierTolerancePercent};
};
TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
@@ -410,8 +408,7 @@
// See b/151146131
TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
const auto mode = displayMode(mPeriod);
- VSyncPredictor tracker{mode, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent,
- mVsyncTrackerCallback};
+ VSyncPredictor tracker{mode, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent};
std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
840923581635, 840940161584, 840956868096,
840973702473, 840990256277, 841007116851,
@@ -658,48 +655,6 @@
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
}
-TEST_F(VSyncPredictorTest, vsyncTrackerCallback) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
-
- const auto refreshRate = Fps::fromPeriodNsecs(mPeriod);
- NotifyExpectedPresentConfig notifyExpectedPresentConfig;
- notifyExpectedPresentConfig.timeoutNs = Period::fromNs(30).ns();
-
- hal::VrrConfig vrrConfig;
- vrrConfig.notifyExpectedPresentConfig = notifyExpectedPresentConfig;
- vrrConfig.minFrameIntervalNs = refreshRate.getPeriodNsecs();
-
- const int32_t kGroup = 0;
- const auto kResolution = ui::Size(1920, 1080);
- const auto mode =
- ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfig, kGroup,
- kResolution, DEFAULT_DISPLAY_ID));
-
- tracker.setDisplayModePtr(mode);
- auto last = mNow;
- for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_CALL(mVsyncTrackerCallback,
- onVsyncGenerated(TimePoint::fromNs(last + mPeriod), mode,
- FpsMatcher(refreshRate)))
- .Times(1);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
- mNow += mPeriod;
- last = mNow;
- tracker.addVsyncTimestamp(mNow);
- }
-
- tracker.setRenderRate(refreshRate / 2);
- {
- // out of render rate phase
- EXPECT_CALL(mVsyncTrackerCallback,
- onVsyncGenerated(TimePoint::fromNs(mNow + 3 * mPeriod), mode,
- FpsMatcher(refreshRate / 2)))
- .Times(1);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod),
- Eq(mNow + 3 * mPeriod));
- }
-}
-
TEST_F(VSyncPredictorTest, adjustsVrrTimeline) {
SET_FLAG_FOR_TEST(flags::vrr_config, true);
@@ -716,7 +671,7 @@
.build());
VSyncPredictor vrrTracker{kMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback};
+ kOutlierTolerancePercent};
vrrTracker.setRenderRate(minFrameRate);
vrrTracker.addVsyncTimestamp(0);
@@ -733,28 +688,6 @@
EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
}
-
-TEST_F(VSyncPredictorTest, absentVrrConfigNoVsyncTrackerCallback) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
- const auto refreshRate = Fps::fromPeriodNsecs(mPeriod);
- const std::optional<hal::VrrConfig> vrrConfigOpt = std::nullopt;
- constexpr int32_t kGroup = 0;
- constexpr auto kResolution = ui::Size(1920, 1080);
- const auto mode =
- ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfigOpt,
- kGroup, kResolution, DEFAULT_DISPLAY_ID));
- tracker.setDisplayModePtr(mode);
-
- auto last = mNow;
- for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_CALL(mVsyncTrackerCallback, onVsyncGenerated(_, _, _)).Times(0);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
- mNow += mPeriod;
- last = mNow;
- tracker.addVsyncTimestamp(mNow);
- }
-}
-
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 22b2ccc..4ca0542 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -28,6 +28,8 @@
MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override));
MOCK_METHOD(void, onChoreographerAttached, (), (override));
+ MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps),
+ (override));
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
@@ -36,6 +38,7 @@
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
void onChoreographerAttached() override {}
+ void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
};
} // namespace android::scheduler::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h
deleted file mode 100644
index b48529f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2023 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 <gmock/gmock.h>
-
-#include "Scheduler/VSyncTracker.h"
-
-namespace android::scheduler::mock {
-
-struct VsyncTrackerCallback final : IVsyncTrackerCallback {
- MOCK_METHOD(void, onVsyncGenerated, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps), (override));
-};
-
-struct NoOpVsyncTrackerCallback final : IVsyncTrackerCallback {
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override{};
-};
-} // namespace android::scheduler::mock