xref: /aosp_15_r20/art/runtime/metrics/reporter.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2021 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 "reporter.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <android-base/parseint.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include <algorithm>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "base/flags.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
25*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file_manager.h"
26*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
27*795d594fSAndroid Build Coastguard Worker #include "runtime_options.h"
28*795d594fSAndroid Build Coastguard Worker #include "statsd.h"
29*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic push
32*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic error "-Wconversion"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker namespace metrics {
36*795d594fSAndroid Build Coastguard Worker 
Create(const ReportingConfig & config,Runtime * runtime)37*795d594fSAndroid Build Coastguard Worker std::unique_ptr<MetricsReporter> MetricsReporter::Create(
38*795d594fSAndroid Build Coastguard Worker     const ReportingConfig& config, Runtime* runtime) {
39*795d594fSAndroid Build Coastguard Worker   // We can't use std::make_unique here because the MetricsReporter constructor is private.
40*795d594fSAndroid Build Coastguard Worker   return std::unique_ptr<MetricsReporter>{new MetricsReporter{std::move(config), runtime}};
41*795d594fSAndroid Build Coastguard Worker }
42*795d594fSAndroid Build Coastguard Worker 
MetricsReporter(const ReportingConfig & config,Runtime * runtime)43*795d594fSAndroid Build Coastguard Worker MetricsReporter::MetricsReporter(const ReportingConfig& config, Runtime* runtime)
44*795d594fSAndroid Build Coastguard Worker     : config_{config},
45*795d594fSAndroid Build Coastguard Worker       runtime_{runtime},
46*795d594fSAndroid Build Coastguard Worker       startup_reported_{false},
47*795d594fSAndroid Build Coastguard Worker       report_interval_index_{0} {}
48*795d594fSAndroid Build Coastguard Worker 
~MetricsReporter()49*795d594fSAndroid Build Coastguard Worker MetricsReporter::~MetricsReporter() { MaybeStopBackgroundThread(); }
50*795d594fSAndroid Build Coastguard Worker 
ReloadConfig(const ReportingConfig & config)51*795d594fSAndroid Build Coastguard Worker void MetricsReporter::ReloadConfig(const ReportingConfig& config) {
52*795d594fSAndroid Build Coastguard Worker   DCHECK(!thread_.has_value()) << "The config cannot be reloaded after the background "
53*795d594fSAndroid Build Coastguard Worker                                   "reporting thread is started.";
54*795d594fSAndroid Build Coastguard Worker   config_ = config;
55*795d594fSAndroid Build Coastguard Worker }
56*795d594fSAndroid Build Coastguard Worker 
IsMetricsReportingEnabled(const SessionData & session_data) const57*795d594fSAndroid Build Coastguard Worker bool MetricsReporter::IsMetricsReportingEnabled(const SessionData& session_data) const {
58*795d594fSAndroid Build Coastguard Worker   return session_data.session_id % config_.reporting_num_mods < config_.reporting_mods;
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker 
MaybeStartBackgroundThread(SessionData session_data)61*795d594fSAndroid Build Coastguard Worker bool MetricsReporter::MaybeStartBackgroundThread(SessionData session_data) {
62*795d594fSAndroid Build Coastguard Worker   CHECK(!thread_.has_value());
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker   session_data_ = session_data;
65*795d594fSAndroid Build Coastguard Worker   LOG_STREAM(DEBUG) << "Received session metadata: " << session_data_.session_id;
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker   if (!IsMetricsReportingEnabled(session_data_)) {
68*795d594fSAndroid Build Coastguard Worker     return false;
69*795d594fSAndroid Build Coastguard Worker   }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker   thread_.emplace(&MetricsReporter::BackgroundThreadRun, this);
72*795d594fSAndroid Build Coastguard Worker   return true;
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker 
MaybeStopBackgroundThread()75*795d594fSAndroid Build Coastguard Worker void MetricsReporter::MaybeStopBackgroundThread() {
76*795d594fSAndroid Build Coastguard Worker   if (thread_.has_value()) {
77*795d594fSAndroid Build Coastguard Worker     messages_.SendMessage(ShutdownRequestedMessage{});
78*795d594fSAndroid Build Coastguard Worker     thread_->join();
79*795d594fSAndroid Build Coastguard Worker     thread_.reset();
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
NotifyStartupCompleted()83*795d594fSAndroid Build Coastguard Worker void MetricsReporter::NotifyStartupCompleted() {
84*795d594fSAndroid Build Coastguard Worker   if (ShouldReportAtStartup() && thread_.has_value()) {
85*795d594fSAndroid Build Coastguard Worker     messages_.SendMessage(StartupCompletedMessage{});
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker 
NotifyAppInfoUpdated(AppInfo * app_info)89*795d594fSAndroid Build Coastguard Worker void MetricsReporter::NotifyAppInfoUpdated(AppInfo* app_info) {
90*795d594fSAndroid Build Coastguard Worker   std::string compilation_reason;
91*795d594fSAndroid Build Coastguard Worker   std::string compiler_filter;
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker   app_info->GetPrimaryApkOptimizationStatus(
94*795d594fSAndroid Build Coastguard Worker       &compiler_filter, &compilation_reason);
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   SetCompilationInfo(
97*795d594fSAndroid Build Coastguard Worker       CompilationReasonFromName(compilation_reason),
98*795d594fSAndroid Build Coastguard Worker       CompilerFilterReportingFromName(compiler_filter));
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker 
RequestMetricsReport(bool synchronous)101*795d594fSAndroid Build Coastguard Worker void MetricsReporter::RequestMetricsReport(bool synchronous) {
102*795d594fSAndroid Build Coastguard Worker   if (thread_.has_value()) {
103*795d594fSAndroid Build Coastguard Worker     messages_.SendMessage(RequestMetricsReportMessage{synchronous});
104*795d594fSAndroid Build Coastguard Worker     if (synchronous) {
105*795d594fSAndroid Build Coastguard Worker       thread_to_host_messages_.ReceiveMessage();
106*795d594fSAndroid Build Coastguard Worker     }
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
SetCompilationInfo(CompilationReason compilation_reason,CompilerFilterReporting compiler_filter)110*795d594fSAndroid Build Coastguard Worker void MetricsReporter::SetCompilationInfo(CompilationReason compilation_reason,
111*795d594fSAndroid Build Coastguard Worker                                          CompilerFilterReporting compiler_filter) {
112*795d594fSAndroid Build Coastguard Worker   if (thread_.has_value()) {
113*795d594fSAndroid Build Coastguard Worker     messages_.SendMessage(CompilationInfoMessage{compilation_reason, compiler_filter});
114*795d594fSAndroid Build Coastguard Worker   }
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker 
BackgroundThreadRun()117*795d594fSAndroid Build Coastguard Worker void MetricsReporter::BackgroundThreadRun() {
118*795d594fSAndroid Build Coastguard Worker   LOG_STREAM(DEBUG) << "Metrics reporting thread started";
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker   // AttachCurrentThread is needed so we can safely use the ART concurrency primitives within the
121*795d594fSAndroid Build Coastguard Worker   // messages_ MessageQueue.
122*795d594fSAndroid Build Coastguard Worker   const bool attached = runtime_->AttachCurrentThread(kBackgroundThreadName,
123*795d594fSAndroid Build Coastguard Worker                                                       /*as_daemon=*/true,
124*795d594fSAndroid Build Coastguard Worker                                                       runtime_->GetSystemThreadGroup(),
125*795d594fSAndroid Build Coastguard Worker                                                       /*create_peer=*/true);
126*795d594fSAndroid Build Coastguard Worker   bool running = true;
127*795d594fSAndroid Build Coastguard Worker 
128*795d594fSAndroid Build Coastguard Worker   // Configure the backends
129*795d594fSAndroid Build Coastguard Worker   if (config_.dump_to_logcat) {
130*795d594fSAndroid Build Coastguard Worker     backends_.emplace_back(new LogBackend(std::make_unique<TextFormatter>(), LogSeverity::INFO));
131*795d594fSAndroid Build Coastguard Worker   }
132*795d594fSAndroid Build Coastguard Worker   if (config_.dump_to_file.has_value()) {
133*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<MetricsFormatter> formatter;
134*795d594fSAndroid Build Coastguard Worker     if (config_.metrics_format == "xml") {
135*795d594fSAndroid Build Coastguard Worker       formatter = std::make_unique<XmlFormatter>();
136*795d594fSAndroid Build Coastguard Worker     } else {
137*795d594fSAndroid Build Coastguard Worker       formatter = std::make_unique<TextFormatter>();
138*795d594fSAndroid Build Coastguard Worker     }
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker     backends_.emplace_back(new FileBackend(std::move(formatter), config_.dump_to_file.value()));
141*795d594fSAndroid Build Coastguard Worker   }
142*795d594fSAndroid Build Coastguard Worker   if (config_.dump_to_statsd) {
143*795d594fSAndroid Build Coastguard Worker     auto backend = CreateStatsdBackend();
144*795d594fSAndroid Build Coastguard Worker     if (backend != nullptr) {
145*795d594fSAndroid Build Coastguard Worker       backends_.emplace_back(std::move(backend));
146*795d594fSAndroid Build Coastguard Worker     }
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker   MaybeResetTimeout();
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker   while (running) {
152*795d594fSAndroid Build Coastguard Worker     messages_.SwitchReceive(
153*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] ShutdownRequestedMessage message) {
154*795d594fSAndroid Build Coastguard Worker           LOG_STREAM(DEBUG) << "Shutdown request received " << session_data_.session_id;
155*795d594fSAndroid Build Coastguard Worker           running = false;
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker           ReportMetrics();
158*795d594fSAndroid Build Coastguard Worker         },
159*795d594fSAndroid Build Coastguard Worker         [&](RequestMetricsReportMessage message) {
160*795d594fSAndroid Build Coastguard Worker           LOG_STREAM(DEBUG) << "Explicit report request received " << session_data_.session_id;
161*795d594fSAndroid Build Coastguard Worker           ReportMetrics();
162*795d594fSAndroid Build Coastguard Worker           if (message.synchronous) {
163*795d594fSAndroid Build Coastguard Worker             thread_to_host_messages_.SendMessage(ReportCompletedMessage{});
164*795d594fSAndroid Build Coastguard Worker           }
165*795d594fSAndroid Build Coastguard Worker         },
166*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] TimeoutExpiredMessage message) {
167*795d594fSAndroid Build Coastguard Worker           LOG_STREAM(DEBUG) << "Timer expired, reporting metrics " << session_data_.session_id;
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker           ReportMetrics();
170*795d594fSAndroid Build Coastguard Worker           MaybeResetTimeout();
171*795d594fSAndroid Build Coastguard Worker         },
172*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] StartupCompletedMessage message) {
173*795d594fSAndroid Build Coastguard Worker           LOG_STREAM(DEBUG) << "App startup completed, reporting metrics "
174*795d594fSAndroid Build Coastguard Worker               << session_data_.session_id;
175*795d594fSAndroid Build Coastguard Worker           ReportMetrics();
176*795d594fSAndroid Build Coastguard Worker           startup_reported_ = true;
177*795d594fSAndroid Build Coastguard Worker           MaybeResetTimeout();
178*795d594fSAndroid Build Coastguard Worker         },
179*795d594fSAndroid Build Coastguard Worker         [&](CompilationInfoMessage message) {
180*795d594fSAndroid Build Coastguard Worker           LOG_STREAM(DEBUG) << "Compilation info received " << session_data_.session_id;
181*795d594fSAndroid Build Coastguard Worker           session_data_.compilation_reason = message.compilation_reason;
182*795d594fSAndroid Build Coastguard Worker           session_data_.compiler_filter = message.compiler_filter;
183*795d594fSAndroid Build Coastguard Worker 
184*795d594fSAndroid Build Coastguard Worker           UpdateSessionInBackends();
185*795d594fSAndroid Build Coastguard Worker         });
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker 
188*795d594fSAndroid Build Coastguard Worker   if (attached) {
189*795d594fSAndroid Build Coastguard Worker     runtime_->DetachCurrentThread();
190*795d594fSAndroid Build Coastguard Worker   }
191*795d594fSAndroid Build Coastguard Worker   LOG_STREAM(DEBUG) << "Metrics reporting thread terminating " << session_data_.session_id;
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker 
MaybeResetTimeout()194*795d594fSAndroid Build Coastguard Worker void MetricsReporter::MaybeResetTimeout() {
195*795d594fSAndroid Build Coastguard Worker   if (ShouldContinueReporting()) {
196*795d594fSAndroid Build Coastguard Worker     messages_.SetTimeout(SecondsToMs(GetNextPeriodSeconds()));
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker }
199*795d594fSAndroid Build Coastguard Worker 
GetMetrics()200*795d594fSAndroid Build Coastguard Worker ArtMetrics* MetricsReporter::GetMetrics() { return runtime_->GetMetrics(); }
201*795d594fSAndroid Build Coastguard Worker 
ReportMetrics()202*795d594fSAndroid Build Coastguard Worker void MetricsReporter::ReportMetrics() {
203*795d594fSAndroid Build Coastguard Worker   ArtMetrics* metrics = GetMetrics();
204*795d594fSAndroid Build Coastguard Worker 
205*795d594fSAndroid Build Coastguard Worker   if (!session_started_) {
206*795d594fSAndroid Build Coastguard Worker     for (auto& backend : backends_) {
207*795d594fSAndroid Build Coastguard Worker       backend->BeginOrUpdateSession(session_data_);
208*795d594fSAndroid Build Coastguard Worker     }
209*795d594fSAndroid Build Coastguard Worker     session_started_ = true;
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker 
212*795d594fSAndroid Build Coastguard Worker   metrics->ReportAllMetricsAndResetValueMetrics(MakeNonOwningPointerVector(backends_));
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker 
UpdateSessionInBackends()215*795d594fSAndroid Build Coastguard Worker void MetricsReporter::UpdateSessionInBackends() {
216*795d594fSAndroid Build Coastguard Worker   if (session_started_) {
217*795d594fSAndroid Build Coastguard Worker     for (auto& backend : backends_) {
218*795d594fSAndroid Build Coastguard Worker       backend->BeginOrUpdateSession(session_data_);
219*795d594fSAndroid Build Coastguard Worker     }
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker 
ShouldReportAtStartup() const223*795d594fSAndroid Build Coastguard Worker bool MetricsReporter::ShouldReportAtStartup() const {
224*795d594fSAndroid Build Coastguard Worker   return IsMetricsReportingEnabled(session_data_) &&
225*795d594fSAndroid Build Coastguard Worker       config_.period_spec.has_value() &&
226*795d594fSAndroid Build Coastguard Worker       config_.period_spec->report_startup_first;
227*795d594fSAndroid Build Coastguard Worker }
228*795d594fSAndroid Build Coastguard Worker 
ShouldContinueReporting() const229*795d594fSAndroid Build Coastguard Worker bool MetricsReporter::ShouldContinueReporting() const {
230*795d594fSAndroid Build Coastguard Worker   bool result =
231*795d594fSAndroid Build Coastguard Worker       // Only if the reporting is enabled
232*795d594fSAndroid Build Coastguard Worker       IsMetricsReportingEnabled(session_data_) &&
233*795d594fSAndroid Build Coastguard Worker       // and if we have period spec
234*795d594fSAndroid Build Coastguard Worker       config_.period_spec.has_value() &&
235*795d594fSAndroid Build Coastguard Worker       // and the periods are non empty
236*795d594fSAndroid Build Coastguard Worker       !config_.period_spec->periods_seconds.empty() &&
237*795d594fSAndroid Build Coastguard Worker       // and we already reported startup or not required to report startup
238*795d594fSAndroid Build Coastguard Worker       (startup_reported_ || !config_.period_spec->report_startup_first) &&
239*795d594fSAndroid Build Coastguard Worker       // and we still have unreported intervals or we are asked to report continuously.
240*795d594fSAndroid Build Coastguard Worker       (config_.period_spec->continuous_reporting ||
241*795d594fSAndroid Build Coastguard Worker               (report_interval_index_ < config_.period_spec->periods_seconds.size()));
242*795d594fSAndroid Build Coastguard Worker   return result;
243*795d594fSAndroid Build Coastguard Worker }
244*795d594fSAndroid Build Coastguard Worker 
GetNextPeriodSeconds()245*795d594fSAndroid Build Coastguard Worker uint32_t MetricsReporter::GetNextPeriodSeconds() {
246*795d594fSAndroid Build Coastguard Worker   DCHECK(ShouldContinueReporting());
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker   // The index is either the current report_interval_index or the last index
249*795d594fSAndroid Build Coastguard Worker   // if we are in continuous mode and reached the end.
250*795d594fSAndroid Build Coastguard Worker   uint32_t index = std::min(
251*795d594fSAndroid Build Coastguard Worker       report_interval_index_,
252*795d594fSAndroid Build Coastguard Worker       static_cast<uint32_t>(config_.period_spec->periods_seconds.size() - 1));
253*795d594fSAndroid Build Coastguard Worker 
254*795d594fSAndroid Build Coastguard Worker   uint32_t result = config_.period_spec->periods_seconds[index];
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker   // Advance the index if we didn't get to the end.
257*795d594fSAndroid Build Coastguard Worker   if (report_interval_index_ < config_.period_spec->periods_seconds.size()) {
258*795d594fSAndroid Build Coastguard Worker     report_interval_index_++;
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker   return result;
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker 
FromFlags(bool is_system_server)263*795d594fSAndroid Build Coastguard Worker ReportingConfig ReportingConfig::FromFlags(bool is_system_server) {
264*795d594fSAndroid Build Coastguard Worker   std::optional<std::string> spec_str = is_system_server
265*795d594fSAndroid Build Coastguard Worker       ? gFlags.MetricsReportingSpecSystemServer.GetValueOptional()
266*795d594fSAndroid Build Coastguard Worker       : gFlags.MetricsReportingSpec.GetValueOptional();
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker   std::optional<ReportingPeriodSpec> period_spec = std::nullopt;
269*795d594fSAndroid Build Coastguard Worker 
270*795d594fSAndroid Build Coastguard Worker   if (spec_str.has_value()) {
271*795d594fSAndroid Build Coastguard Worker     std::string error;
272*795d594fSAndroid Build Coastguard Worker     period_spec = ReportingPeriodSpec::Parse(spec_str.value(), &error);
273*795d594fSAndroid Build Coastguard Worker     if (!period_spec.has_value()) {
274*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to create metrics reporting spec from: " << spec_str.value()
275*795d594fSAndroid Build Coastguard Worker           << " with error: " << error;
276*795d594fSAndroid Build Coastguard Worker     }
277*795d594fSAndroid Build Coastguard Worker   }
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker   uint32_t reporting_num_mods = is_system_server
280*795d594fSAndroid Build Coastguard Worker       ? gFlags.MetricsReportingNumModsServer()
281*795d594fSAndroid Build Coastguard Worker       : gFlags.MetricsReportingNumMods();
282*795d594fSAndroid Build Coastguard Worker   uint32_t reporting_mods = is_system_server
283*795d594fSAndroid Build Coastguard Worker       ? gFlags.MetricsReportingModsServer()
284*795d594fSAndroid Build Coastguard Worker       : gFlags.MetricsReportingMods();
285*795d594fSAndroid Build Coastguard Worker 
286*795d594fSAndroid Build Coastguard Worker   if (reporting_mods > reporting_num_mods || reporting_num_mods == 0) {
287*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Invalid metrics reporting mods: " << reporting_mods
288*795d594fSAndroid Build Coastguard Worker         << " num modes=" << reporting_num_mods
289*795d594fSAndroid Build Coastguard Worker         << ". The reporting is disabled";
290*795d594fSAndroid Build Coastguard Worker     reporting_mods = 0;
291*795d594fSAndroid Build Coastguard Worker     reporting_num_mods = 100;
292*795d594fSAndroid Build Coastguard Worker   }
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker   return {
295*795d594fSAndroid Build Coastguard Worker       .dump_to_logcat = gFlags.MetricsWriteToLogcat(),
296*795d594fSAndroid Build Coastguard Worker       .dump_to_statsd = gFlags.MetricsWriteToStatsd(),
297*795d594fSAndroid Build Coastguard Worker       .dump_to_file = gFlags.MetricsWriteToFile.GetValueOptional(),
298*795d594fSAndroid Build Coastguard Worker       .metrics_format = gFlags.MetricsFormat(),
299*795d594fSAndroid Build Coastguard Worker       .period_spec = period_spec,
300*795d594fSAndroid Build Coastguard Worker       .reporting_mods = reporting_mods,
301*795d594fSAndroid Build Coastguard Worker       .reporting_num_mods = reporting_num_mods,
302*795d594fSAndroid Build Coastguard Worker   };
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker 
Parse(const std::string & spec_str,std::string * error_msg)305*795d594fSAndroid Build Coastguard Worker std::optional<ReportingPeriodSpec> ReportingPeriodSpec::Parse(
306*795d594fSAndroid Build Coastguard Worker     const std::string& spec_str, std::string* error_msg) {
307*795d594fSAndroid Build Coastguard Worker   *error_msg = "";
308*795d594fSAndroid Build Coastguard Worker   if (spec_str.empty()) {
309*795d594fSAndroid Build Coastguard Worker     *error_msg = "Invalid empty spec.";
310*795d594fSAndroid Build Coastguard Worker     return std::nullopt;
311*795d594fSAndroid Build Coastguard Worker   }
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker   // Split the string. Each element is separated by comma.
314*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> elems;
315*795d594fSAndroid Build Coastguard Worker   Split(spec_str, ',', &elems);
316*795d594fSAndroid Build Coastguard Worker 
317*795d594fSAndroid Build Coastguard Worker   // Check the startup marker (front) and the continuous one (back).
318*795d594fSAndroid Build Coastguard Worker   std::optional<ReportingPeriodSpec> spec = std::make_optional(ReportingPeriodSpec());
319*795d594fSAndroid Build Coastguard Worker   spec->spec = spec_str;
320*795d594fSAndroid Build Coastguard Worker   spec->report_startup_first = elems.front() == "S";
321*795d594fSAndroid Build Coastguard Worker   spec->continuous_reporting = elems.back() == "*";
322*795d594fSAndroid Build Coastguard Worker 
323*795d594fSAndroid Build Coastguard Worker   // Compute the indices for the period values.
324*795d594fSAndroid Build Coastguard Worker   size_t start_interval_idx = spec->report_startup_first ? 1 : 0;
325*795d594fSAndroid Build Coastguard Worker   size_t end_interval_idx = spec->continuous_reporting ? (elems.size() - 1) : elems.size();
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker   // '*' needs a numeric interval before in order to be valid.
328*795d594fSAndroid Build Coastguard Worker   if (spec->continuous_reporting &&
329*795d594fSAndroid Build Coastguard Worker       end_interval_idx == start_interval_idx) {
330*795d594fSAndroid Build Coastguard Worker     *error_msg = "Invalid period value in spec: " + spec_str;
331*795d594fSAndroid Build Coastguard Worker     return std::nullopt;
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   // Parse the periods.
335*795d594fSAndroid Build Coastguard Worker   for (size_t i = start_interval_idx; i < end_interval_idx; i++) {
336*795d594fSAndroid Build Coastguard Worker     uint32_t period;
337*795d594fSAndroid Build Coastguard Worker     if (!android::base::ParseUint(elems[i], &period)) {
338*795d594fSAndroid Build Coastguard Worker         *error_msg = "Invalid period value in spec: " + spec_str;
339*795d594fSAndroid Build Coastguard Worker         return std::nullopt;
340*795d594fSAndroid Build Coastguard Worker     }
341*795d594fSAndroid Build Coastguard Worker     spec->periods_seconds.push_back(period);
342*795d594fSAndroid Build Coastguard Worker   }
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker   return spec;
345*795d594fSAndroid Build Coastguard Worker }
346*795d594fSAndroid Build Coastguard Worker 
347*795d594fSAndroid Build Coastguard Worker }  // namespace metrics
348*795d594fSAndroid Build Coastguard Worker }  // namespace art
349*795d594fSAndroid Build Coastguard Worker 
350*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic pop  // -Wconversion
351