xref: /aosp_15_r20/external/perfetto/src/trace_processor/rpc/rpc.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2019 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 "src/trace_processor/rpc/rpc.h"
18 
19 #include <cinttypes>
20 #include <cstdint>
21 #include <cstdio>
22 #include <cstring>
23 #include <memory>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/status.h"
30 #include "perfetto/base/time.h"
31 #include "perfetto/ext/base/version.h"
32 #include "perfetto/ext/protozero/proto_ring_buffer.h"
33 #include "perfetto/ext/trace_processor/rpc/query_result_serializer.h"
34 #include "perfetto/protozero/field.h"
35 #include "perfetto/protozero/proto_utils.h"
36 #include "perfetto/protozero/scattered_heap_buffer.h"
37 #include "perfetto/trace_processor/basic_types.h"
38 #include "perfetto/trace_processor/metatrace_config.h"
39 #include "perfetto/trace_processor/trace_processor.h"
40 #include "src/trace_processor/tp_metatrace.h"
41 #include "src/trace_processor/util/status_macros.h"
42 
43 #include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
44 #include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
45 
46 namespace perfetto::trace_processor {
47 
48 namespace {
49 // Writes a "Loading trace ..." update every N bytes.
50 constexpr size_t kProgressUpdateBytes = 50ul * 1000 * 1000;
51 using TraceProcessorRpcStream = protos::pbzero::TraceProcessorRpcStream;
52 using RpcProto = protos::pbzero::TraceProcessorRpc;
53 
54 // Most RPC messages are either very small or a query results.
55 // QueryResultSerializer splits rows into batches of approximately 128KB. Try
56 // avoid extra heap allocations for the nominal case.
57 constexpr auto kSliceSize =
58     QueryResultSerializer::kDefaultBatchSplitThreshold + 4096;
59 
60 // Holds a trace_processor::TraceProcessorRpc pbzero message. Avoids extra
61 // copies by doing direct scattered calls from the fragmented heap buffer onto
62 // the RpcResponseFunction (the receiver is expected to deal with arbitrary
63 // fragmentation anyways). It also takes care of prefixing each message with
64 // the proto preamble and varint size.
65 class Response {
66  public:
67   Response(int64_t seq, int method);
68   Response(const Response&) = delete;
69   Response& operator=(const Response&) = delete;
operator ->()70   RpcProto* operator->() { return msg_; }
71   void Send(Rpc::RpcResponseFunction);
72 
73  private:
74   RpcProto* msg_ = nullptr;
75 
76   // The reason why we use TraceProcessorRpcStream as root message is because
77   // the RPC wire protocol expects each message to be prefixed with a proto
78   // preamble and varint size. This happens to be the same serialization of a
79   // repeated field (this is really the same trick we use between
80   // Trace and TracePacket in trace.proto)
81   protozero::HeapBuffered<TraceProcessorRpcStream> buf_;
82 };
83 
Response(int64_t seq,int method)84 Response::Response(int64_t seq, int method) : buf_(kSliceSize, kSliceSize) {
85   msg_ = buf_->add_msg();
86   msg_->set_seq(seq);
87   msg_->set_response(static_cast<RpcProto::TraceProcessorMethod>(method));
88 }
89 
Send(Rpc::RpcResponseFunction send_fn)90 void Response::Send(Rpc::RpcResponseFunction send_fn) {
91   buf_->Finalize();
92   for (const auto& slice : buf_.GetSlices()) {
93     auto range = slice.GetUsedRange();
94     send_fn(range.begin, static_cast<uint32_t>(range.size()));
95   }
96 }
97 
98 }  // namespace
99 
Rpc(std::unique_ptr<TraceProcessor> preloaded_instance)100 Rpc::Rpc(std::unique_ptr<TraceProcessor> preloaded_instance)
101     : trace_processor_(std::move(preloaded_instance)) {
102   if (!trace_processor_)
103     ResetTraceProcessorInternal(Config());
104 }
105 
Rpc()106 Rpc::Rpc() : Rpc(nullptr) {}
107 Rpc::~Rpc() = default;
108 
ResetTraceProcessorInternal(const Config & config)109 void Rpc::ResetTraceProcessorInternal(const Config& config) {
110   trace_processor_config_ = config;
111   trace_processor_ = TraceProcessor::CreateInstance(config);
112   bytes_parsed_ = bytes_last_progress_ = 0;
113   t_parse_started_ = base::GetWallTimeNs().count();
114   // Deliberately not resetting the RPC channel state (rxbuf_, {tx,rx}_seq_id_).
115   // This is invoked from the same client to clear the current trace state
116   // before loading a new one. The IPC channel is orthogonal to that and the
117   // message numbering continues regardless of the reset.
118 }
119 
OnRpcRequest(const void * data,size_t len)120 void Rpc::OnRpcRequest(const void* data, size_t len) {
121   rxbuf_.Append(data, len);
122   for (;;) {
123     auto msg = rxbuf_.ReadMessage();
124     if (!msg.valid()) {
125       if (msg.fatal_framing_error) {
126         protozero::HeapBuffered<TraceProcessorRpcStream> err_msg;
127         err_msg->add_msg()->set_fatal_error("RPC framing error");
128         auto err = err_msg.SerializeAsArray();
129         rpc_response_fn_(err.data(), static_cast<uint32_t>(err.size()));
130         rpc_response_fn_(nullptr, 0);  // Disconnect.
131       }
132       break;
133     }
134     ParseRpcRequest(msg.start, msg.len);
135   }
136 }
137 
138 namespace {
139 
140 using ProtoEnum = protos::pbzero::MetatraceCategories;
MetatraceCategoriesToPublicEnum(ProtoEnum categories)141 TraceProcessor::MetatraceCategories MetatraceCategoriesToPublicEnum(
142     ProtoEnum categories) {
143   TraceProcessor::MetatraceCategories result =
144       TraceProcessor::MetatraceCategories::NONE;
145   if (categories & ProtoEnum::QUERY_TIMELINE) {
146     result = static_cast<TraceProcessor::MetatraceCategories>(
147         result | TraceProcessor::MetatraceCategories::QUERY_TIMELINE);
148   }
149   if (categories & ProtoEnum::QUERY_DETAILED) {
150     result = static_cast<TraceProcessor::MetatraceCategories>(
151         result | TraceProcessor::MetatraceCategories::QUERY_DETAILED);
152   }
153   if (categories & ProtoEnum::FUNCTION_CALL) {
154     result = static_cast<TraceProcessor::MetatraceCategories>(
155         result | TraceProcessor::MetatraceCategories::FUNCTION_CALL);
156   }
157   if (categories & ProtoEnum::DB) {
158     result = static_cast<TraceProcessor::MetatraceCategories>(
159         result | TraceProcessor::MetatraceCategories::DB);
160   }
161   if (categories & ProtoEnum::API_TIMELINE) {
162     result = static_cast<TraceProcessor::MetatraceCategories>(
163         result | TraceProcessor::MetatraceCategories::API_TIMELINE);
164   }
165   return result;
166 }
167 
168 }  // namespace
169 
170 // [data, len] here is a tokenized TraceProcessorRpc proto message, without the
171 // size header.
ParseRpcRequest(const uint8_t * data,size_t len)172 void Rpc::ParseRpcRequest(const uint8_t* data, size_t len) {
173   RpcProto::Decoder req(data, len);
174 
175   // We allow restarting the sequence from 0. This happens when refreshing the
176   // browser while using the external trace_processor_shell --httpd.
177   if (req.seq() != 0 && rx_seq_id_ != 0 && req.seq() != rx_seq_id_ + 1) {
178     char err_str[255];
179     // "(ERR:rpc_seq)" is intercepted by error_dialog.ts in the UI.
180     snprintf(err_str, sizeof(err_str),
181              "RPC request out of order. Expected %" PRId64 ", got %" PRId64
182              " (ERR:rpc_seq)",
183              rx_seq_id_ + 1, req.seq());
184     PERFETTO_ELOG("%s", err_str);
185     protozero::HeapBuffered<TraceProcessorRpcStream> err_msg;
186     err_msg->add_msg()->set_fatal_error(err_str);
187     auto err = err_msg.SerializeAsArray();
188     rpc_response_fn_(err.data(), static_cast<uint32_t>(err.size()));
189     rpc_response_fn_(nullptr, 0);  // Disconnect.
190     return;
191   }
192   rx_seq_id_ = req.seq();
193 
194   // The static cast is to prevent that the compiler breaks future proofness.
195   const int req_type = static_cast<int>(req.request());
196   static const char kErrFieldNotSet[] = "RPC error: request field not set";
197   switch (req_type) {
198     case RpcProto::TPM_APPEND_TRACE_DATA: {
199       Response resp(tx_seq_id_++, req_type);
200       auto* result = resp->set_append_result();
201       if (!req.has_append_trace_data()) {
202         result->set_error(kErrFieldNotSet);
203       } else {
204         protozero::ConstBytes byte_range = req.append_trace_data();
205         base::Status res = Parse(byte_range.data, byte_range.size);
206         if (!res.ok()) {
207           result->set_error(res.message());
208         }
209       }
210       resp.Send(rpc_response_fn_);
211       break;
212     }
213     case RpcProto::TPM_FINALIZE_TRACE_DATA: {
214       Response resp(tx_seq_id_++, req_type);
215       auto* result = resp->set_finalize_data_result();
216       base::Status res = NotifyEndOfFile();
217       if (!res.ok()) {
218         result->set_error(res.message());
219       }
220       resp.Send(rpc_response_fn_);
221       break;
222     }
223     case RpcProto::TPM_QUERY_STREAMING: {
224       if (!req.has_query_args()) {
225         Response resp(tx_seq_id_++, req_type);
226         auto* result = resp->set_query_result();
227         result->set_error(kErrFieldNotSet);
228         resp.Send(rpc_response_fn_);
229       } else {
230         protozero::ConstBytes args = req.query_args();
231         protos::pbzero::QueryArgs::Decoder query(args.data, args.size);
232         std::string sql = query.sql_query().ToStdString();
233 
234         PERFETTO_TP_TRACE(metatrace::Category::API_TIMELINE, "RPC_QUERY",
235                           [&](metatrace::Record* r) {
236                             r->AddArg("SQL", sql);
237                             if (query.has_tag()) {
238                               r->AddArg("tag", query.tag());
239                             }
240                           });
241 
242         auto it = trace_processor_->ExecuteQuery(sql);
243         QueryResultSerializer serializer(std::move(it));
244         for (bool has_more = true; has_more;) {
245           const auto seq_id = tx_seq_id_++;
246           Response resp(seq_id, req_type);
247           has_more = serializer.Serialize(resp->set_query_result());
248           const uint32_t resp_size = resp->Finalize();
249           if (resp_size < protozero::proto_utils::kMaxMessageLength) {
250             // This is the nominal case.
251             resp.Send(rpc_response_fn_);
252             continue;
253           }
254           // In rare cases a query can end up with a batch which is too big.
255           // Normally batches are automatically split before hitting the limit,
256           // but one can come up with a query where a single cell is > 256MB.
257           // If this happens, just bail out gracefully rather than creating an
258           // unparsable proto which will cause a RPC framing error.
259           // If we hit this, we have to discard `resp` because it's
260           // unavoidably broken (due to have overflown the 4-bytes size) and
261           // can't be parsed. Instead create a new response with the error.
262           Response err_resp(seq_id, req_type);
263           auto* qres = err_resp->set_query_result();
264           qres->add_batch()->set_is_last_batch(true);
265           qres->set_error(
266               "The query ended up with a response that is too big (" +
267               std::to_string(resp_size) +
268               " bytes). This usually happens when a single row is >= 256 MiB. "
269               "See also WRITE_FILE for dealing with large rows.");
270           err_resp.Send(rpc_response_fn_);
271           break;
272         }
273       }
274       break;
275     }
276     case RpcProto::TPM_COMPUTE_METRIC: {
277       Response resp(tx_seq_id_++, req_type);
278       auto* result = resp->set_metric_result();
279       if (!req.has_compute_metric_args()) {
280         result->set_error(kErrFieldNotSet);
281       } else {
282         protozero::ConstBytes args = req.compute_metric_args();
283         ComputeMetricInternal(args.data, args.size, result);
284       }
285       resp.Send(rpc_response_fn_);
286       break;
287     }
288     case RpcProto::TPM_GET_METRIC_DESCRIPTORS: {
289       Response resp(tx_seq_id_++, req_type);
290       auto descriptor_set = trace_processor_->GetMetricDescriptors();
291       auto* result = resp->set_metric_descriptors();
292       result->AppendRawProtoBytes(descriptor_set.data(), descriptor_set.size());
293       resp.Send(rpc_response_fn_);
294       break;
295     }
296     case RpcProto::TPM_RESTORE_INITIAL_TABLES: {
297       trace_processor_->RestoreInitialTables();
298       Response resp(tx_seq_id_++, req_type);
299       resp.Send(rpc_response_fn_);
300       break;
301     }
302     case RpcProto::TPM_ENABLE_METATRACE: {
303       using protos::pbzero::MetatraceCategories;
304       protozero::ConstBytes args = req.enable_metatrace_args();
305       EnableMetatrace(args.data, args.size);
306 
307       Response resp(tx_seq_id_++, req_type);
308       resp.Send(rpc_response_fn_);
309       break;
310     }
311     case RpcProto::TPM_DISABLE_AND_READ_METATRACE: {
312       Response resp(tx_seq_id_++, req_type);
313       DisableAndReadMetatraceInternal(resp->set_metatrace());
314       resp.Send(rpc_response_fn_);
315       break;
316     }
317     case RpcProto::TPM_GET_STATUS: {
318       Response resp(tx_seq_id_++, req_type);
319       std::vector<uint8_t> status = GetStatus();
320       resp->set_status()->AppendRawProtoBytes(status.data(), status.size());
321       resp.Send(rpc_response_fn_);
322       break;
323     }
324     case RpcProto::TPM_RESET_TRACE_PROCESSOR: {
325       Response resp(tx_seq_id_++, req_type);
326       protozero::ConstBytes args = req.reset_trace_processor_args();
327       ResetTraceProcessor(args.data, args.size);
328       resp.Send(rpc_response_fn_);
329       break;
330     }
331     case RpcProto::TPM_REGISTER_SQL_PACKAGE: {
332       Response resp(tx_seq_id_++, req_type);
333       base::Status status = RegisterSqlPackage(req.register_sql_package_args());
334       auto* res = resp->set_register_sql_package_result();
335       if (!status.ok()) {
336         res->set_error(status.message());
337       }
338       resp.Send(rpc_response_fn_);
339       break;
340     }
341     default: {
342       // This can legitimately happen if the client is newer. We reply with a
343       // generic "unkown request" response, so the client can do feature
344       // detection
345       PERFETTO_DLOG("[RPC] Uknown request type (%d), size=%zu", req_type, len);
346       Response resp(tx_seq_id_++, req_type);
347       resp->set_invalid_request(
348           static_cast<RpcProto::TraceProcessorMethod>(req_type));
349       resp.Send(rpc_response_fn_);
350       break;
351     }
352   }  // switch(req_type)
353 }
354 
Parse(const uint8_t * data,size_t len)355 base::Status Rpc::Parse(const uint8_t* data, size_t len) {
356   PERFETTO_TP_TRACE(
357       metatrace::Category::API_TIMELINE, "RPC_PARSE",
358       [&](metatrace::Record* r) { r->AddArg("length", std::to_string(len)); });
359   if (eof_) {
360     // Reset the trace processor state if another trace has been previously
361     // loaded. Use the same TraceProcessor Config.
362     ResetTraceProcessorInternal(trace_processor_config_);
363   }
364 
365   eof_ = false;
366   bytes_parsed_ += len;
367   MaybePrintProgress();
368 
369   if (len == 0)
370     return base::OkStatus();
371 
372   // TraceProcessor needs take ownership of the memory chunk.
373   std::unique_ptr<uint8_t[]> data_copy(new uint8_t[len]);
374   memcpy(data_copy.get(), data, len);
375   return trace_processor_->Parse(std::move(data_copy), len);
376 }
377 
NotifyEndOfFile()378 base::Status Rpc::NotifyEndOfFile() {
379   PERFETTO_TP_TRACE(metatrace::Category::API_TIMELINE,
380                     "RPC_NOTIFY_END_OF_FILE");
381 
382   eof_ = true;
383   RETURN_IF_ERROR(trace_processor_->NotifyEndOfFile());
384   MaybePrintProgress();
385   return base::OkStatus();
386 }
387 
ResetTraceProcessor(const uint8_t * args,size_t len)388 void Rpc::ResetTraceProcessor(const uint8_t* args, size_t len) {
389   protos::pbzero::ResetTraceProcessorArgs::Decoder reset_trace_processor_args(
390       args, len);
391   Config config;
392   if (reset_trace_processor_args.has_drop_track_event_data_before()) {
393     config.drop_track_event_data_before =
394         reset_trace_processor_args.drop_track_event_data_before() ==
395                 protos::pbzero::ResetTraceProcessorArgs::
396                     TRACK_EVENT_RANGE_OF_INTEREST
397             ? DropTrackEventDataBefore::kTrackEventRangeOfInterest
398             : DropTrackEventDataBefore::kNoDrop;
399   }
400   if (reset_trace_processor_args.has_ingest_ftrace_in_raw_table()) {
401     config.ingest_ftrace_in_raw_table =
402         reset_trace_processor_args.ingest_ftrace_in_raw_table();
403   }
404   if (reset_trace_processor_args.has_analyze_trace_proto_content()) {
405     config.analyze_trace_proto_content =
406         reset_trace_processor_args.analyze_trace_proto_content();
407   }
408   if (reset_trace_processor_args.has_ftrace_drop_until_all_cpus_valid()) {
409     config.soft_drop_ftrace_data_before =
410         reset_trace_processor_args.ftrace_drop_until_all_cpus_valid()
411             ? SoftDropFtraceDataBefore::kAllPerCpuBuffersValid
412             : SoftDropFtraceDataBefore::kNoDrop;
413   }
414   using Args = protos::pbzero::ResetTraceProcessorArgs;
415   switch (reset_trace_processor_args.parsing_mode()) {
416     case Args::ParsingMode::DEFAULT:
417       config.parsing_mode = ParsingMode::kDefault;
418       break;
419     case Args::ParsingMode::TOKENIZE_ONLY:
420       config.parsing_mode = ParsingMode::kTokenizeOnly;
421       break;
422     case Args::ParsingMode::TOKENIZE_AND_SORT:
423       config.parsing_mode = ParsingMode::kTokenizeAndSort;
424       break;
425   }
426   ResetTraceProcessorInternal(config);
427 }
428 
RegisterSqlPackage(protozero::ConstBytes bytes)429 base::Status Rpc::RegisterSqlPackage(protozero::ConstBytes bytes) {
430   protos::pbzero::RegisterSqlPackageArgs::Decoder args(bytes);
431   SqlPackage package;
432   package.name = args.package_name().ToStdString();
433   package.allow_override = args.allow_override();
434   for (auto it = args.modules(); it; ++it) {
435     protos::pbzero::RegisterSqlPackageArgs::Module::Decoder m(*it);
436     package.modules.emplace_back(m.name().ToStdString(), m.sql().ToStdString());
437   }
438   return trace_processor_->RegisterSqlPackage(package);
439 }
440 
MaybePrintProgress()441 void Rpc::MaybePrintProgress() {
442   if (eof_ || bytes_parsed_ - bytes_last_progress_ > kProgressUpdateBytes) {
443     bytes_last_progress_ = bytes_parsed_;
444     auto t_load_s =
445         static_cast<double>(base::GetWallTimeNs().count() - t_parse_started_) /
446         1e9;
447     fprintf(stderr, "\rLoading trace %.2f MB (%.1f MB/s)%s",
448             static_cast<double>(bytes_parsed_) / 1e6,
449             static_cast<double>(bytes_parsed_) / 1e6 / t_load_s,
450             (eof_ ? "\n" : ""));
451     fflush(stderr);
452   }
453 }
454 
Query(const uint8_t * args,size_t len,const QueryResultBatchCallback & result_callback)455 void Rpc::Query(const uint8_t* args,
456                 size_t len,
457                 const QueryResultBatchCallback& result_callback) {
458   protos::pbzero::QueryArgs::Decoder query(args, len);
459   std::string sql = query.sql_query().ToStdString();
460   PERFETTO_TP_TRACE(metatrace::Category::API_TIMELINE, "RPC_QUERY",
461                     [&](metatrace::Record* r) {
462                       r->AddArg("SQL", sql);
463                       if (query.has_tag()) {
464                         r->AddArg("tag", query.tag());
465                       }
466                     });
467 
468   auto it = trace_processor_->ExecuteQuery(sql);
469 
470   QueryResultSerializer serializer(std::move(it));
471 
472   std::vector<uint8_t> res;
473   for (bool has_more = true; has_more;) {
474     has_more = serializer.Serialize(&res);
475     result_callback(res.data(), res.size(), has_more);
476     res.clear();
477   }
478 }
479 
RestoreInitialTables()480 void Rpc::RestoreInitialTables() {
481   trace_processor_->RestoreInitialTables();
482 }
483 
ComputeMetric(const uint8_t * args,size_t len)484 std::vector<uint8_t> Rpc::ComputeMetric(const uint8_t* args, size_t len) {
485   protozero::HeapBuffered<protos::pbzero::ComputeMetricResult> result;
486   ComputeMetricInternal(args, len, result.get());
487   return result.SerializeAsArray();
488 }
489 
ComputeMetricInternal(const uint8_t * data,size_t len,protos::pbzero::ComputeMetricResult * result)490 void Rpc::ComputeMetricInternal(const uint8_t* data,
491                                 size_t len,
492                                 protos::pbzero::ComputeMetricResult* result) {
493   protos::pbzero::ComputeMetricArgs::Decoder args(data, len);
494   std::vector<std::string> metric_names;
495   for (auto it = args.metric_names(); it; ++it) {
496     metric_names.emplace_back(it->as_std_string());
497   }
498 
499   PERFETTO_TP_TRACE(metatrace::Category::API_TIMELINE, "RPC_COMPUTE_METRIC",
500                     [&](metatrace::Record* r) {
501                       for (const auto& metric : metric_names) {
502                         r->AddArg("Metric", metric);
503                         r->AddArg("Format", std::to_string(args.format()));
504                       }
505                     });
506 
507   PERFETTO_DLOG("[RPC] ComputeMetrics(%zu, %s), format=%d", metric_names.size(),
508                 metric_names.empty() ? "" : metric_names.front().c_str(),
509                 args.format());
510   switch (args.format()) {
511     case protos::pbzero::ComputeMetricArgs::BINARY_PROTOBUF: {
512       std::vector<uint8_t> metrics_proto;
513       base::Status status =
514           trace_processor_->ComputeMetric(metric_names, &metrics_proto);
515       if (status.ok()) {
516         result->set_metrics(metrics_proto.data(), metrics_proto.size());
517       } else {
518         result->set_error(status.message());
519       }
520       break;
521     }
522     case protos::pbzero::ComputeMetricArgs::TEXTPROTO: {
523       std::string metrics_string;
524       base::Status status = trace_processor_->ComputeMetricText(
525           metric_names, TraceProcessor::MetricResultFormat::kProtoText,
526           &metrics_string);
527       if (status.ok()) {
528         result->set_metrics_as_prototext(metrics_string);
529       } else {
530         result->set_error(status.message());
531       }
532       break;
533     }
534     case protos::pbzero::ComputeMetricArgs::JSON: {
535       std::string metrics_string;
536       base::Status status = trace_processor_->ComputeMetricText(
537           metric_names, TraceProcessor::MetricResultFormat::kJson,
538           &metrics_string);
539       if (status.ok()) {
540         result->set_metrics_as_json(metrics_string);
541       } else {
542         result->set_error(status.message());
543       }
544       break;
545     }
546   }
547 }
548 
EnableMetatrace(const uint8_t * data,size_t len)549 void Rpc::EnableMetatrace(const uint8_t* data, size_t len) {
550   using protos::pbzero::MetatraceCategories;
551   TraceProcessor::MetatraceConfig config;
552   protos::pbzero::EnableMetatraceArgs::Decoder args(data, len);
553   config.categories = MetatraceCategoriesToPublicEnum(
554       static_cast<MetatraceCategories>(args.categories()));
555   trace_processor_->EnableMetatrace(config);
556 }
557 
DisableAndReadMetatrace()558 std::vector<uint8_t> Rpc::DisableAndReadMetatrace() {
559   protozero::HeapBuffered<protos::pbzero::DisableAndReadMetatraceResult> result;
560   DisableAndReadMetatraceInternal(result.get());
561   return result.SerializeAsArray();
562 }
563 
DisableAndReadMetatraceInternal(protos::pbzero::DisableAndReadMetatraceResult * result)564 void Rpc::DisableAndReadMetatraceInternal(
565     protos::pbzero::DisableAndReadMetatraceResult* result) {
566   std::vector<uint8_t> trace_proto;
567   base::Status status = trace_processor_->DisableAndReadMetatrace(&trace_proto);
568   if (status.ok()) {
569     result->set_metatrace(trace_proto.data(), trace_proto.size());
570   } else {
571     result->set_error(status.message());
572   }
573 }
574 
GetStatus()575 std::vector<uint8_t> Rpc::GetStatus() {
576   protozero::HeapBuffered<protos::pbzero::StatusResult> status;
577   status->set_loaded_trace_name(trace_processor_->GetCurrentTraceName());
578   status->set_human_readable_version(base::GetVersionString());
579   if (const char* version_code = base::GetVersionCode(); version_code) {
580     status->set_version_code(version_code);
581   }
582   status->set_api_version(protos::pbzero::TRACE_PROCESSOR_CURRENT_API_VERSION);
583   return status.SerializeAsArray();
584 }
585 
586 }  // namespace perfetto::trace_processor
587