• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2025 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 // #define LOG_NDEBUG 0
18 #undef LOG_TAG
19 #define LOG_TAG "DependencyMonitor"
20 
21 #include <ui/DependencyMonitor.h>
22 #include <ui/Fence.h>
23 #include <utils/Timers.h>
24 
25 #include <inttypes.h>
26 
27 namespace android {
28 
addIngress(FenceTimePtr fence,std::string annotation)29 void DependencyMonitor::addIngress(FenceTimePtr fence, std::string annotation) {
30     std::lock_guard lock(mMutex);
31     resolveLocked();
32     if (mDependencies.isFull() && !mDependencies.front().updateSignalTimes(true)) {
33         ALOGD("%s: Clobbering unresolved dependencies -- make me bigger!", mToken.c_str());
34     }
35 
36     auto& entry = mDependencies.next();
37     entry.reset(mToken.c_str());
38     ALOGV("%" PRId64 "/%s: addIngress at CPU time %" PRId64 " (%s)", mDependencies.back().id,
39           mToken.c_str(), systemTime(), annotation.c_str());
40 
41     mDependencies.back().ingress = {std::move(fence), std::move(annotation)};
42 }
43 
addAccessCompletion(FenceTimePtr fence,std::string annotation)44 void DependencyMonitor::addAccessCompletion(FenceTimePtr fence, std::string annotation) {
45     std::lock_guard lock(mMutex);
46     if (mDependencies.size() == 0) {
47         return;
48     }
49     ALOGV("%" PRId64 "/%s: addAccessCompletion at CPU time %" PRId64 " (%s)",
50           mDependencies.back().id, mToken.c_str(), systemTime(), annotation.c_str());
51     mDependencies.back().accessCompletions.emplace_back(std::move(fence), std::move(annotation));
52 }
53 
addEgress(FenceTimePtr fence,std::string annotation)54 void DependencyMonitor::addEgress(FenceTimePtr fence, std::string annotation) {
55     std::lock_guard lock(mMutex);
56     if (mDependencies.size() == 0) {
57         return;
58     }
59     ALOGV("%" PRId64 "/%s: addEgress at CPU time %" PRId64 " (%s)", mDependencies.back().id,
60           mToken.c_str(), systemTime(), annotation.c_str());
61     mDependencies.back().egress = {std::move(fence), std::move(annotation)};
62 }
63 
resolveLocked()64 void DependencyMonitor::resolveLocked() {
65     if (mDependencies.size() == 0) {
66         return;
67     }
68 
69     for (size_t i = mDependencies.size(); i > 0; i--) {
70         auto& dependencyBlock = mDependencies[i - 1];
71 
72         if (dependencyBlock.validated) {
73             continue;
74         }
75 
76         if (!dependencyBlock.updateSignalTimes(false)) {
77             break;
78         }
79 
80         dependencyBlock.validated = true;
81         dependencyBlock.checkUnsafeAccess();
82     }
83 }
84 
updateSignalTimes(bool excludeIngress)85 bool DependencyMonitor::DependencyBlock::updateSignalTimes(bool excludeIngress) {
86     if (egress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
87         return false;
88     }
89 
90     if (!excludeIngress && ingress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
91         return false;
92     }
93 
94     for (auto& accessCompletion : accessCompletions) {
95         if (accessCompletion.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
96             return false;
97         }
98     }
99 
100     return true;
101 }
102 
checkUnsafeAccess() const103 void DependencyMonitor::DependencyBlock::checkUnsafeAccess() const {
104     const nsecs_t egressTime = egress.fence->getCachedSignalTime();
105     const nsecs_t ingressTime = ingress.fence->getCachedSignalTime();
106 
107     ALOGV_IF(egressTime != Fence::SIGNAL_TIME_INVALID,
108              "%" PRId64 "/%s: Egress time: %" PRId64 " (%s)", token, id, egressTime,
109              egress.annotation.c_str());
110     ALOGV_IF(Fence::isValidTimestamp(egressTime) && Fence::isValidTimestamp(ingressTime) &&
111                      egressTime < ingressTime,
112              "%" PRId64 "/%s: Detected egress before ingress!: %" PRId64 " (%s) < %" PRId64 " (%s)",
113              id, token, egressTime, egress.annotation, ingressTime, ingress.annotation.c_str());
114 
115     for (auto& accessCompletion : accessCompletions) {
116         const nsecs_t accessCompletionTime = accessCompletion.fence->getCachedSignalTime();
117         if (!Fence::isValidTimestamp(accessCompletionTime)) {
118             ALOGI("%" PRId64 "/%s: Detected invalid access completion! <%s>", id, token,
119                   accessCompletion.annotation.c_str());
120             continue;
121         } else {
122             ALOGV("%" PRId64 "/%s: Access completion time: %" PRId64 " <%s>", id, token,
123                   accessCompletionTime, accessCompletion.annotation.c_str());
124         }
125 
126         ALOGI_IF(Fence::isValidTimestamp(egressTime) && accessCompletionTime > egressTime,
127                  "%" PRId64 "/%s: Detected access completion after egress!: %" PRId64
128                  " (%s) > %" PRId64 " (%s)",
129                  id, token, accessCompletionTime, accessCompletion.annotation.c_str(), egressTime,
130                  egress.annotation.c_str());
131 
132         ALOGI_IF(Fence::isValidTimestamp(ingressTime) && accessCompletionTime < ingressTime,
133                  "%" PRId64 "/%s: Detected access completion prior to ingress!: %" PRId64
134                  " (%s) < %" PRId64 " (%s)",
135                  id, token, accessCompletionTime, accessCompletion.annotation.c_str(), ingressTime,
136                  ingress.annotation.c_str());
137     }
138 
139     ALOGV_IF(ingressTime != Fence::SIGNAL_TIME_INVALID,
140              "%" PRId64 "/%s: Ingress time: %" PRId64 " (%s)", id, token, ingressTime,
141              ingress.annotation.c_str());
142 }
143 
144 } // namespace android