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