1 /*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android/gui/BnWindowInfosPublisher.h>
18 #include <android/gui/IWindowInfosPublisher.h>
19 #include <android/gui/WindowInfosListenerInfo.h>
20 #include <gui/ISurfaceComposer.h>
21 #include <gui/TraceUtils.h>
22 #include <gui/WindowInfosUpdate.h>
23 #include <scheduler/Time.h>
24
25 #include "BackgroundExecutor.h"
26 #include "WindowInfosListenerInvoker.h"
27
28 #undef ATRACE_TAG
29 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
30
31 namespace android {
32
33 using gui::DisplayInfo;
34 using gui::IWindowInfosListener;
35 using gui::WindowInfo;
36
addWindowInfosListener(sp<IWindowInfosListener> listener,gui::WindowInfosListenerInfo * outInfo)37 void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener,
38 gui::WindowInfosListenerInfo* outInfo) {
39 int64_t listenerId = mNextListenerId++;
40 outInfo->listenerId = listenerId;
41 outInfo->windowInfosPublisher = sp<gui::IWindowInfosPublisher>::fromExisting(this);
42
43 BackgroundExecutor::getInstance().sendCallbacks(
44 {[this, listener = std::move(listener), listenerId]() {
45 ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener");
46 sp<IBinder> asBinder = IInterface::asBinder(listener);
47 asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
48 mWindowInfosListeners.try_emplace(asBinder,
49 std::make_pair(listenerId, std::move(listener)));
50 }});
51 }
52
removeWindowInfosListener(const sp<IWindowInfosListener> & listener)53 void WindowInfosListenerInvoker::removeWindowInfosListener(
54 const sp<IWindowInfosListener>& listener) {
55 BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() {
56 ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener");
57 sp<IBinder> asBinder = IInterface::asBinder(listener);
58 asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
59 mWindowInfosListeners.erase(asBinder);
60 }});
61 }
62
binderDied(const wp<IBinder> & who)63 void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
64 BackgroundExecutor::getInstance().sendCallbacks({[this, who]() {
65 ATRACE_NAME("WindowInfosListenerInvoker::binderDied");
66 auto it = mWindowInfosListeners.find(who);
67 int64_t listenerId = it->second.first;
68 mWindowInfosListeners.erase(who);
69
70 std::vector<int64_t> vsyncIds;
71 for (auto& [vsyncId, state] : mUnackedState) {
72 if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(),
73 listenerId) != state.unackedListenerIds.end()) {
74 vsyncIds.push_back(vsyncId);
75 }
76 }
77
78 for (int64_t vsyncId : vsyncIds) {
79 ackWindowInfosReceived(vsyncId, listenerId);
80 }
81 }});
82 }
83
windowInfosChanged(gui::WindowInfosUpdate update,WindowInfosReportedListenerSet reportedListeners,bool forceImmediateCall)84 void WindowInfosListenerInvoker::windowInfosChanged(
85 gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners,
86 bool forceImmediateCall) {
87 if (!mDelayInfo) {
88 mDelayInfo = DelayInfo{
89 .vsyncId = update.vsyncId,
90 .frameTime = update.timestamp,
91 };
92 }
93
94 // If there are unacked messages and this isn't a forced call, then return immediately.
95 // If a forced window infos change doesn't happen first, the update will be sent after
96 // the WindowInfosReportedListeners are called. If a forced window infos change happens or
97 // if there are subsequent delayed messages before this update is sent, then this message
98 // will be dropped and the listeners will only be called with the latest info. This is done
99 // to reduce the amount of binder memory used.
100 if (!mUnackedState.empty() && !forceImmediateCall) {
101 mDelayedUpdate = std::move(update);
102 mReportedListeners.merge(reportedListeners);
103 return;
104 }
105
106 if (mDelayedUpdate) {
107 mDelayedUpdate.reset();
108 }
109
110 if (CC_UNLIKELY(mWindowInfosListeners.empty())) {
111 mReportedListeners.merge(reportedListeners);
112 mDelayInfo.reset();
113 return;
114 }
115
116 reportedListeners.merge(mReportedListeners);
117 mReportedListeners.clear();
118
119 // Update mUnackedState to include the message we're about to send
120 auto [it, _] = mUnackedState.try_emplace(update.vsyncId,
121 UnackedState{.reportedListeners =
122 std::move(reportedListeners)});
123 auto& unackedState = it->second;
124 for (auto& pair : mWindowInfosListeners) {
125 int64_t listenerId = pair.second.first;
126 unackedState.unackedListenerIds.push_back(listenerId);
127 }
128
129 mDelayInfo.reset();
130 updateMaxSendDelay();
131
132 // Call the listeners
133 for (auto& pair : mWindowInfosListeners) {
134 auto& [listenerId, listener] = pair.second;
135 auto status = listener->onWindowInfosChanged(update);
136 if (!status.isOk()) {
137 ackWindowInfosReceived(update.vsyncId, listenerId);
138 }
139 }
140 }
141
getDebugInfo()142 WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() {
143 DebugInfo result;
144 BackgroundExecutor::getInstance().sendCallbacks({[&, this]() {
145 ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo");
146 updateMaxSendDelay();
147 result = mDebugInfo;
148 result.pendingMessageCount = mUnackedState.size();
149 }});
150 BackgroundExecutor::getInstance().flushQueue();
151 return result;
152 }
153
updateMaxSendDelay()154 void WindowInfosListenerInvoker::updateMaxSendDelay() {
155 if (!mDelayInfo) {
156 return;
157 }
158 nsecs_t delay = TimePoint::now().ns() - mDelayInfo->frameTime;
159 if (delay > mDebugInfo.maxSendDelayDuration) {
160 mDebugInfo.maxSendDelayDuration = delay;
161 mDebugInfo.maxSendDelayVsyncId = VsyncId{mDelayInfo->vsyncId};
162 }
163 }
164
ackWindowInfosReceived(int64_t vsyncId,int64_t listenerId)165 binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId,
166 int64_t listenerId) {
167 BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() {
168 ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived");
169 auto it = mUnackedState.find(vsyncId);
170 if (it == mUnackedState.end()) {
171 return;
172 }
173
174 auto& state = it->second;
175 state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(),
176 state.unackedListenerIds.end(),
177 listenerId));
178 if (!state.unackedListenerIds.empty()) {
179 return;
180 }
181
182 WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)};
183 mUnackedState.erase(vsyncId);
184
185 for (const auto& reportedListener : reportedListeners) {
186 sp<IBinder> asBinder = IInterface::asBinder(reportedListener);
187 if (asBinder->isBinderAlive()) {
188 reportedListener->onWindowInfosReported();
189 }
190 }
191
192 if (!mDelayedUpdate || !mUnackedState.empty()) {
193 return;
194 }
195 gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)};
196 mDelayedUpdate.reset();
197 windowInfosChanged(std::move(update), {}, false);
198 }});
199 return binder::Status::ok();
200 }
201
202 } // namespace android
203