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