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