1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <map>
20*795d594fSAndroid Build Coastguard Worker #include <memory>
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include "base/leb128.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
25*795d594fSAndroid Build Coastguard Worker #include "jni.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace art {
28*795d594fSAndroid Build Coastguard Worker namespace {
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker static const int kMagicValue = 0x574f4c53;
31*795d594fSAndroid Build Coastguard Worker static const int kVersionDualClockStreaming = 0xf5;
32*795d594fSAndroid Build Coastguard Worker static const int kVersionDualClock = 0x05;
33*795d594fSAndroid Build Coastguard Worker static const int kThreadInfo = 0;
34*795d594fSAndroid Build Coastguard Worker static const int kMethodInfo = 1;
35*795d594fSAndroid Build Coastguard Worker static const int kTraceEntries = 2;
36*795d594fSAndroid Build Coastguard Worker static const int kTraceActionBits = 2;
37*795d594fSAndroid Build Coastguard Worker static const int kSummary = 3;
38*795d594fSAndroid Build Coastguard Worker static const int kMethodEntry = 0;
39*795d594fSAndroid Build Coastguard Worker static const int kMethodExitNormal = 1;
40*795d594fSAndroid Build Coastguard Worker static const int kMethodExitError = 2;
41*795d594fSAndroid Build Coastguard Worker
42*795d594fSAndroid Build Coastguard Worker // List of methods that could be triggered by a GC. It isn't possible to control
43*795d594fSAndroid Build Coastguard Worker // when GCs happen especially in gcstress configs. So we ignore certain methods
44*795d594fSAndroid Build Coastguard Worker // that could be executed based on when GC occurs.
45*795d594fSAndroid Build Coastguard Worker static const std::string_view ignored_methods_list[] = {
46*795d594fSAndroid Build Coastguard Worker "java.lang.ref.ReferenceQueue add (Ljava/lang/ref/Reference;)V ReferenceQueue.java"
47*795d594fSAndroid Build Coastguard Worker };
48*795d594fSAndroid Build Coastguard Worker
ReadNumber(int num_bytes,uint8_t * header)49*795d594fSAndroid Build Coastguard Worker uint64_t ReadNumber(int num_bytes, uint8_t* header) {
50*795d594fSAndroid Build Coastguard Worker uint64_t number = 0;
51*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < num_bytes; i++) {
52*795d594fSAndroid Build Coastguard Worker uint64_t c = header[i];
53*795d594fSAndroid Build Coastguard Worker number += c << (i * 8);
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker return number;
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker
ProcessThreadOrMethodInfo(std::unique_ptr<File> & file,std::map<uint64_t,std::string> & name_map,bool is_method)58*795d594fSAndroid Build Coastguard Worker bool ProcessThreadOrMethodInfo(std::unique_ptr<File>& file,
59*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string>& name_map,
60*795d594fSAndroid Build Coastguard Worker bool is_method) {
61*795d594fSAndroid Build Coastguard Worker uint8_t header[10];
62*795d594fSAndroid Build Coastguard Worker uint8_t header_length = is_method ? 10 : 6;
63*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(&header, header_length)) {
64*795d594fSAndroid Build Coastguard Worker printf("Couldn't read header\n");
65*795d594fSAndroid Build Coastguard Worker return false;
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker uint8_t num_bytes_for_id = is_method ? 8 : 4;
68*795d594fSAndroid Build Coastguard Worker uint64_t id = ReadNumber(num_bytes_for_id, header);
69*795d594fSAndroid Build Coastguard Worker int length = ReadNumber(2, header + num_bytes_for_id);
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker char* name = new char[length];
72*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(name, length)) {
73*795d594fSAndroid Build Coastguard Worker delete[] name;
74*795d594fSAndroid Build Coastguard Worker return false;
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker std::string str(name, length);
77*795d594fSAndroid Build Coastguard Worker std::replace(str.begin(), str.end(), '\t', ' ');
78*795d594fSAndroid Build Coastguard Worker if (str[str.length() - 1] == '\n') {
79*795d594fSAndroid Build Coastguard Worker str.erase(str.length() - 1);
80*795d594fSAndroid Build Coastguard Worker }
81*795d594fSAndroid Build Coastguard Worker name_map.emplace(id, str);
82*795d594fSAndroid Build Coastguard Worker delete[] name;
83*795d594fSAndroid Build Coastguard Worker return true;
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker
MethodInIgnoreList(const std::string & method_name)86*795d594fSAndroid Build Coastguard Worker bool MethodInIgnoreList(const std::string& method_name) {
87*795d594fSAndroid Build Coastguard Worker for (const std::string_view& ignored_method : ignored_methods_list) {
88*795d594fSAndroid Build Coastguard Worker if (method_name.compare(ignored_method) == 0) {
89*795d594fSAndroid Build Coastguard Worker return true;
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker return false;
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker
PrintTraceEntry(const std::string & thread_name,const std::string & method_name,int event_type,int * current_depth,std::string & ignored_method,int * ignored_method_depth)95*795d594fSAndroid Build Coastguard Worker void PrintTraceEntry(const std::string& thread_name,
96*795d594fSAndroid Build Coastguard Worker const std::string& method_name,
97*795d594fSAndroid Build Coastguard Worker int event_type,
98*795d594fSAndroid Build Coastguard Worker int* current_depth,
99*795d594fSAndroid Build Coastguard Worker std::string& ignored_method,
100*795d594fSAndroid Build Coastguard Worker int* ignored_method_depth) {
101*795d594fSAndroid Build Coastguard Worker bool ignore_trace_entry = false;
102*795d594fSAndroid Build Coastguard Worker if (ignored_method.empty()) {
103*795d594fSAndroid Build Coastguard Worker // Check if we need to ignore the method.
104*795d594fSAndroid Build Coastguard Worker if (MethodInIgnoreList(method_name)) {
105*795d594fSAndroid Build Coastguard Worker CHECK_EQ(event_type, kMethodEntry);
106*795d594fSAndroid Build Coastguard Worker ignored_method = method_name;
107*795d594fSAndroid Build Coastguard Worker *ignored_method_depth = *current_depth;
108*795d594fSAndroid Build Coastguard Worker ignore_trace_entry = true;
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker } else {
111*795d594fSAndroid Build Coastguard Worker // Check if the ignored method is exiting.
112*795d594fSAndroid Build Coastguard Worker if (MethodInIgnoreList(method_name) && *current_depth == *ignored_method_depth + 1) {
113*795d594fSAndroid Build Coastguard Worker CHECK_NE(event_type, kMethodEntry);
114*795d594fSAndroid Build Coastguard Worker ignored_method.clear();
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker ignore_trace_entry = true;
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker std::string entry;
119*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < *current_depth; i++) {
120*795d594fSAndroid Build Coastguard Worker entry.push_back('.');
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker if (event_type == kMethodEntry) {
123*795d594fSAndroid Build Coastguard Worker *current_depth += 1;
124*795d594fSAndroid Build Coastguard Worker entry.append(".>> ");
125*795d594fSAndroid Build Coastguard Worker } else if (event_type == kMethodExitNormal) {
126*795d594fSAndroid Build Coastguard Worker *current_depth -= 1;
127*795d594fSAndroid Build Coastguard Worker entry.append("<< ");
128*795d594fSAndroid Build Coastguard Worker } else if (event_type == kMethodExitError) {
129*795d594fSAndroid Build Coastguard Worker *current_depth -= 1;
130*795d594fSAndroid Build Coastguard Worker entry.append("<<E ");
131*795d594fSAndroid Build Coastguard Worker } else {
132*795d594fSAndroid Build Coastguard Worker entry.append("?? ");
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker entry.append(thread_name);
135*795d594fSAndroid Build Coastguard Worker entry.append(" ");
136*795d594fSAndroid Build Coastguard Worker entry.append(method_name);
137*795d594fSAndroid Build Coastguard Worker entry.append("\n");
138*795d594fSAndroid Build Coastguard Worker if (!ignore_trace_entry) {
139*795d594fSAndroid Build Coastguard Worker printf("%s", entry.c_str());
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker }
142*795d594fSAndroid Build Coastguard Worker
ProcessTraceEntries(std::unique_ptr<File> & file,std::map<int64_t,int> & current_depth_map,std::map<uint64_t,std::string> & thread_map,std::map<uint64_t,std::string> & method_map,bool is_dual_clock,const char * thread_name_filter,std::map<uint64_t,std::string> & ignored_method_map,std::map<int64_t,int> & ignored_method_depth_map)143*795d594fSAndroid Build Coastguard Worker bool ProcessTraceEntries(std::unique_ptr<File>& file,
144*795d594fSAndroid Build Coastguard Worker std::map<int64_t, int>& current_depth_map,
145*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string>& thread_map,
146*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string>& method_map,
147*795d594fSAndroid Build Coastguard Worker bool is_dual_clock,
148*795d594fSAndroid Build Coastguard Worker const char* thread_name_filter,
149*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string>& ignored_method_map,
150*795d594fSAndroid Build Coastguard Worker std::map<int64_t, int>& ignored_method_depth_map) {
151*795d594fSAndroid Build Coastguard Worker uint8_t header[11];
152*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(header, sizeof(header))) {
153*795d594fSAndroid Build Coastguard Worker return false;
154*795d594fSAndroid Build Coastguard Worker }
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker uint32_t thread_id = ReadNumber(4, header);
157*795d594fSAndroid Build Coastguard Worker int offset = 4;
158*795d594fSAndroid Build Coastguard Worker int num_records = ReadNumber(3, header + offset);
159*795d594fSAndroid Build Coastguard Worker offset += 3;
160*795d594fSAndroid Build Coastguard Worker int total_size = ReadNumber(4, header + offset);
161*795d594fSAndroid Build Coastguard Worker uint8_t* buffer = new uint8_t[total_size];
162*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(buffer, total_size)) {
163*795d594fSAndroid Build Coastguard Worker delete[] buffer;
164*795d594fSAndroid Build Coastguard Worker return false;
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker
167*795d594fSAndroid Build Coastguard Worker int current_depth = 0;
168*795d594fSAndroid Build Coastguard Worker if (current_depth_map.find(thread_id) != current_depth_map.end()) {
169*795d594fSAndroid Build Coastguard Worker // Get the current call stack depth. If it is the first method we are seeing on this thread
170*795d594fSAndroid Build Coastguard Worker // then this map wouldn't haven an entry we start with the depth of 0.
171*795d594fSAndroid Build Coastguard Worker current_depth = current_depth_map[thread_id];
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker
174*795d594fSAndroid Build Coastguard Worker int ignored_method_depth = 0;
175*795d594fSAndroid Build Coastguard Worker std::string ignored_method;
176*795d594fSAndroid Build Coastguard Worker if (ignored_method_map.find(thread_id) != ignored_method_map.end()) {
177*795d594fSAndroid Build Coastguard Worker ignored_method = ignored_method_map[thread_id];
178*795d594fSAndroid Build Coastguard Worker ignored_method_depth = ignored_method_depth_map[thread_id];
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker
181*795d594fSAndroid Build Coastguard Worker std::string thread_name = thread_map[thread_id];
182*795d594fSAndroid Build Coastguard Worker bool print_thread_events = (thread_name.compare(thread_name_filter) == 0);
183*795d594fSAndroid Build Coastguard Worker
184*795d594fSAndroid Build Coastguard Worker const uint8_t* current_buffer_ptr = buffer;
185*795d594fSAndroid Build Coastguard Worker int64_t prev_method_value = 0;
186*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < num_records; i++) {
187*795d594fSAndroid Build Coastguard Worker int64_t diff = 0;
188*795d594fSAndroid Build Coastguard Worker if (!DecodeSignedLeb128Checked(¤t_buffer_ptr, buffer + total_size - 1, &diff)) {
189*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Reading past the buffer???";
190*795d594fSAndroid Build Coastguard Worker }
191*795d594fSAndroid Build Coastguard Worker int64_t curr_method_value = prev_method_value + diff;
192*795d594fSAndroid Build Coastguard Worker prev_method_value = curr_method_value;
193*795d594fSAndroid Build Coastguard Worker uint8_t event_type = curr_method_value & 0x3;
194*795d594fSAndroid Build Coastguard Worker uint64_t method_id = (curr_method_value >> kTraceActionBits) << kTraceActionBits;
195*795d594fSAndroid Build Coastguard Worker if (method_map.find(method_id) == method_map.end()) {
196*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "No entry for method " << std::hex << method_id;
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker if (print_thread_events) {
199*795d594fSAndroid Build Coastguard Worker PrintTraceEntry(thread_name,
200*795d594fSAndroid Build Coastguard Worker method_map[method_id],
201*795d594fSAndroid Build Coastguard Worker event_type,
202*795d594fSAndroid Build Coastguard Worker ¤t_depth,
203*795d594fSAndroid Build Coastguard Worker ignored_method,
204*795d594fSAndroid Build Coastguard Worker &ignored_method_depth);
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker // Read timestamps
207*795d594fSAndroid Build Coastguard Worker DecodeUnsignedLeb128(¤t_buffer_ptr);
208*795d594fSAndroid Build Coastguard Worker if (is_dual_clock) {
209*795d594fSAndroid Build Coastguard Worker DecodeUnsignedLeb128(¤t_buffer_ptr);
210*795d594fSAndroid Build Coastguard Worker }
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker current_depth_map[thread_id] = current_depth;
213*795d594fSAndroid Build Coastguard Worker if (!ignored_method.empty()) {
214*795d594fSAndroid Build Coastguard Worker ignored_method_map[thread_id] = ignored_method;
215*795d594fSAndroid Build Coastguard Worker ignored_method_depth_map[thread_id] = ignored_method_depth;
216*795d594fSAndroid Build Coastguard Worker }
217*795d594fSAndroid Build Coastguard Worker return true;
218*795d594fSAndroid Build Coastguard Worker }
219*795d594fSAndroid Build Coastguard Worker
Java_Main_dumpTrace(JNIEnv * env,jclass,jstring fileName,jstring threadName)220*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_Main_dumpTrace(JNIEnv* env,
221*795d594fSAndroid Build Coastguard Worker jclass,
222*795d594fSAndroid Build Coastguard Worker jstring fileName,
223*795d594fSAndroid Build Coastguard Worker jstring threadName) {
224*795d594fSAndroid Build Coastguard Worker const char* file_name = env->GetStringUTFChars(fileName, nullptr);
225*795d594fSAndroid Build Coastguard Worker const char* thread_name = env->GetStringUTFChars(threadName, nullptr);
226*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string> thread_map;
227*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string> method_map;
228*795d594fSAndroid Build Coastguard Worker std::map<uint64_t, std::string> ignored_method_map;
229*795d594fSAndroid Build Coastguard Worker std::map<int64_t, int> current_depth_map;
230*795d594fSAndroid Build Coastguard Worker std::map<int64_t, int> ignored_method_depth_map;
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker std::unique_ptr<File> file(OS::OpenFileForReading(file_name));
233*795d594fSAndroid Build Coastguard Worker if (file == nullptr) {
234*795d594fSAndroid Build Coastguard Worker printf("Couldn't open file\n");
235*795d594fSAndroid Build Coastguard Worker return;
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker uint8_t header[32];
239*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(&header, sizeof(header))) {
240*795d594fSAndroid Build Coastguard Worker printf("Couldn't read header\n");
241*795d594fSAndroid Build Coastguard Worker return;
242*795d594fSAndroid Build Coastguard Worker }
243*795d594fSAndroid Build Coastguard Worker int magic_value = ReadNumber(4, header);
244*795d594fSAndroid Build Coastguard Worker if (magic_value != kMagicValue) {
245*795d594fSAndroid Build Coastguard Worker printf("Incorrect magic value got:%0x expected:%0x\n", magic_value, kMagicValue);
246*795d594fSAndroid Build Coastguard Worker return;
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker int version = ReadNumber(2, header + 4);
249*795d594fSAndroid Build Coastguard Worker printf("version=%0x\n", version);
250*795d594fSAndroid Build Coastguard Worker
251*795d594fSAndroid Build Coastguard Worker bool is_dual_clock = (version == kVersionDualClock) || (version == kVersionDualClockStreaming);
252*795d594fSAndroid Build Coastguard Worker bool has_entries = true;
253*795d594fSAndroid Build Coastguard Worker while (has_entries) {
254*795d594fSAndroid Build Coastguard Worker uint8_t entry_header;
255*795d594fSAndroid Build Coastguard Worker if (!file->ReadFully(&entry_header, sizeof(entry_header))) {
256*795d594fSAndroid Build Coastguard Worker break;
257*795d594fSAndroid Build Coastguard Worker }
258*795d594fSAndroid Build Coastguard Worker switch (entry_header) {
259*795d594fSAndroid Build Coastguard Worker case kThreadInfo:
260*795d594fSAndroid Build Coastguard Worker if (!ProcessThreadOrMethodInfo(file, thread_map, /*is_method=*/false)) {
261*795d594fSAndroid Build Coastguard Worker has_entries = false;
262*795d594fSAndroid Build Coastguard Worker }
263*795d594fSAndroid Build Coastguard Worker break;
264*795d594fSAndroid Build Coastguard Worker case kMethodInfo:
265*795d594fSAndroid Build Coastguard Worker if (!ProcessThreadOrMethodInfo(file, method_map, /*is_method=*/true)) {
266*795d594fSAndroid Build Coastguard Worker has_entries = false;
267*795d594fSAndroid Build Coastguard Worker }
268*795d594fSAndroid Build Coastguard Worker break;
269*795d594fSAndroid Build Coastguard Worker case kTraceEntries:
270*795d594fSAndroid Build Coastguard Worker ProcessTraceEntries(file,
271*795d594fSAndroid Build Coastguard Worker current_depth_map,
272*795d594fSAndroid Build Coastguard Worker thread_map,
273*795d594fSAndroid Build Coastguard Worker method_map,
274*795d594fSAndroid Build Coastguard Worker is_dual_clock,
275*795d594fSAndroid Build Coastguard Worker thread_name,
276*795d594fSAndroid Build Coastguard Worker ignored_method_map,
277*795d594fSAndroid Build Coastguard Worker ignored_method_depth_map);
278*795d594fSAndroid Build Coastguard Worker break;
279*795d594fSAndroid Build Coastguard Worker case kSummary:
280*795d594fSAndroid Build Coastguard Worker has_entries = false;
281*795d594fSAndroid Build Coastguard Worker break;
282*795d594fSAndroid Build Coastguard Worker default:
283*795d594fSAndroid Build Coastguard Worker printf("Invalid Header %d\n", entry_header);
284*795d594fSAndroid Build Coastguard Worker has_entries = false;
285*795d594fSAndroid Build Coastguard Worker break;
286*795d594fSAndroid Build Coastguard Worker }
287*795d594fSAndroid Build Coastguard Worker }
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(fileName, file_name);
290*795d594fSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(threadName, thread_name);
291*795d594fSAndroid Build Coastguard Worker }
292*795d594fSAndroid Build Coastguard Worker
293*795d594fSAndroid Build Coastguard Worker } // namespace
294*795d594fSAndroid Build Coastguard Worker } // namespace art
295