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 eraseListenerAndAckMessages(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 eraseListenerAndAckMessages(who);
67 }});
68 }
69
eraseListenerAndAckMessages(const wp<IBinder> & binder)70 void WindowInfosListenerInvoker::eraseListenerAndAckMessages(const wp<IBinder>& binder) {
71 auto it = mWindowInfosListeners.find(binder);
72 int64_t listenerId = it->second.first;
73 mWindowInfosListeners.erase(binder);
74
75 std::vector<int64_t> vsyncIds;
76 for (auto& [vsyncId, state] : mUnackedState) {
77 if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(),
78 listenerId) != state.unackedListenerIds.end()) {
79 vsyncIds.push_back(vsyncId);
80 }
81 }
82
83 for (int64_t vsyncId : vsyncIds) {
84 ackWindowInfosReceived(vsyncId, listenerId);
85 }
86 }
87
windowInfosChanged(gui::WindowInfosUpdate update,WindowInfosReportedListenerSet reportedListeners,bool forceImmediateCall)88 void WindowInfosListenerInvoker::windowInfosChanged(
89 gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners,
90 bool forceImmediateCall) {
91 if (!mDelayInfo) {
92 mDelayInfo = DelayInfo{
93 .vsyncId = update.vsyncId,
94 .frameTime = update.timestamp,
95 };
96 }
97
98 // If there are unacked messages and this isn't a forced call, then return immediately.
99 // If a forced window infos change doesn't happen first, the update will be sent after
100 // the WindowInfosReportedListeners are called. If a forced window infos change happens or
101 // if there are subsequent delayed messages before this update is sent, then this message
102 // will be dropped and the listeners will only be called with the latest info. This is done
103 // to reduce the amount of binder memory used.
104 if (!mUnackedState.empty() && !forceImmediateCall) {
105 mDelayedUpdate = std::move(update);
106 mReportedListeners.merge(reportedListeners);
107 return;
108 }
109
110 if (mDelayedUpdate) {
111 mDelayedUpdate.reset();
112 }
113
114 if (CC_UNLIKELY(mWindowInfosListeners.empty())) {
115 mReportedListeners.merge(reportedListeners);
116 mDelayInfo.reset();
117 return;
118 }
119
120 reportedListeners.merge(mReportedListeners);
121 mReportedListeners.clear();
122
123 // Update mUnackedState to include the message we're about to send
124 auto [it, _] = mUnackedState.try_emplace(update.vsyncId,
125 UnackedState{.reportedListeners =
126 std::move(reportedListeners)});
127 auto& unackedState = it->second;
128 for (auto& pair : mWindowInfosListeners) {
129 int64_t listenerId = pair.second.first;
130 unackedState.unackedListenerIds.push_back(listenerId);
131 }
132
133 mDelayInfo.reset();
134 updateMaxSendDelay();
135
136 // Call the listeners
137 for (auto& pair : mWindowInfosListeners) {
138 auto& [listenerId, listener] = pair.second;
139 auto status = listener->onWindowInfosChanged(update);
140 if (!status.isOk()) {
141 ackWindowInfosReceived(update.vsyncId, listenerId);
142 }
143 }
144 }
145
getDebugInfo()146 WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() {
147 DebugInfo result;
148 BackgroundExecutor::getInstance().sendCallbacks({[&, this]() {
149 ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo");
150 updateMaxSendDelay();
151 result = mDebugInfo;
152 result.pendingMessageCount = mUnackedState.size();
153 }});
154 BackgroundExecutor::getInstance().flushQueue();
155 return result;
156 }
157
updateMaxSendDelay()158 void WindowInfosListenerInvoker::updateMaxSendDelay() {
159 if (!mDelayInfo) {
160 return;
161 }
162 nsecs_t delay = TimePoint::now().ns() - mDelayInfo->frameTime;
163 if (delay > mDebugInfo.maxSendDelayDuration) {
164 mDebugInfo.maxSendDelayDuration = delay;
165 mDebugInfo.maxSendDelayVsyncId = VsyncId{mDelayInfo->vsyncId};
166 }
167 }
168
ackWindowInfosReceived(int64_t vsyncId,int64_t listenerId)169 binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId,
170 int64_t listenerId) {
171 BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() {
172 ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived");
173 auto it = mUnackedState.find(vsyncId);
174 if (it == mUnackedState.end()) {
175 return;
176 }
177
178 auto& state = it->second;
179 state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(),
180 state.unackedListenerIds.end(),
181 listenerId));
182 if (!state.unackedListenerIds.empty()) {
183 return;
184 }
185
186 WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)};
187 mUnackedState.erase(vsyncId);
188
189 for (const auto& reportedListener : reportedListeners) {
190 sp<IBinder> asBinder = IInterface::asBinder(reportedListener);
191 if (asBinder->isBinderAlive()) {
192 reportedListener->onWindowInfosReported();
193 }
194 }
195
196 if (!mDelayedUpdate || !mUnackedState.empty()) {
197 return;
198 }
199 gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)};
200 mDelayedUpdate.reset();
201 windowInfosChanged(std::move(update), {}, false);
202 }});
203 return binder::Status::ok();
204 }
205
206 } // namespace android
207