Bug 1460399 - Miscellaneous refactoring in android_emulator_unittest.py; r=me,a=test-only
authorGeoff Brown <gbrown@mozilla.com>
Thu, 17 May 2018 16:19:00 -0600
changeset 418785 8fe97d20da6f
parent 418784 5428125d8636
child 418786 94304ecaaadf
push id34013
push userdluca@mozilla.com
push date2018-05-18 09:56 +0000
treeherdermozilla-central@11ee70f24ea5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme, test-only
bugs1460399
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1460399 - Miscellaneous refactoring in android_emulator_unittest.py; r=me,a=test-only Also moved more diagnostic information into separate artifacts, to declutter the main test log.
testing/mozharness/scripts/android_emulator_unittest.py
--- a/testing/mozharness/scripts/android_emulator_unittest.py
+++ b/testing/mozharness/scripts/android_emulator_unittest.py
@@ -25,16 +25,22 @@ from mozharness.base.log import FATAL
 from mozharness.base.script import BaseScript, PreScriptAction, PostScriptAction
 from mozharness.mozilla.buildbot import TBPL_RETRY, EXIT_STATUS_DICT
 from mozharness.mozilla.mozbase import MozbaseMixin
 from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
 from mozharness.mozilla.testing.codecoverage import CodeCoverageMixin
 
 
 class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMixin):
