1 package com.android.helpers; 2 3 import android.app.Instrumentation; 4 import android.os.ParcelFileDescriptor; 5 import android.util.Log; 6 7 import java.io.ByteArrayOutputStream; 8 import java.io.InputStream; 9 import java.io.IOException; 10 import java.text.DecimalFormat; 11 import java.text.ParseException; 12 import java.util.ArrayList; 13 import java.util.List; 14 import java.util.Map; 15 16 /** 17 * MetricUtility consist of basic utility methods to construct the metrics 18 * reported at the end of the test. 19 */ 20 public class MetricUtility { 21 22 private static final String TAG = MetricUtility.class.getSimpleName(); 23 private static final String KEY_JOIN = "_"; 24 public static final String METRIC_SEPARATOR = ","; 25 26 public static final int BUFFER_SIZE = 1024; 27 private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("#0.000001"); 28 29 /** 30 * Append the given array of string to construct the final key used to track the metrics. 31 * 32 * @param keys to append using KEY_JOIN 33 */ constructKey(String... keys)34 public static String constructKey(String... keys) { 35 return String.join(KEY_JOIN, keys); 36 } 37 38 /** 39 * Add metric to the result map. If metric key already exist append the new metric. 40 * 41 * @param metricKey Unique key to track the metric. 42 * @param metric metric to track. 43 * @param resultMap map of all the metrics. 44 */ addMetric(String metricKey, long metric, Map<String, StringBuilder> resultMap)45 public static void addMetric(String metricKey, long metric, Map<String, 46 StringBuilder> resultMap) { 47 resultMap.compute(metricKey, (key, value) -> (value == null) ? 48 new StringBuilder().append(metric) : value.append(METRIC_SEPARATOR).append(metric)); 49 } 50 51 /** 52 * Add metric to the result map. If metric key already exist append the new metric. 53 * 54 * @param metricKey Unique key to track the metric. 55 * @param metric metric to track. 56 * @param resultMap map of all the metrics. 57 */ addMetric( String metricKey, double metric, Map<String, StringBuilder> resultMap)58 public static void addMetric( 59 String metricKey, double metric, Map<String, StringBuilder> resultMap) { 60 resultMap.compute( 61 metricKey, 62 (key, value) -> 63 (value == null ? new StringBuilder() : value.append(METRIC_SEPARATOR)) 64 .append(DOUBLE_FORMAT.format(metric))); 65 } 66 67 /** 68 * Add metric to the result map. If metric key already exist increment the value by 1. 69 * 70 * @param metricKey Unique key to track the metric. 71 * @param resultMap map of all the metrics. 72 */ addMetric(String metricKey, Map<String, Integer> resultMap)73 public static void addMetric(String metricKey, Map<String, 74 Integer> resultMap) { 75 resultMap.compute(metricKey, (key, value) -> (value == null) ? 1 : value + 1); 76 } 77 78 /** 79 * Get metric values from result map. 80 * 81 * @param metricKey Unique key to track the metric. 82 * @param resultMap Map of all the metrics. 83 * @return Double List of metric values for metric key 84 */ getMetricDoubles( String metricKey, Map<String, StringBuilder> resultMap)85 public static List<Double> getMetricDoubles( 86 String metricKey, Map<String, StringBuilder> resultMap) { 87 List<Double> result = new ArrayList<Double>(); 88 if (!resultMap.containsKey(metricKey)) { 89 Log.e(TAG, String.format("No such metric key %s", metricKey)); 90 return result; 91 } else { 92 String value = resultMap.get(metricKey).toString(); 93 if (value.length() == 0) { 94 Log.e(TAG, String.format("Missed value of metric key %s", metricKey)); 95 return result; 96 } else { 97 String[] values = value.split(METRIC_SEPARATOR); 98 for (int i = 0; i < values.length; i++) { 99 try { 100 result.add(DOUBLE_FORMAT.parse(values[i]).doubleValue()); 101 } catch (ParseException e) { 102 Log.e( 103 TAG, 104 String.format( 105 "Error parsing value of metric key %s: #%d of value %s", 106 metricKey, i, value)); 107 return new ArrayList<Double>(); 108 } 109 } 110 } 111 } 112 return result; 113 } 114 115 /** 116 * Turn executeShellCommand into a blocking operation. 117 * 118 * @param command shell command to be executed. 119 * @param instr used to run the shell command. 120 * @return byte array of execution result 121 */ executeCommandBlocking(String command, Instrumentation instr)122 public static byte[] executeCommandBlocking(String command, Instrumentation instr) { 123 try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(instr.getUiAutomation() 124 .executeShellCommand(command)); 125 ByteArrayOutputStream out = new ByteArrayOutputStream()) { 126 byte[] buf = new byte[BUFFER_SIZE]; 127 int length; 128 Log.i(TAG, "Start reading the data"); 129 while ((length = is.read(buf)) >= 0) { 130 out.write(buf, 0, length); 131 } 132 Log.i(TAG, "Stop reading the data"); 133 return out.toByteArray(); 134 } catch (IOException e) { 135 Log.e(TAG, "Error executing: " + command, e); 136 return null; 137 } 138 } 139 140 } 141