Loading cmds/statsd/tools/localtools/Android.bp +25 −4 Original line number Diff line number Diff line Loading @@ -11,9 +11,8 @@ java_binary_host { ], } java_binary_host { name: "statsd_testdrive", manifest: "testdrive_manifest.txt", java_library_host { name: "statsd_testdrive_lib", srcs: [ "src/com/android/statsd/shelltools/testdrive/*.java", "src/com/android/statsd/shelltools/Utils.java", Loading @@ -23,3 +22,25 @@ java_binary_host { "guava", ], } java_binary_host { name: "statsd_testdrive", manifest: "testdrive_manifest.txt", static_libs: [ "statsd_testdrive_lib", ], } java_test_host { name: "statsd_testdrive_test", test_suites: ["general-tests"], srcs: ["test/com/android/statsd/shelltools/testdrive/*.java"], static_libs: [ "statsd_testdrive_lib", "junit", "platformprotos", "guava", ], } cmds/statsd/tools/localtools/TEST_MAPPING 0 → 100644 +8 −0 Original line number Diff line number Diff line { "presubmit": [ { "name": "statsd_testdrive_test", "host": true } ] } cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java +52 −0 Original line number Diff line number Diff line Loading @@ -229,4 +229,56 @@ public class Utils { } return null; } /** * Returns ANDROID_SERIAL environment variable, or null if that is undefined or unavailable. * @param logger Destination of error messages. * @return String value of ANDROID_SERIAL environment variable, or null. */ public static String getDefaultDevice(Logger logger) { try { return System.getenv("ANDROID_SERIAL"); } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to check ANDROID_SERIAL environment variable.", ex); } return null; } /** * Returns the device to use if one can be deduced, or null. * @param device Command-line specified device, or null. * @param connectedDevices List of all connected devices. * @param defaultDevice Environment-variable specified device, or null. * @param logger Destination of error messages. * @return Device to use, or null. */ public static String chooseDevice(String device, List<String> connectedDevices, String defaultDevice, Logger logger) { if (connectedDevices == null || connectedDevices.isEmpty()) { logger.severe("No connected device."); return null; } if (device != null) { if (connectedDevices.contains(device)) { return device; } logger.severe("Device not connected: " + device); return null; } if (connectedDevices.size() == 1) { return connectedDevices.get(0); } if (defaultDevice != null) { if (connectedDevices.contains(defaultDevice)) { return defaultDevice; } else { logger.severe("ANDROID_SERIAL device is not connected: " + defaultDevice); return null; } } logger.severe("More than one device is connected. Choose one" + " with -s DEVICE_SERIAL or environment variable ANDROID_SERIAL."); return null; } } cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java +2 −11 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** Loading Loading @@ -112,17 +111,9 @@ public class LocalDrive { } List<String> connectedDevices = Utils.getDeviceSerials(sLogger); if (connectedDevices == null || connectedDevices.size() == 0) { sLogger.log(Level.SEVERE, "No device connected."); return; } if (connectedDevices.size() == 1 && deviceSerial == null) { deviceSerial = connectedDevices.get(0); } deviceSerial = Utils.chooseDevice(deviceSerial, connectedDevices, Utils.getDefaultDevice(sLogger), sLogger); if (deviceSerial == null) { sLogger.log(Level.SEVERE, "More than one devices connected. Please specify" + " with -s DEVICE_SERIAL"); return; } Loading cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java +207 −128 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.statsd.shelltools.testdrive; import com.android.internal.os.StatsdConfigProto; import com.android.internal.os.StatsdConfigProto.AtomMatcher; import com.android.internal.os.StatsdConfigProto.EventMetric; import com.android.internal.os.StatsdConfigProto.FieldFilter; Loading @@ -29,6 +30,7 @@ import com.android.os.StatsLog.ConfigMetricsReportList; import com.android.os.StatsLog.StatsLogReport; import com.android.statsd.shelltools.Utils; import com.google.common.annotations.VisibleForTesting; import com.google.common.io.Files; import java.io.File; Loading @@ -39,6 +41,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; Loading Loading @@ -73,148 +76,181 @@ public class TestDrive { }; private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName()); private String mAdditionalAllowedPackage; private String mDeviceSerial; private final Set<Long> mTrackedMetrics = new HashSet<>(); @VisibleForTesting String mDeviceSerial = null; public static void main(String[] args) { final Configuration configuration = new Configuration(); TestDrive testDrive = new TestDrive(); Set<Integer> trackedAtoms = new HashSet<>(); Utils.setUpLogger(LOGGER, false); String remoteConfigPath = null; if (args.length < 1) { LOGGER.log(Level.SEVERE, "Usage: ./test_drive [-p additional_allowed_package] " + "[-s DEVICE_SERIAL_NUMBER]" + "<atomId1> <atomId2> ... <atomIdN>"); if (!testDrive.processArgs(configuration, args, Utils.getDeviceSerials(LOGGER), Utils.getDefaultDevice(LOGGER))) { return; } List<String> connectedDevices = Utils.getDeviceSerials(LOGGER); if (connectedDevices == null || connectedDevices.size() == 0) { LOGGER.log(Level.SEVERE, "No device connected."); return; final ConfigMetricsReportList reports = testDrive.testDriveAndGetReports( configuration.createConfig(), configuration.hasPulledAtoms(), configuration.hasPushedAtoms()); if (reports != null) { configuration.dumpMetrics(reports); } int arg_index = 0; while (arg_index < args.length) { String arg = args[arg_index]; if (arg.equals("-p")) { testDrive.mAdditionalAllowedPackage = args[++arg_index]; } else if (arg.equals("-s")) { testDrive.mDeviceSerial = args[++arg_index]; } else { break; } arg_index++; boolean processArgs(Configuration configuration, String[] args, List<String> connectedDevices, String defaultDevice) { if (args.length < 1) { LOGGER.severe("Usage: ./test_drive [-one] " + "[-p additional_allowed_package] " + "[-s DEVICE_SERIAL_NUMBER] " + "<atomId1> <atomId2> ... <atomIdN>"); return false; } if (connectedDevices.size() == 1 && testDrive.mDeviceSerial == null) { testDrive.mDeviceSerial = connectedDevices.get(0); int first_arg = 0; // Consume all flags, which must precede all atoms for (; first_arg < args.length; ++first_arg) { String arg = args[first_arg]; int remaining_args = args.length - first_arg; if (remaining_args >= 2 && arg.equals("-one")) { LOGGER.info("Creating one event metric to catch all pushed atoms."); configuration.mOnePushedAtomEvent = true; } else if (remaining_args >= 3 && arg.equals("-p")) { configuration.mAdditionalAllowedPackage = args[++first_arg]; } else if (remaining_args >= 3 && arg.equals("-s")) { mDeviceSerial = args[++first_arg]; } else { break; // Found the atom list } } if (testDrive.mDeviceSerial == null) { LOGGER.log(Level.SEVERE, "More than one devices connected. Please specify" + " with -s DEVICE_SERIAL"); return; mDeviceSerial = Utils.chooseDevice(mDeviceSerial, connectedDevices, defaultDevice, LOGGER); if (mDeviceSerial == null) { return false; } for (int i = arg_index; i < args.length; i++) { for ( ; first_arg < args.length; ++first_arg) { String atom = args[first_arg]; try { int atomId = Integer.valueOf(args[i]); if (Atom.getDescriptor().findFieldByNumber(atomId) == null) { LOGGER.log(Level.SEVERE, "No such atom found: " + args[i]); continue; } trackedAtoms.add(atomId); configuration.addAtom(Integer.valueOf(atom)); } catch (NumberFormatException e) { LOGGER.log(Level.SEVERE, "Bad atom id provided: " + args[i]); continue; LOGGER.severe("Bad atom id provided: " + atom); } } try { StatsdConfig config = testDrive.createConfig(trackedAtoms); return configuration.hasPulledAtoms() || configuration.hasPushedAtoms(); } private ConfigMetricsReportList testDriveAndGetReports(StatsdConfig config, boolean hasPulledAtoms, boolean hasPushedAtoms) { if (config == null) { LOGGER.log(Level.SEVERE, "Failed to create valid config."); return; LOGGER.severe("Failed to create valid config."); return null; } remoteConfigPath = testDrive.pushConfig(config, testDrive.mDeviceSerial); LOGGER.info("Pushed the following config to statsd:"); String remoteConfigPath = null; try { remoteConfigPath = pushConfig(config, mDeviceSerial); LOGGER.info("Pushed the following config to statsd on device '" + mDeviceSerial + "':"); LOGGER.info(config.toString()); if (!hasPulledAtom(trackedAtoms)) { if (hasPushedAtoms) { LOGGER.info("Now please play with the device to trigger the event."); } if (!hasPulledAtoms) { LOGGER.info( "Now please play with the device to trigger the event. All events should " + "be dumped after 1 min ..."); "All events should be dumped after 1 min ..."); Thread.sleep(60_000); } else { LOGGER.info("Now wait for 1.5 minutes ..."); LOGGER.info("All events should be dumped after 1.5 minutes ..."); Thread.sleep(15_000); Utils.logAppBreadcrumb(0, 0, LOGGER, testDrive.mDeviceSerial); Utils.logAppBreadcrumb(0, 0, LOGGER, mDeviceSerial); Thread.sleep(75_000); } testDrive.dumpMetrics(); return Utils.getReportList(CONFIG_ID, true, false, LOGGER, mDeviceSerial); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to test drive: " + e.getMessage(), e); } finally { testDrive.removeConfig(testDrive.mDeviceSerial); removeConfig(mDeviceSerial); if (remoteConfigPath != null) { try { Utils.runCommand(null, LOGGER, "adb", "-s", testDrive.mDeviceSerial, "shell", "rm", remoteConfigPath); "adb", "-s", mDeviceSerial, "shell", "rm", remoteConfigPath); } catch (Exception e) { LOGGER.log(Level.WARNING, "Unable to remove remote config file: " + remoteConfigPath, e); } } } return null; } private void dumpMetrics() throws Exception { ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, LOGGER, mDeviceSerial); static class Configuration { boolean mOnePushedAtomEvent = false; @VisibleForTesting Set<Integer> mPushedAtoms = new TreeSet<>(); @VisibleForTesting Set<Integer> mPulledAtoms = new TreeSet<>(); @VisibleForTesting String mAdditionalAllowedPackage = null; private final Set<Long> mTrackedMetrics = new HashSet<>(); private void dumpMetrics(ConfigMetricsReportList reportList) { // We may get multiple reports. Take the last one. ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1); for (StatsLogReport statsLog : report.getMetricsList()) { if (mTrackedMetrics.contains(statsLog.getMetricId())) { if (isTrackedMetric(statsLog.getMetricId())) { LOGGER.info(statsLog.toString()); } } } private StatsdConfig createConfig(Set<Integer> atomIds) { long metricId = METRIC_ID_BASE; long atomMatcherId = ATOM_MATCHER_ID_BASE; boolean isTrackedMetric(long metricId) { return mTrackedMetrics.contains(metricId); } ArrayList<String> allowedSources = new ArrayList<>(); Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES); if (mAdditionalAllowedPackage != null) { allowedSources.add(mAdditionalAllowedPackage); static boolean isPulledAtom(int atomId) { return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG || atomId >= VENDOR_PULLED_ATOM_START_TAG; } StatsdConfig.Builder builder = StatsdConfig.newBuilder(); builder .addAllAllowedLogSource(allowedSources) .addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES)) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER) .addPackages("AID_STATSD")) .setHashStringsInMetricReport(false); void addAtom(Integer atom) { if (Atom.getDescriptor().findFieldByNumber(atom) == null) { LOGGER.severe("No such atom found: " + atom); return; } if (isPulledAtom(atom)) { mPulledAtoms.add(atom); } else { mPushedAtoms.add(atom); } } if (hasPulledAtom(atomIds)) { private boolean hasPulledAtoms() { return !mPulledAtoms.isEmpty(); } private boolean hasPushedAtoms() { return !mPushedAtoms.isEmpty(); } StatsdConfig createConfig() { long metricId = METRIC_ID_BASE; long atomMatcherId = ATOM_MATCHER_ID_BASE; StatsdConfig.Builder builder = baseBuilder(); if (hasPulledAtoms()) { builder.addAtomMatcher( createAtomMatcher( Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, APP_BREADCRUMB_MATCHER_ID)); Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, APP_BREADCRUMB_MATCHER_ID)); } for (int atomId : atomIds) { if (isPulledAtom(atomId)) { for (int atomId : mPulledAtoms) { builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); GaugeMetric.Builder gaugeMetricBuilder = GaugeMetric.newBuilder(); gaugeMetricBuilder Loading @@ -226,17 +262,39 @@ public class TestDrive { .setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES) .setMaxNumGaugeAtomsPerBucket(100); builder.addGaugeMetric(gaugeMetricBuilder.build()); atomMatcherId++; mTrackedMetrics.add(metricId++); } // A simple atom matcher for each pushed atom. List<AtomMatcher> simpleAtomMatchers = new ArrayList<>(); for (int atomId : mPushedAtoms) { final AtomMatcher atomMatcher = createAtomMatcher(atomId, atomMatcherId++); simpleAtomMatchers.add(atomMatcher); builder.addAtomMatcher(atomMatcher); } if (mOnePushedAtomEvent) { // Create a union event metric, using an matcher that matches all pulled atoms. AtomMatcher unionAtomMatcher = createUnionMatcher(simpleAtomMatchers, atomMatcherId); builder.addAtomMatcher(unionAtomMatcher); EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder(); eventMetricBuilder.setId(metricId).setWhat(unionAtomMatcher.getId()); builder.addEventMetric(eventMetricBuilder.build()); mTrackedMetrics.add(metricId++); } else { // Create multiple event metrics, one per pulled atom. for (AtomMatcher atomMatcher : simpleAtomMatchers) { EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder(); eventMetricBuilder .setId(metricId) .setWhat(atomMatcherId); .setWhat(atomMatcher.getId()); builder.addEventMetric(eventMetricBuilder.build()); builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); } atomMatcherId++; mTrackedMetrics.add(metricId++); } } return builder.build(); } Loading @@ -248,6 +306,41 @@ public class TestDrive { return atomMatcherBuilder.build(); } private AtomMatcher createUnionMatcher(List<AtomMatcher> simpleAtomMatchers, long atomMatcherId) { AtomMatcher.Combination.Builder combinationBuilder = AtomMatcher.Combination.newBuilder(); combinationBuilder.setOperation(StatsdConfigProto.LogicalOperation.OR); for (AtomMatcher matcher : simpleAtomMatchers) { combinationBuilder.addMatcher(matcher.getId()); } AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder(); atomMatcherBuilder.setId(atomMatcherId).setCombination(combinationBuilder.build()); return atomMatcherBuilder.build(); } private StatsdConfig.Builder baseBuilder() { ArrayList<String> allowedSources = new ArrayList<>(); Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES); if (mAdditionalAllowedPackage != null) { allowedSources.add(mAdditionalAllowedPackage); } return StatsdConfig.newBuilder() .addAllAllowedLogSource(allowedSources) .addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES)) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER) .addPackages("AID_STATSD")) .setHashStringsInMetricReport(false); } } private static String pushConfig(StatsdConfig config, String deviceSerial) throws IOException, InterruptedException { File configFile = File.createTempFile("statsdconfig", ".config"); Loading @@ -267,21 +360,7 @@ public class TestDrive { Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial, "shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID)); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to remove config: " + e.getMessage()); } } private static boolean isPulledAtom(int atomId) { return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG || atomId >= VENDOR_PULLED_ATOM_START_TAG; LOGGER.severe("Failed to remove config: " + e.getMessage()); } private static boolean hasPulledAtom(Set<Integer> atoms) { for (Integer i : atoms) { if (isPulledAtom(i)) { return true; } } return false; } } Loading
cmds/statsd/tools/localtools/Android.bp +25 −4 Original line number Diff line number Diff line Loading @@ -11,9 +11,8 @@ java_binary_host { ], } java_binary_host { name: "statsd_testdrive", manifest: "testdrive_manifest.txt", java_library_host { name: "statsd_testdrive_lib", srcs: [ "src/com/android/statsd/shelltools/testdrive/*.java", "src/com/android/statsd/shelltools/Utils.java", Loading @@ -23,3 +22,25 @@ java_binary_host { "guava", ], } java_binary_host { name: "statsd_testdrive", manifest: "testdrive_manifest.txt", static_libs: [ "statsd_testdrive_lib", ], } java_test_host { name: "statsd_testdrive_test", test_suites: ["general-tests"], srcs: ["test/com/android/statsd/shelltools/testdrive/*.java"], static_libs: [ "statsd_testdrive_lib", "junit", "platformprotos", "guava", ], }
cmds/statsd/tools/localtools/TEST_MAPPING 0 → 100644 +8 −0 Original line number Diff line number Diff line { "presubmit": [ { "name": "statsd_testdrive_test", "host": true } ] }
cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java +52 −0 Original line number Diff line number Diff line Loading @@ -229,4 +229,56 @@ public class Utils { } return null; } /** * Returns ANDROID_SERIAL environment variable, or null if that is undefined or unavailable. * @param logger Destination of error messages. * @return String value of ANDROID_SERIAL environment variable, or null. */ public static String getDefaultDevice(Logger logger) { try { return System.getenv("ANDROID_SERIAL"); } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to check ANDROID_SERIAL environment variable.", ex); } return null; } /** * Returns the device to use if one can be deduced, or null. * @param device Command-line specified device, or null. * @param connectedDevices List of all connected devices. * @param defaultDevice Environment-variable specified device, or null. * @param logger Destination of error messages. * @return Device to use, or null. */ public static String chooseDevice(String device, List<String> connectedDevices, String defaultDevice, Logger logger) { if (connectedDevices == null || connectedDevices.isEmpty()) { logger.severe("No connected device."); return null; } if (device != null) { if (connectedDevices.contains(device)) { return device; } logger.severe("Device not connected: " + device); return null; } if (connectedDevices.size() == 1) { return connectedDevices.get(0); } if (defaultDevice != null) { if (connectedDevices.contains(defaultDevice)) { return defaultDevice; } else { logger.severe("ANDROID_SERIAL device is not connected: " + defaultDevice); return null; } } logger.severe("More than one device is connected. Choose one" + " with -s DEVICE_SERIAL or environment variable ANDROID_SERIAL."); return null; } }
cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java +2 −11 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** Loading Loading @@ -112,17 +111,9 @@ public class LocalDrive { } List<String> connectedDevices = Utils.getDeviceSerials(sLogger); if (connectedDevices == null || connectedDevices.size() == 0) { sLogger.log(Level.SEVERE, "No device connected."); return; } if (connectedDevices.size() == 1 && deviceSerial == null) { deviceSerial = connectedDevices.get(0); } deviceSerial = Utils.chooseDevice(deviceSerial, connectedDevices, Utils.getDefaultDevice(sLogger), sLogger); if (deviceSerial == null) { sLogger.log(Level.SEVERE, "More than one devices connected. Please specify" + " with -s DEVICE_SERIAL"); return; } Loading
cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java +207 −128 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.statsd.shelltools.testdrive; import com.android.internal.os.StatsdConfigProto; import com.android.internal.os.StatsdConfigProto.AtomMatcher; import com.android.internal.os.StatsdConfigProto.EventMetric; import com.android.internal.os.StatsdConfigProto.FieldFilter; Loading @@ -29,6 +30,7 @@ import com.android.os.StatsLog.ConfigMetricsReportList; import com.android.os.StatsLog.StatsLogReport; import com.android.statsd.shelltools.Utils; import com.google.common.annotations.VisibleForTesting; import com.google.common.io.Files; import java.io.File; Loading @@ -39,6 +41,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; Loading Loading @@ -73,148 +76,181 @@ public class TestDrive { }; private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName()); private String mAdditionalAllowedPackage; private String mDeviceSerial; private final Set<Long> mTrackedMetrics = new HashSet<>(); @VisibleForTesting String mDeviceSerial = null; public static void main(String[] args) { final Configuration configuration = new Configuration(); TestDrive testDrive = new TestDrive(); Set<Integer> trackedAtoms = new HashSet<>(); Utils.setUpLogger(LOGGER, false); String remoteConfigPath = null; if (args.length < 1) { LOGGER.log(Level.SEVERE, "Usage: ./test_drive [-p additional_allowed_package] " + "[-s DEVICE_SERIAL_NUMBER]" + "<atomId1> <atomId2> ... <atomIdN>"); if (!testDrive.processArgs(configuration, args, Utils.getDeviceSerials(LOGGER), Utils.getDefaultDevice(LOGGER))) { return; } List<String> connectedDevices = Utils.getDeviceSerials(LOGGER); if (connectedDevices == null || connectedDevices.size() == 0) { LOGGER.log(Level.SEVERE, "No device connected."); return; final ConfigMetricsReportList reports = testDrive.testDriveAndGetReports( configuration.createConfig(), configuration.hasPulledAtoms(), configuration.hasPushedAtoms()); if (reports != null) { configuration.dumpMetrics(reports); } int arg_index = 0; while (arg_index < args.length) { String arg = args[arg_index]; if (arg.equals("-p")) { testDrive.mAdditionalAllowedPackage = args[++arg_index]; } else if (arg.equals("-s")) { testDrive.mDeviceSerial = args[++arg_index]; } else { break; } arg_index++; boolean processArgs(Configuration configuration, String[] args, List<String> connectedDevices, String defaultDevice) { if (args.length < 1) { LOGGER.severe("Usage: ./test_drive [-one] " + "[-p additional_allowed_package] " + "[-s DEVICE_SERIAL_NUMBER] " + "<atomId1> <atomId2> ... <atomIdN>"); return false; } if (connectedDevices.size() == 1 && testDrive.mDeviceSerial == null) { testDrive.mDeviceSerial = connectedDevices.get(0); int first_arg = 0; // Consume all flags, which must precede all atoms for (; first_arg < args.length; ++first_arg) { String arg = args[first_arg]; int remaining_args = args.length - first_arg; if (remaining_args >= 2 && arg.equals("-one")) { LOGGER.info("Creating one event metric to catch all pushed atoms."); configuration.mOnePushedAtomEvent = true; } else if (remaining_args >= 3 && arg.equals("-p")) { configuration.mAdditionalAllowedPackage = args[++first_arg]; } else if (remaining_args >= 3 && arg.equals("-s")) { mDeviceSerial = args[++first_arg]; } else { break; // Found the atom list } } if (testDrive.mDeviceSerial == null) { LOGGER.log(Level.SEVERE, "More than one devices connected. Please specify" + " with -s DEVICE_SERIAL"); return; mDeviceSerial = Utils.chooseDevice(mDeviceSerial, connectedDevices, defaultDevice, LOGGER); if (mDeviceSerial == null) { return false; } for (int i = arg_index; i < args.length; i++) { for ( ; first_arg < args.length; ++first_arg) { String atom = args[first_arg]; try { int atomId = Integer.valueOf(args[i]); if (Atom.getDescriptor().findFieldByNumber(atomId) == null) { LOGGER.log(Level.SEVERE, "No such atom found: " + args[i]); continue; } trackedAtoms.add(atomId); configuration.addAtom(Integer.valueOf(atom)); } catch (NumberFormatException e) { LOGGER.log(Level.SEVERE, "Bad atom id provided: " + args[i]); continue; LOGGER.severe("Bad atom id provided: " + atom); } } try { StatsdConfig config = testDrive.createConfig(trackedAtoms); return configuration.hasPulledAtoms() || configuration.hasPushedAtoms(); } private ConfigMetricsReportList testDriveAndGetReports(StatsdConfig config, boolean hasPulledAtoms, boolean hasPushedAtoms) { if (config == null) { LOGGER.log(Level.SEVERE, "Failed to create valid config."); return; LOGGER.severe("Failed to create valid config."); return null; } remoteConfigPath = testDrive.pushConfig(config, testDrive.mDeviceSerial); LOGGER.info("Pushed the following config to statsd:"); String remoteConfigPath = null; try { remoteConfigPath = pushConfig(config, mDeviceSerial); LOGGER.info("Pushed the following config to statsd on device '" + mDeviceSerial + "':"); LOGGER.info(config.toString()); if (!hasPulledAtom(trackedAtoms)) { if (hasPushedAtoms) { LOGGER.info("Now please play with the device to trigger the event."); } if (!hasPulledAtoms) { LOGGER.info( "Now please play with the device to trigger the event. All events should " + "be dumped after 1 min ..."); "All events should be dumped after 1 min ..."); Thread.sleep(60_000); } else { LOGGER.info("Now wait for 1.5 minutes ..."); LOGGER.info("All events should be dumped after 1.5 minutes ..."); Thread.sleep(15_000); Utils.logAppBreadcrumb(0, 0, LOGGER, testDrive.mDeviceSerial); Utils.logAppBreadcrumb(0, 0, LOGGER, mDeviceSerial); Thread.sleep(75_000); } testDrive.dumpMetrics(); return Utils.getReportList(CONFIG_ID, true, false, LOGGER, mDeviceSerial); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to test drive: " + e.getMessage(), e); } finally { testDrive.removeConfig(testDrive.mDeviceSerial); removeConfig(mDeviceSerial); if (remoteConfigPath != null) { try { Utils.runCommand(null, LOGGER, "adb", "-s", testDrive.mDeviceSerial, "shell", "rm", remoteConfigPath); "adb", "-s", mDeviceSerial, "shell", "rm", remoteConfigPath); } catch (Exception e) { LOGGER.log(Level.WARNING, "Unable to remove remote config file: " + remoteConfigPath, e); } } } return null; } private void dumpMetrics() throws Exception { ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, LOGGER, mDeviceSerial); static class Configuration { boolean mOnePushedAtomEvent = false; @VisibleForTesting Set<Integer> mPushedAtoms = new TreeSet<>(); @VisibleForTesting Set<Integer> mPulledAtoms = new TreeSet<>(); @VisibleForTesting String mAdditionalAllowedPackage = null; private final Set<Long> mTrackedMetrics = new HashSet<>(); private void dumpMetrics(ConfigMetricsReportList reportList) { // We may get multiple reports. Take the last one. ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1); for (StatsLogReport statsLog : report.getMetricsList()) { if (mTrackedMetrics.contains(statsLog.getMetricId())) { if (isTrackedMetric(statsLog.getMetricId())) { LOGGER.info(statsLog.toString()); } } } private StatsdConfig createConfig(Set<Integer> atomIds) { long metricId = METRIC_ID_BASE; long atomMatcherId = ATOM_MATCHER_ID_BASE; boolean isTrackedMetric(long metricId) { return mTrackedMetrics.contains(metricId); } ArrayList<String> allowedSources = new ArrayList<>(); Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES); if (mAdditionalAllowedPackage != null) { allowedSources.add(mAdditionalAllowedPackage); static boolean isPulledAtom(int atomId) { return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG || atomId >= VENDOR_PULLED_ATOM_START_TAG; } StatsdConfig.Builder builder = StatsdConfig.newBuilder(); builder .addAllAllowedLogSource(allowedSources) .addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES)) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER) .addPackages("AID_STATSD")) .setHashStringsInMetricReport(false); void addAtom(Integer atom) { if (Atom.getDescriptor().findFieldByNumber(atom) == null) { LOGGER.severe("No such atom found: " + atom); return; } if (isPulledAtom(atom)) { mPulledAtoms.add(atom); } else { mPushedAtoms.add(atom); } } if (hasPulledAtom(atomIds)) { private boolean hasPulledAtoms() { return !mPulledAtoms.isEmpty(); } private boolean hasPushedAtoms() { return !mPushedAtoms.isEmpty(); } StatsdConfig createConfig() { long metricId = METRIC_ID_BASE; long atomMatcherId = ATOM_MATCHER_ID_BASE; StatsdConfig.Builder builder = baseBuilder(); if (hasPulledAtoms()) { builder.addAtomMatcher( createAtomMatcher( Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, APP_BREADCRUMB_MATCHER_ID)); Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, APP_BREADCRUMB_MATCHER_ID)); } for (int atomId : atomIds) { if (isPulledAtom(atomId)) { for (int atomId : mPulledAtoms) { builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); GaugeMetric.Builder gaugeMetricBuilder = GaugeMetric.newBuilder(); gaugeMetricBuilder Loading @@ -226,17 +262,39 @@ public class TestDrive { .setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES) .setMaxNumGaugeAtomsPerBucket(100); builder.addGaugeMetric(gaugeMetricBuilder.build()); atomMatcherId++; mTrackedMetrics.add(metricId++); } // A simple atom matcher for each pushed atom. List<AtomMatcher> simpleAtomMatchers = new ArrayList<>(); for (int atomId : mPushedAtoms) { final AtomMatcher atomMatcher = createAtomMatcher(atomId, atomMatcherId++); simpleAtomMatchers.add(atomMatcher); builder.addAtomMatcher(atomMatcher); } if (mOnePushedAtomEvent) { // Create a union event metric, using an matcher that matches all pulled atoms. AtomMatcher unionAtomMatcher = createUnionMatcher(simpleAtomMatchers, atomMatcherId); builder.addAtomMatcher(unionAtomMatcher); EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder(); eventMetricBuilder.setId(metricId).setWhat(unionAtomMatcher.getId()); builder.addEventMetric(eventMetricBuilder.build()); mTrackedMetrics.add(metricId++); } else { // Create multiple event metrics, one per pulled atom. for (AtomMatcher atomMatcher : simpleAtomMatchers) { EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder(); eventMetricBuilder .setId(metricId) .setWhat(atomMatcherId); .setWhat(atomMatcher.getId()); builder.addEventMetric(eventMetricBuilder.build()); builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); } atomMatcherId++; mTrackedMetrics.add(metricId++); } } return builder.build(); } Loading @@ -248,6 +306,41 @@ public class TestDrive { return atomMatcherBuilder.build(); } private AtomMatcher createUnionMatcher(List<AtomMatcher> simpleAtomMatchers, long atomMatcherId) { AtomMatcher.Combination.Builder combinationBuilder = AtomMatcher.Combination.newBuilder(); combinationBuilder.setOperation(StatsdConfigProto.LogicalOperation.OR); for (AtomMatcher matcher : simpleAtomMatchers) { combinationBuilder.addMatcher(matcher.getId()); } AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder(); atomMatcherBuilder.setId(atomMatcherId).setCombination(combinationBuilder.build()); return atomMatcherBuilder.build(); } private StatsdConfig.Builder baseBuilder() { ArrayList<String> allowedSources = new ArrayList<>(); Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES); if (mAdditionalAllowedPackage != null) { allowedSources.add(mAdditionalAllowedPackage); } return StatsdConfig.newBuilder() .addAllAllowedLogSource(allowedSources) .addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES)) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER) .addPackages("AID_GPU_SERVICE")) .addPullAtomPackages(PullAtomPackages.newBuilder() .setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER) .addPackages("AID_STATSD")) .setHashStringsInMetricReport(false); } } private static String pushConfig(StatsdConfig config, String deviceSerial) throws IOException, InterruptedException { File configFile = File.createTempFile("statsdconfig", ".config"); Loading @@ -267,21 +360,7 @@ public class TestDrive { Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial, "shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID)); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to remove config: " + e.getMessage()); } } private static boolean isPulledAtom(int atomId) { return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG || atomId >= VENDOR_PULLED_ATOM_START_TAG; LOGGER.severe("Failed to remove config: " + e.getMessage()); } private static boolean hasPulledAtom(Set<Integer> atoms) { for (Integer i : atoms) { if (isPulledAtom(i)) { return true; } } return false; } }