MCPcopy Create free account
hub / github.com/Snapchat/Valdi / onANR

Method onANR

valdi/src/valdi/runtime/JavaScript/JavaScriptANRDetector.cpp:131–199  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

129 _tickInterval = tickInterval;
130}
131
132void JavaScriptANRDetector::onNextTick(DispatchFunction nextTickCallback) {
133 std::lock_guard<Mutex> lock(_mutex);
134 _nextTickCallbacks.emplace_back(std::move(nextTickCallback));
135}
136
137void JavaScriptANRDetector::scheduleNextTick() {
138 if (_nextTickTask != 0 || !_started || !_isInForeground) {
139 return;
140 }
141 _nextTickTask = _dispatchQueue->asyncAfter(
142 [self = Valdi::weakRef(this)]() {
143 auto strongSelf = self.lock();
144 if (strongSelf != nullptr) {
145 strongSelf->checkForANRs();
146 }
147 },
148 _tickInterval);
149}
150
151bool JavaScriptANRDetector::onANR(JavaScriptTaskScheduler& taskScheduler,
152 std::chrono::steady_clock::duration detectionThreshold,
153 const std::atomic<bool>& ack) {
154 // Read the native-side attribution before waiting on the stack capture. The capture can take up
155 // to kCaptureStacktraceTimeoutSeconds, and a native call or module load that finishes during
156 // that wait clears its name, which would report the stall as unattributed. Both getters read
157 // saved native state, not JS, so they are safe to call while the JS thread is stuck.
158 auto loadingModule = taskScheduler.getCurrentlyLoadingModule();
159 auto attributionInfo = taskScheduler.getANRAttributionInfo();
160 auto stacktraces = taskScheduler.captureStackTraces(std::chrono::seconds(kCaptureStacktraceTimeoutSeconds));
161 StringBox moduleName;
162 std::string message;
163
164 if (!stacktraces.empty() && stacktraces[0].getContext() != nullptr) {
165 moduleName = stacktraces[0].getContext()->getPath().getResourceId().bundleName;
166 }
167
168 // Module loads run under the global context (no bundle name) and expose no JS stack while the
169 // bundle is being parsed, so a load that holds the JS thread past the threshold would
170 // otherwise be reported unattributed. Attribute it to the bundle being loaded instead.
171 bool isLoadingModule = false;
172 if (moduleName.isEmpty()) {
173 moduleName = loadingModule;
174 isLoadingModule = !moduleName.isEmpty();
175 }
176
177 if (!hasRunningStacktrace(stacktraces) && ack.load()) {
178 // The ack was submitted while waiting to capture stacktraces.
179 // We consider that task scheduler has recovered
180 return true;
181 }
182
183 auto detectionThresholdString =
184 snap::utils::time::Duration<std::chrono::steady_clock>(detectionThreshold).toString();
185 if (moduleName.isEmpty()) {
186 message = fmt::format("Detected unattributed ANR after {}", detectionThresholdString);
187 } else if (isLoadingModule) {
188 message =

Callers

nothing calls this directly

Calls 14

hasRunningStacktraceFunction · 0.85
JavaScriptANRClass · 0.85
getStatusMethod · 0.80
emitANRMethod · 0.80
withAttributionMethod · 0.80
loadMethod · 0.65
toStringMethod · 0.65
getStackTraceMethod · 0.65
captureStackTracesMethod · 0.45
emptyMethod · 0.45
getContextMethod · 0.45
getPathMethod · 0.45

Tested by

no test coverage detected