1 /*
2  * Copyright (C) 2018 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 package android.cts.statsd.metric;
17 
18 import static com.google.common.truth.Truth.assertWithMessage;
19 
20 import android.cts.statsd.atom.BufferDebug;
21 
22 import com.android.internal.os.StatsdConfigProto;
23 import com.android.internal.os.StatsdConfigProto.AtomMatcher;
24 import com.android.internal.os.StatsdConfigProto.EventActivation;
25 import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
26 import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
27 import com.android.os.AtomsProto.Atom;
28 import com.android.os.AtomsProto.AppBreadcrumbReported;
29 import com.android.tradefed.device.CollectingByteOutputReceiver;
30 import com.android.tradefed.device.DeviceNotAvailableException;
31 import com.android.tradefed.device.ITestDevice;
32 import com.android.tradefed.log.LogUtil;
33 import com.android.tradefed.util.RunUtil;
34 
35 import com.google.protobuf.InvalidProtocolBufferException;
36 import com.google.protobuf.Message;
37 import com.google.protobuf.Descriptors.Descriptor;
38 import com.google.protobuf.Descriptors.FieldDescriptor;
39 import com.google.protobuf.MessageLite;
40 import com.google.protobuf.Parser;
41 
42 import java.text.SimpleDateFormat;
43 import java.util.Date;
44 
45 public class MetricsUtils {
46     public static final String DEVICE_SIDE_TEST_PACKAGE =
47             "com.android.server.cts.device.statsd";
48     public static final String DEVICE_SIDE_TEST_APK = "CtsStatsdApp.apk";
49     public static final long COUNT_METRIC_ID = 3333;
50     public static final long DURATION_METRIC_ID = 4444;
51     public static final long GAUGE_METRIC_ID = 5555;
52     public static final long VALUE_METRIC_ID = 6666;
53     public static final long EVENT_METRIC_ID = 7777;
54 
getAtomMatcher(int atomId)55     public static AtomMatcher.Builder getAtomMatcher(int atomId) {
56         AtomMatcher.Builder builder = AtomMatcher.newBuilder();
57         builder.setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
58                 .setAtomId(atomId));
59         return builder;
60     }
61 
startAtomMatcher(int id)62     public static AtomMatcher startAtomMatcher(int id) {
63         return AtomMatcher.newBuilder()
64                 .setId(id)
65                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
66                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
67                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
68                                 .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
69                                 .setEqInt(AppBreadcrumbReported.State.START.getNumber())))
70                 .build();
71     }
72 
startAtomMatcherWithLabel(int id, int label)73     public static AtomMatcher startAtomMatcherWithLabel(int id, int label) {
74         return appBreadcrumbMatcherWithLabelAndState(id, label, AppBreadcrumbReported.State.START);
75     }
76 
stopAtomMatcher(int id)77     public static AtomMatcher stopAtomMatcher(int id) {
78         return AtomMatcher.newBuilder()
79                 .setId(id)
80                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
81                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
82                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
83                                 .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
84                                 .setEqInt(AppBreadcrumbReported.State.STOP.getNumber())))
85                 .build();
86     }
87 
stopAtomMatcherWithLabel(int id, int label)88     public static AtomMatcher stopAtomMatcherWithLabel(int id, int label) {
89         return appBreadcrumbMatcherWithLabelAndState(id, label, AppBreadcrumbReported.State.STOP);
90     }
91 
unspecifiedAtomMatcher(int id)92     public static AtomMatcher unspecifiedAtomMatcher(int id) {
93         return AtomMatcher.newBuilder()
94                 .setId(id)
95                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
96                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
97                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
98                                 .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
99                                 .setEqInt(AppBreadcrumbReported.State.UNSPECIFIED.getNumber())))
100                 .build();
101     }
102 
simpleAtomMatcher(int id)103     public static AtomMatcher simpleAtomMatcher(int id) {
104         return AtomMatcher.newBuilder()
105                 .setId(id)
106                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
107                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER))
108                 .build();
109     }
110 
appBreadcrumbMatcherWithLabel(int id, int label)111     public static AtomMatcher appBreadcrumbMatcherWithLabel(int id, int label) {
112         return AtomMatcher.newBuilder()
113                 .setId(id)
114                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
115                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
116                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
117                                 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
118                                 .setEqInt(label)))
119                 .build();
120     }
121 
appBreadcrumbMatcherWithLabelAndState(int id, int label, final AppBreadcrumbReported.State state)122     public static AtomMatcher appBreadcrumbMatcherWithLabelAndState(int id, int label,
123             final AppBreadcrumbReported.State state) {
124 
125         return AtomMatcher.newBuilder()
126                 .setId(id)
127                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
128                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
129                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
130                                 .setField(AppBreadcrumbReported.STATE_FIELD_NUMBER)
131                                 .setEqInt(state.getNumber()))
132                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
133                                 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
134                                 .setEqInt(label)))
135                 .build();
136     }
137 
simpleAtomMatcher(int id, int label)138     public static AtomMatcher simpleAtomMatcher(int id, int label) {
139         return AtomMatcher.newBuilder()
140                 .setId(id)
141                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
142                         .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
143                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
144                                 .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
145                                 .setEqInt(label)
146                         )
147                 )
148                 .build();
149     }
150 
createEventActivation(int ttlSecs, int matcherId, int cancelMatcherId)151     public static EventActivation.Builder createEventActivation(int ttlSecs, int matcherId,
152             int cancelMatcherId) {
153         return EventActivation.newBuilder()
154                 .setAtomMatcherId(matcherId)
155                 .setTtlSeconds(ttlSecs)
156                 .setDeactivationAtomMatcherId(cancelMatcherId);
157     }
158 
StringToId(String str)159     public static long StringToId(String str) {
160         return str.hashCode();
161     }
162 
getCurrentLogcatDate(ITestDevice device)163     public static String getCurrentLogcatDate(ITestDevice device) throws Exception {
164         // TODO: Do something more robust than this for getting logcat markers.
165         long timestampMs = device.getDeviceDate();
166         return new SimpleDateFormat("MM-dd HH:mm:ss.SSS")
167                 .format(new Date(timestampMs));
168     }
169 
assertBucketTimePresent(Message bucketInfo)170     public static void assertBucketTimePresent(Message bucketInfo) {
171         Descriptor descriptor = bucketInfo.getDescriptorForType();
172         boolean found = false;
173         FieldDescriptor bucketNum = descriptor.findFieldByName("bucket_num");
174         FieldDescriptor startMillis = descriptor.findFieldByName("start_bucket_elapsed_millis");
175         FieldDescriptor endMillis = descriptor.findFieldByName("end_bucket_elapsed_millis");
176         if (bucketNum != null && bucketInfo.hasField(bucketNum)) {
177             found = true;
178         } else if (startMillis != null && bucketInfo.hasField(startMillis) &&
179                 endMillis != null && bucketInfo.hasField(endMillis)) {
180             found = true;
181         }
182         assertWithMessage(
183                 "Bucket info did not have either bucket num or start and end elapsed millis"
184         ).that(found).isTrue();
185     }
186 
didIncidentdFireSince(ITestDevice device, String date)187     public static boolean didIncidentdFireSince(ITestDevice device, String date) throws Exception {
188         final String INCIDENTD_TAG = "incidentd";
189         final String INCIDENTD_STARTED_STRING = "reportIncident";
190         // TODO: Do something more robust than this in case of delayed logging.
191         RunUtil.getDefault().sleep(1000);
192         String log = getLogcatSince(device, date, String.format(
193                 "-s %s -e %s", INCIDENTD_TAG, INCIDENTD_STARTED_STRING));
194         return log.contains(INCIDENTD_STARTED_STRING);
195     }
196 
getLogcatSince(ITestDevice device, String date, String logcatParams)197     public static String getLogcatSince(ITestDevice device, String date, String logcatParams)
198             throws Exception {
199         return device.executeShellCommand(String.format(
200                 "logcat -v threadtime -t '%s' -d %s", date, logcatParams));
201     }
202 
203     /**
204      * Call onto the device with an adb shell command and get the results of
205      * that as a proto of the given type.
206      *
207      * @param parser  A protobuf parser object. e.g. MyProto.parser()
208      * @param command The adb shell command to run. e.g. "dumpsys fingerprint --proto"
209      * @throws DeviceNotAvailableException    If there was a problem communicating with
210      *                                        the test device.
211      * @throws InvalidProtocolBufferException If there was an error parsing
212      *                                        the proto. Note that a 0 length buffer is not
213      *                                        necessarily an error.
214      */
getDump(ITestDevice device, Parser<T> parser, String command)215     public static <T extends MessageLite> T getDump(ITestDevice device, Parser<T> parser,
216             String command)
217             throws DeviceNotAvailableException, InvalidProtocolBufferException {
218         final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
219         device.executeShellCommand(command, receiver);
220         if (false) {
221             LogUtil.CLog.d("Command output while parsing " + parser.getClass().getCanonicalName()
222                     + " for command: " + command + "\n"
223                     + BufferDebug.debugString(receiver.getOutput(), -1));
224         }
225         try {
226             return parser.parseFrom(receiver.getOutput());
227         } catch (Exception ex) {
228             LogUtil.CLog.d(
229                     "Error parsing " + parser.getClass().getCanonicalName() + " for command: "
230                             + command
231                             + BufferDebug.debugString(receiver.getOutput(), 16384));
232             throw ex;
233         }
234     }
235 }
236