1 /*
2  * Copyright (C) 2023 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 package android.boottime.postprocessor;
18 
19 import com.android.tradefed.config.Option;
20 import com.android.tradefed.log.LogUtil;
21 import com.android.tradefed.metrics.proto.MetricMeasurement;
22 import com.android.tradefed.postprocessor.BasePostProcessor;
23 import com.android.tradefed.result.LogFile;
24 import com.android.tradefed.result.TestDescription;
25 
26 import java.io.File;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Comparator;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Optional;
35 import java.util.Set;
36 import java.util.stream.Collectors;
37 
38 public class BaseBootTimeTestLogPostProcessor extends BasePostProcessor {
39     protected static final String DMESG_BOOT_COMPLETE_TIME =
40             "dmesg_action_sys.boot_completed_first_timestamp";
41 
42     @Option(name = "file-regex", description = "Regex for identifying a logcat file name.")
43     protected Set<String> mFileRegex = new HashSet<>();
44 
45     /** {@inheritDoc} */
46     @Override
processTestMetricsAndLogs( TestDescription testDescription, HashMap<String, MetricMeasurement.Metric> testMetrics, Map<String, LogFile> testLogs)47     public Map<String, MetricMeasurement.Metric.Builder> processTestMetricsAndLogs(
48             TestDescription testDescription,
49             HashMap<String, MetricMeasurement.Metric> testMetrics,
50             Map<String, LogFile> testLogs) {
51         return new HashMap<>();
52     }
53 
54     /** {@inheritDoc} */
55     @Override
processRunMetricsAndLogs( HashMap<String, MetricMeasurement.Metric> rawMetrics, Map<String, LogFile> runLogs)56     public Map<String, MetricMeasurement.Metric.Builder> processRunMetricsAndLogs(
57             HashMap<String, MetricMeasurement.Metric> rawMetrics, Map<String, LogFile> runLogs) {
58         return new HashMap<>();
59     }
60 
61     /** {@inheritDoc} */
62     /**
63      * Returns {@link MetricMeasurement.DataType.RAW} for metrics reported by the post processor.
64      * RAW is required in order for {@link
65      * com.android.tradefed.postprocessor.MetricFilePostProcessor} to aggregate the values
66      */
67     @Override
getMetricType()68     protected MetricMeasurement.DataType getMetricType() {
69         // Return raw metrics in order for MetricFilePostProcessor to aggregate
70         return MetricMeasurement.DataType.RAW;
71     }
72 
73     /**
74      * Build TradeFed metrics from raw Double values.
75      *
76      * @param metrics contains a map of {@link Collection} each single value represents a metric for
77      *     a particular boot iteration
78      * @return Map with metric keys and stringified double values joined by comma
79      */
buildTfMetrics( Map<String, Collection<Double>> metrics)80     protected Map<String, MetricMeasurement.Metric.Builder> buildTfMetrics(
81             Map<String, Collection<Double>> metrics) {
82         Map<String, MetricMeasurement.Metric.Builder> tfMetrics = new HashMap<>();
83 
84         LogUtil.CLog.v("Collected %d metrics", metrics.size());
85         for (Map.Entry<String, Collection<Double>> entry : metrics.entrySet()) {
86             String stringValue =
87                     entry.getValue().stream()
88                             .map(value -> value.toString())
89                             .collect(Collectors.joining(","));
90             MetricMeasurement.Measurements.Builder measurement =
91                     MetricMeasurement.Measurements.newBuilder().setSingleString(stringValue);
92             MetricMeasurement.Metric.Builder metricBuilder =
93                     MetricMeasurement.Metric.newBuilder().setMeasurements(measurement);
94             tfMetrics.put(entry.getKey(), metricBuilder);
95         }
96         return tfMetrics;
97     }
98 
filterFiles(Map<String, LogFile> logs)99     protected List<File> filterFiles(Map<String, LogFile> logs) {
100         List<File> files = new ArrayList<>();
101         for (Map.Entry<String, LogFile> entry : logs.entrySet()) {
102             LogUtil.CLog.v("Filtering log file %s", entry.getKey());
103             Optional<String> match =
104                     mFileRegex.stream().filter(regex -> entry.getKey().matches(regex)).findAny();
105             if (match.isPresent()) {
106                 LogUtil.CLog.d(
107                         "Found match testLog file %s at %s",
108                         entry.getKey(), entry.getValue().getPath());
109                 files.add(new File(entry.getValue().getPath()));
110             }
111         }
112         files.sort(Comparator.comparing(File::getName));
113         return files;
114     }
115 }
116