+    """
+       A mozharness script for Android functional tests (like mochitests and reftests)
+       run on an Android emulator. This script starts and manages an Android emulator
+       for the duration of the required tests. This is like desktop_unittest.py, but
+       for Android emulator test platforms.
+    """
     config_options = [[
         ["--test-suite"],
         {"action": "store",
          "dest": "test_suite",
          "default": None
          }
     ], [
         ["--total-chunk"],
@@ -66,18 +72,16 @@ class AndroidEmulatorTest(TestingMixin, 
                          'install',
                          'run-tests',
                          ],
             require_config_file=require_config_file,
             config={
                 'virtualenv_modules': [],
                 'virtualenv_requirements': [],
                 'require_test_zip': True,
-                # IP address of the host as seen from the emulator
-                'remote_webserver': '10.0.2.2',
             }
         )
 
         # these are necessary since self.config is read only
         c = self.config
         abs_dirs = self.query_abs_dirs()
         self.adb_path = self.query_exe('adb')
         self.installer_url = c.get('installer_url')
@@ -95,24 +99,16 @@ class AndroidEmulatorTest(TestingMixin, 
             m = re.match("(.*)-(\d*)", self.test_suite)
             if m:
                 self.test_suite = m.group(1)
                 if self.this_chunk is None:
                     self.this_chunk = m.group(2)
         self.sdk_level = None
         self.xre_path = None
 
-    def _query_tests_dir(self):
-        dirs = self.query_abs_dirs()
-        try:
-            test_dir = self.config["suite_definitions"][self.test_suite]["testsdir"]
-        except Exception:
-            test_dir = self.test_suite
-        return os.path.join(dirs['abs_test_install_dir'], test_dir)
-
     def query_abs_dirs(self):
         if self.abs_dirs:
             return self.abs_dirs
         abs_dirs = super(AndroidEmulatorTest, self).query_abs_dirs()
         dirs = {}
         dirs['abs_test_install_dir'] = os.path.join(
             abs_dirs['abs_work_dir'], 'tests')
         dirs['abs_test_bin_dir'] = os.path.join(
@@ -137,16 +133,49 @@ class AndroidEmulatorTest(TestingMixin, 
         dirs['abs_avds_dir'] = self.config.get("avds_dir", "/home/cltbld/.android")
 
         for key in dirs.keys():
             if key not in abs_dirs:
                 abs_dirs[key] = dirs[key]
         self.abs_dirs = abs_dirs
         return self.abs_dirs
 
+    def _query_tests_dir(self, test_suite):
+        dirs = self.query_abs_dirs()
+        try:
+            test_dir = self.config["suite_definitions"][test_suite]["testsdir"]
+        except Exception:
+            test_dir = test_suite
+        return os.path.join(dirs['abs_test_install_dir'], test_dir)
+
+    def _query_package_name(self):
+        if self.app_name is None:
+            # For convenience, assume geckoview.test/geckoview_example when install
+            # target looks like geckoview.
+            if 'androidTest' in self.installer_path:
+                self.app_name = 'org.mozilla.geckoview.test'
+            elif 'geckoview' in self.installer_path:
+                self.app_name = 'org.mozilla.geckoview_example'
+        if self.app_name is None:
+            # Find appname from package-name.txt - assumes download-and-extract
+            # has completed successfully.
+            # The app/package name will typically be org.mozilla.fennec,
+            # but org.mozilla.firefox for release builds, and there may be
+            # other variations. 'aapt dump badging <apk>' could be used as an
+            # alternative to package-name.txt, but introduces a dependency
+            # on aapt, found currently in the Android SDK build-tools component.
+            apk_dir = self.abs_dirs['abs_work_dir']
+            self.apk_path = os.path.join(apk_dir, self.installer_path)
+            unzip = self.query_exe("unzip")
+            package_path = os.path.join(apk_dir, 'package-name.txt')
+            unzip_cmd = [unzip, '-q', '-o',  self.apk_path]
+            self.run_command(unzip_cmd, cwd=apk_dir, halt_on_failure=True)
+            self.app_name = str(self.read_from_file(package_path, verbose=True)).rstrip()
+        return self.app_name
+
     def _launch_emulator(self):
         env = self.query_env()
 
         # Write a default ddms.cfg to avoid unwanted prompts
         avd_home_dir = self.abs_dirs['abs_avds_dir']
         DDMS_FILE = os.path.join(avd_home_dir, "ddms.cfg")
         with open(DDMS_FILE, 'w') as f:
             f.write("pingOptIn=false\npingId=0\n")
@@ -187,23 +216,24 @@ class AndroidEmulatorTest(TestingMixin, 
                 self.run_command(["emulator", "-accel-check"], env=env)
             except Exception as e:
                 self.warning("Extra kvm diagnostics failed: %s" % str(e))
 
         command = ["emulator", "-avd", self.emulator["name"]]
         if "emulator_extra_args" in self.config:
             command += self.config["emulator_extra_args"].split()
 
-        tmp_file = tempfile.NamedTemporaryFile(mode='w')
-        tmp_stdout = open(tmp_file.name, 'w')
-        self.info("Trying to start the emulator with this command: %s" % ' '.join(command))
-        proc = subprocess.Popen(command, stdout=tmp_stdout, stderr=tmp_stdout, env=env)
+        dir = self.query_abs_dirs()['abs_blob_upload_dir']
+        tmp_file = tempfile.NamedTemporaryFile(mode='w', prefix='emulator-',
+                                               suffix='.log', dir=dir, delete=False)
+        self.info("Launching the emulator with: %s" % ' '.join(command))
+        self.info("Writing log to %s" % tmp_file.name)
+        proc = subprocess.Popen(command, stdout=tmp_file, stderr=tmp_file, env=env)
         return {
             "process": proc,
-            "tmp_file": tmp_file,
         }
 
     def _retry(self, max_attempts, interval, func, description, max_time=0):
         '''
         Execute func until it returns True, up to max_attempts times, waiting for
         interval seconds between each attempt. description is logged on each attempt.
         If max_time is specified, no further attempts will be made once max_time
         seconds have elapsed; this provides some protection for the case where
@@ -227,16 +257,20 @@ class AndroidEmulatorTest(TestingMixin, 
             self.info(">> %s: Attempt #%d of %d" % (description, attempts, max_attempts))
             status = func()
         return status
 
     def _run_with_timeout(self, timeout, cmd, quiet=False):
         timeout_cmd = ['timeout', '%s' % timeout] + cmd
         return self._run_proc(timeout_cmd, quiet=quiet)
 
+    def _run_adb_with_timeout(self, timeout, cmd, quiet=False):
+        cmd = [self.adb_path, '-s', self.emulator['device_id']] + cmd
+        return self._run_with_timeout(timeout, cmd, quiet)
+
     def _run_proc(self, cmd, quiet=False):
         self.info('Running %s' % subprocess.list2cmdline(cmd))
         p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         out, err = p.communicate()
         if out and not quiet:
             self.info('%s' % str(out.strip()))
         if err and not quiet:
             self.info('stderr: %s' % str(err.strip()))
@@ -249,19 +283,18 @@ class AndroidEmulatorTest(TestingMixin, 
 
     def _verify_adb_device(self):
         out, _ = self._run_with_timeout(30, [self.adb_path, 'devices'])
         if (self.emulator['device_id'] in out) and ("device" in out):
             return True
         return False
 
     def _is_boot_completed(self):
-        boot_cmd = [self.adb_path, '-s', self.emulator['device_id'],
-                    'shell', 'getprop', 'sys.boot_completed']
-        out, _ = self._run_with_timeout(30, boot_cmd)
+        boot_cmd = ['shell', 'getprop', 'sys.boot_completed']
+        out, _ = self._run_adb_with_timeout(30, boot_cmd)
         if out.strip() == '1':
             return True
         return False
 
     def _verify_emulator(self):
         adb_ok = self._verify_adb()
         if not adb_ok:
             self.warning('Unable to communicate with adb')
@@ -277,150 +310,105 @@ class AndroidEmulatorTest(TestingMixin, 
         if not boot_ok:
             self.warning('Unable to verify Android boot completion')
             return False
         return True
 
     def _verify_emulator_and_restart_on_fail(self):
         emulator_ok = self._verify_emulator()
         if not emulator_ok:
-            self._dump_host_state()
             self._screenshot("emulator-startup-screenshot-")
             self._kill_processes(self.config["emulator_process_name"])
             self._run_proc(['ps', '-ef'])
-            self._dump_emulator_log()
             # remove emulator tmp files
             for dir in glob.glob("/tmp/android-*"):
                 self.rmtree(dir)
             self._restart_adbd()
             time.sleep(5)
             self.emulator_proc = self._launch_emulator()
         return emulator_ok
 
     def _install_target_apk(self):
         install_ok = False
         if int(self.sdk_level) >= 23:
-            cmd = [self.adb_path, '-s', self.emulator['device_id'], 'install', '-r', '-g',
-                   self.installer_path]
+            cmd = ['install', '-r', '-g', self.installer_path]
         else:
-            cmd = [self.adb_path, '-s', self.emulator['device_id'], 'install', '-r',
-                   self.installer_path]
-        out, err = self._run_with_timeout(300, cmd, True)
+            cmd = ['install', '-r', self.installer_path]
+        out, err = self._run_adb_with_timeout(300, cmd, True)
         if 'Success' in out or 'Success' in err:
             install_ok = True
         return install_ok
 
     def _install_robocop_apk(self):
         install_ok = False
         if int(self.sdk_level) >= 23:
-            cmd = [self.adb_path, '-s', self.emulator['device_id'], 'install', '-r', '-g',
-                   self.robocop_path]
+            cmd = ['install', '-r', '-g', self.robocop_path]
         else:
-            cmd = [self.adb_path, '-s', self.emulator['device_id'], 'install', '-r',
-                   self.robocop_path]
-        out, err = self._run_with_timeout(300, cmd, True)
+            cmd = ['install', '-r', self.robocop_path]
+        out, err = self._run_adb_with_timeout(300, cmd, True)
         if 'Success' in out or 'Success' in err:
             install_ok = True
         return install_ok
 
-    def _dump_host_state(self):
-        self._run_proc(['ps', '-ef'])
-        self._run_proc(['netstat', '-a', '-p', '-n', '-t', '-u'])
-
-    def _dump_emulator_log(self):
-        self.info("##### %s emulator log begins" % self.emulator["name"])
-        output = self.read_from_file(self.emulator_proc["tmp_file"].name, verbose=False)
-        if output:
-            self.info(output)
-        self.info("##### %s emulator log ends" % self.emulator["name"])
-
     def _kill_processes(self, process_name):
         p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
         out, err = p.communicate()
-        self.info("Let's kill every process called %s" % process_name)
+        self.info("Killing every process called %s" % process_name)
         for line in out.splitlines():
             if process_name in line:
                 pid = int(line.split(None, 1)[0])
                 self.info("Killing pid %d." % pid)
                 os.kill(pid, signal.SIGKILL)
 
     def _restart_adbd(self):
         self._run_with_timeout(30, [self.adb_path, 'kill-server'])
         self._run_with_timeout(30, [self.adb_path, 'root'])
 
     def _screenshot(self, prefix):
         """
-           Save a screenshot of the entire screen to the blob upload directory.
+           Save a screenshot of the entire screen to the upload directory.
         """
         dirs = self.query_abs_dirs()
         utility = os.path.join(self.xre_path, "screentopng")
         if not os.path.exists(utility):
             self.warning("Unable to take screenshot: %s does not exist" % utility)
             return
         try:
             tmpfd, filename = tempfile.mkstemp(prefix=prefix, suffix='.png',
                                                dir=dirs['abs_blob_upload_dir'])
             os.close(tmpfd)
             self.info("Taking screenshot with %s; saving to %s" % (utility, filename))
             subprocess.call([utility, filename], env=self.query_env())
         except OSError, err:
             self.warning("Failed to take screenshot: %s" % err.strerror)
 
-    def _query_package_name(self):
-        if self.app_name is None:
-            # For convenience, assume geckoview.test/geckoview_example when install
-            # target looks like geckoview.
-            if 'androidTest' in self.installer_path:
-                self.app_name = 'org.mozilla.geckoview.test'
-            elif 'geckoview' in self.installer_path:
-                self.app_name = 'org.mozilla.geckoview_example'
-        if self.app_name is None:
-            # Find appname from package-name.txt - assumes download-and-extract
-            # has completed successfully.
-            # The app/package name will typically be org.mozilla.fennec,
-            # but org.mozilla.firefox for release builds, and there may be
-            # other variations. 'aapt dump badging <apk>' could be used as an
-            # alternative to package-name.txt, but introduces a dependency
-            # on aapt, found currently in the Android SDK build-tools component.
-            apk_dir = self.abs_dirs['abs_work_dir']
-            self.apk_path = os.path.join(apk_dir, self.installer_path)
-            unzip = self.query_exe("unzip")
-            package_path = os.path.join(apk_dir, 'package-name.txt')
-            unzip_cmd = [unzip, '-q', '-o',  self.apk_path]
-            self.run_command(unzip_cmd, cwd=apk_dir, halt_on_failure=True)
-            self.app_name = str(self.read_from_file(package_path, verbose=True)).rstrip()
-        return self.app_name
-
-    def preflight_install(self):
-        # in the base class, this checks for mozinstall, but we don't use it
-        pass
-
     def _build_command(self):
         c = self.config
         dirs = self.query_abs_dirs()
 
         if self.test_suite not in self.config["suite_definitions"]:
             self.fatal("Key '%s' not defined in the config!" % self.test_suite)
 
         cmd = [
             self.query_python_path('python'),
             '-u',
             os.path.join(
-                self._query_tests_dir(),
+                self._query_tests_dir(self.test_suite),
                 self.config["suite_definitions"][self.test_suite]["run_filename"]
             ),
         ]
 
         raw_log_file = os.path.join(dirs['abs_blob_upload_dir'],
                                     '%s_raw.log' % self.test_suite)
 
         error_summary_file = os.path.join(dirs['abs_blob_upload_dir'],
                                           '%s_errorsummary.log' % self.test_suite)
         str_format_values = {
-            'remote_webserver': c['remote_webserver'],
+            # IP address of the host as seen from the emulator
+            'remote_webserver': '10.0.2.2',
             'xre_path': self.xre_path,
             'utility_path': self.xre_path,
             'certs_path': os.path.join(dirs['abs_work_dir'], 'tests/certs'),
             # TestingMixin._download_and_extract_symbols() will set
             # self.symbols_path when downloading/extracting.
             'symbols_path': self.symbols_path,
             'modules_dir': dirs['abs_modules_dir'],
             'installer_path': self.installer_path,
@@ -500,17 +488,16 @@ class AndroidEmulatorTest(TestingMixin, 
             self.fatal("Could not retrieve manifest needed to retrieve "
                        "artifacts from %s" % manifest_path)
         cache = self.config.get("tooltool_cache", None)
         if self.tooltool_fetch(manifest_path, output_dir=dir, cache=cache):
             self.warning("Unable to download from tooltool: %s" % url)
 
     def _install_emulator(self):
         dirs = self.query_abs_dirs()
-        self.mkdir_p(dirs['abs_work_dir'])
         if self.config.get('emulator_url'):
             self.download_unpack(self.config['emulator_url'], dirs['abs_work_dir'])
         elif self.config.get('emulator_manifest'):
             manifest_path = self.create_tooltool_manifest(self.config['emulator_manifest'])
             dirs = self.query_abs_dirs()
             cache = self.config.get("tooltool_cache", None)
             if self.tooltool_fetch(manifest_path,
                                    output_dir=dirs['abs_work_dir'],
@@ -537,33 +524,34 @@ class AndroidEmulatorTest(TestingMixin, 
             f.write('\n\nHost /proc/meminfo:\n')
             out, _ = self._run_proc(['cat', '/proc/meminfo'], quiet=True)
             f.write(out)
 
             f.write('\n\nHost process list:\n')
             out, _ = self._run_proc(['ps', '-ef'], quiet=True)
             f.write(out)
 
+            f.write('\n\nHost netstat:\n')
+            out, _ = self._run_proc(['netstat', '-a', '-p', '-n', '-t', '-u'], quiet=True)
+            f.write(out)
+
             f.write('\n\nEmulator /proc/cpuinfo:\n')
-            cmd = [self.adb_path, '-s', self.emulator['device_id'],
-                   'shell', 'cat', '/proc/cpuinfo']
-            out, _ = self._run_with_timeout(30, cmd, quiet=True)
+            cmd = ['shell', 'cat', '/proc/cpuinfo']
+            out, _ = self._run_adb_with_timeout(30, cmd, quiet=True)
             f.write(out)
             cpuinfo = out
 
             f.write('\n\nEmulator /proc/meminfo:\n')
-            cmd = [self.adb_path, '-s', self.emulator['device_id'],
-                   'shell', 'cat', '/proc/meminfo']
-            out, _ = self._run_with_timeout(30, cmd, quiet=True)
+            cmd = ['shell', 'cat', '/proc/meminfo']
+            out, _ = self._run_adb_with_timeout(30, cmd, quiet=True)
             f.write(out)
 
             f.write('\n\nEmulator process list:\n')
-            cmd = [self.adb_path, '-s', self.emulator['device_id'],
-                   'shell', 'ps']
-            out, _ = self._run_with_timeout(30, cmd, quiet=True)
+            cmd = ['shell', 'ps']
+            out, _ = self._run_adb_with_timeout(30, cmd, quiet=True)
             f.write(out)
 
         # Search android cpuinfo for "BogoMIPS"; if found and < 250, retry
         # this task, in hopes of getting a higher-powered environment.
         # (Carry on silently if BogoMIPS is not found -- this may vary by
         # Android implementation -- no big deal.)
         # See bug 1321605: Sometimes the emulator is really slow, and
         # low bogomips can be a good predictor of that condition.
@@ -603,16 +591,20 @@ class AndroidEmulatorTest(TestingMixin, 
             # per-test mode
             categories = ['mochitest', 'reftest', 'xpcshell']
         return categories
 
     ##########################################
     # Actions for AndroidEmulatorTest        #
     ##########################################
 
+    def preflight_install(self):
+        # in the base class, this checks for mozinstall, but we don't use it
+        pass
+
     @PreScriptAction('create-virtualenv')
     def pre_create_virtualenv(self, action):
         dirs = self.query_abs_dirs()
         requirements = None
         if self.test_suite == 'mochitest-media':
             # mochitest-media is the only thing that needs this
             requirements = os.path.join(dirs['abs_mochitest_dir'],
                                         'websocketprocessbridge',
@@ -627,16 +619,18 @@ class AndroidEmulatorTest(TestingMixin, 
     def setup_avds(self):
         '''
         If tooltool cache mechanism is enabled, the cached version is used by
         the fetch command. If the manifest includes an "unpack" field, tooltool
         will unpack all compressed archives mentioned in the manifest.
         '''
         c = self.config
         dirs = self.query_abs_dirs()
+        self.mkdir_p(dirs['abs_work_dir'])
+        self.mkdir_p(dirs['abs_blob_upload_dir'])
 
         # Always start with a clean AVD: AVD includes Android images
         # which can be stateful.
         self.rmtree(dirs['abs_avds_dir'])
         self.mkdir_p(dirs['abs_avds_dir'])
         if 'avd_url' in c:
             # Intended for experimental setups to evaluate an avd prior to
             # tooltool deployment.
@@ -674,37 +668,36 @@ class AndroidEmulatorTest(TestingMixin, 
 
         self.emulator_proc = self._launch_emulator()
 
     def verify_emulator(self):
         '''
         Check to see if the emulator can be contacted via adb.
         If any communication attempt fails, kill the emulator, re-launch, and re-check.
         '''
-        self.mkdir_p(self.query_abs_dirs()['abs_blob_upload_dir'])
         max_restarts = 5
         emulator_ok = self._retry(max_restarts, 10, self._verify_emulator_and_restart_on_fail,
                                   "Check emulator")
         if not emulator_ok:
             self.fatal('INFRA-ERROR: Unable to start emulator after %d attempts' % max_restarts,
                        EXIT_STATUS_DICT[TBPL_RETRY])
         self._dump_perf_info()
         # Start logcat for the emulator. The adb process runs until the
         # corresponding emulator is killed. Output is written directly to
-        # the blobber upload directory so that it is uploaded automatically
+        # the upload directory so that it is uploaded automatically
         # at the end of the job.
         logcat_filename = 'logcat-%s.log' % self.emulator["device_id"]
         logcat_path = os.path.join(self.abs_dirs['abs_blob_upload_dir'], logcat_filename)
         logcat_cmd = '%s -s %s logcat -v threadtime Trace:S StrictMode:S '\
             ' ExchangeService:S > %s &' % (self.adb_path, self.emulator["device_id"], logcat_path)
         self.info(logcat_cmd)
         os.system(logcat_cmd)
         # Get a post-boot emulator process list for diagnostics
-        ps_cmd = [self.adb_path, '-s', self.emulator["device_id"], 'shell', 'ps']
-        self._run_with_timeout(30, ps_cmd)
+        ps_cmd = ['shell', 'ps']
+        self._run_adb_with_timeout(30, ps_cmd)
 
     def download_and_extract(self):
         """
         Download and extract fennec APK, tests.zip, host utils, and robocop (if required).
         """
         super(AndroidEmulatorTest, self).download_and_extract(
             suite_categories=self._query_suite_categories())
         dirs = self.query_abs_dirs()
@@ -733,19 +726,18 @@ class AndroidEmulatorTest(TestingMixin, 
             self.config["suite_definitions"][self.test_suite].get("install")
         if install_needed is False:
             self.info("Skipping apk installation for %s" % self.test_suite)
             return
 
         assert self.installer_path is not None, \
             "Either add installer_path to the config or use --installer-path."
 
-        cmd = [self.adb_path, '-s', self.emulator['device_id'], 'shell',
-               'getprop', 'ro.build.version.sdk']
-        self.sdk_level, _ = self._run_with_timeout(30, cmd)
+        cmd = ['shell', 'getprop', 'ro.build.version.sdk']
+        self.sdk_level, _ = self._run_adb_with_timeout(30, cmd)
 
         # Install Fennec
         install_ok = self._retry(3, 30, self._install_target_apk, "Install app APK")
         if not install_ok:
             self.fatal('INFRA-ERROR: Failed to install %s on %s' %
                        (self.installer_path, self.emulator["name"]),
                        EXIT_STATUS_DICT[TBPL_RETRY])
 
@@ -769,20 +761,17 @@ class AndroidEmulatorTest(TestingMixin, 
         per_test_args = []
         suites = self._query_suites()
         minidump = self.query_minidump_stackwalk()
         for (per_test_suite, suite) in suites:
             self.test_suite = suite
 
             cmd = self._build_command()
 
-            try:
-                cwd = self._query_tests_dir()
-            except Exception:
-                self.fatal("Don't know how to run --test-suite '%s'!" % self.test_suite)
+            cwd = self._query_tests_dir(self.test_suite)
             env = self.query_env()
             if minidump:
                 env['MINIDUMP_STACKWALK'] = minidump
             env['MOZ_UPLOAD_DIR'] = self.query_abs_dirs()['abs_blob_upload_dir']
             env['MINIDUMP_SAVE_PATH'] = self.query_abs_dirs()['abs_blob_upload_dir']
             env['RUST_BACKTRACE'] = 'full'
 
             summary = None
@@ -800,18 +789,17 @@ class AndroidEmulatorTest(TestingMixin, 
                 final_cmd = copy.copy(cmd)
                 if len(per_test_args) > 0:
                     # in per-test mode, remove any chunk arguments from command
                     for arg in final_cmd:
                         if 'total-chunk' in arg or 'this-chunk' in arg:
                             final_cmd.remove(arg)
                 final_cmd.extend(per_test_args)
 
-                self.info("Running on %s the command %s" % (self.emulator["name"],
-                          subprocess.list2cmdline(final_cmd)))
+                self.info("Running the command %s" % subprocess.list2cmdline(final_cmd))
                 self.info("##### %s log begins" % self.test_suite)
 
                 suite_category = self.test_suite
                 parser = self.get_test_output_parser(
                     suite_category,
                     config=self.config,
                     log_obj=self.log_obj,
                     error_list=[])