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