Example #1
0
 def _get_online_devices(self):
     adbhost = ADBHost()
     devices = adbhost.devices()
     return [
         d['device_serial'] for d in devices if d['state'] != 'offline'
         if not d['device_serial'].startswith('emulator')
     ]
Example #2
0
 def _get_online_devices(self):
     adbhost = ADBHost(adb=self.app_ctx.adb)
     return [
         d['device_serial'] for d in adbhost.devices()
         if d['state'] != 'offline'
         if d['device_serial'].startswith('emulator')
     ]
Example #3
0
 def _get_online_devices(self):
     adbhost = ADBHost(adb=self.app_ctx.adb)
     return [
         d["device_serial"] for d in adbhost.devices()
         if d["state"] != "offline"
         if d["device_serial"].startswith("emulator")
     ]
Example #4
0
 def _get_device_status(self):
     self.adbhost = ADBHost()
     if self.adbhost.devices():
         return True
     if "y" == raw_input("WARNING: no device connected."
                         " Connect a device and try again.\n"
                         "Try again? (y or n): "):
         return self.get_device_status()
     raise Exception("Aborting!")
Example #5
0
    def wait_for_start(self):
        """
           Verify that the emulator is running, the emulator device is visible
           to adb, and Android has booted.
        """
        if not self.proc:
            _log_warning("Emulator not started!")
            return False
        if self.check_completed():
            return False
        _log_debug("Waiting for device status...")
        adb_path = _find_sdk_exe(self.substs, 'adb', False)
        if not adb_path:
            adb_path = 'adb'
        adbhost = ADBHost(adb=adb_path,
                          verbose=verbose_logging,
                          timeout=SHORT_TIMEOUT)
        devs = adbhost.devices(timeout=SHORT_TIMEOUT)
        devs = [(d['device_serial'], d['state']) for d in devs]
        while ('emulator-5554', 'device') not in devs:
            time.sleep(10)
            if self.check_completed():
                return False
            devs = adbhost.devices(timeout=SHORT_TIMEOUT)
            devs = [(d['device_serial'], d['state']) for d in devs]
        _log_debug("Device status verified.")

        _log_debug("Checking that Android has booted...")
        device = _get_device(self.substs, self.device_serial)
        complete = False
        while not complete:
            output = ''
            try:
                output = device.get_prop('sys.boot_completed', timeout=5)
            except Exception:
                # adb not yet responding...keep trying
                pass
            if output.strip() == '1':
                complete = True
            else:
                time.sleep(10)
                if self.check_completed():
                    return False
        _log_debug("Android boot status verified.")

        if not self._verify_emulator():
            return False
        if self.avd_info.x86:
            _log_info(
                "Running the x86/x86_64 emulator; be sure to install an x86 or x86_64 APK!"
            )
        else:
            _log_info(
                "Running the arm emulator; be sure to install an arm APK!")
        return True
 def is_running(self):
     """
        Returns True if the Android emulator is running.
     """
     adb_path = _find_sdk_exe(self.substs, 'adb', False)
     if not adb_path:
         adb_path = 'adb'
     adbhost = ADBHost(adb=adb_path, verbose=verbose_logging, timeout=SHORT_TIMEOUT)
     devs = adbhost.devices(timeout=SHORT_TIMEOUT)
     devs = [(d['device_serial'], d['state']) for d in devs]
     _log_debug(devs)
     if ('emulator-5554', 'device') in devs:
         return True
     return False
Example #7
0
    def run_raptor_test(self, **kwargs):

        build_obj = MozbuildObject.from_environment(cwd=HERE)

        firefox_android_browsers = ["fennec", "geckoview", "refbrow", "fenix"]

        if conditions.is_android(
                build_obj) or kwargs['app'] in firefox_android_browsers:
            from mozrunner.devices.android_device import verify_android_device
            from mozdevice import ADBAndroid, ADBHost
            if not verify_android_device(
                    build_obj, install=True, app=kwargs['binary'],
                    xre=True):  # Equivalent to 'run_local' = True.
                return 1

        debug_command = '--debug-command'
        if debug_command in sys.argv:
            sys.argv.remove(debug_command)

        raptor = self._spawn(RaptorRunner)

        try:
            if kwargs['app'] in firefox_android_browsers and kwargs[
                    'power_test']:
                device = ADBAndroid(verbose=True)
                adbhost = ADBHost(verbose=True)
                device_serial = "%s:5555" % device.get_ip_address()
                device.command_output(["tcpip", "5555"])
                raw_input(
                    "Please disconnect your device from USB then press Enter/return..."
                )
                adbhost.command_output(["connect", device_serial])
                while len(adbhost.devices()) > 1:
                    raw_input(
                        "You must disconnect your device from USB before continuing."
                    )
                # must reset the environment DEVICE_SERIAL which was set during
                # verify_android_device to match our new tcpip value.
                os.environ["DEVICE_SERIAL"] = device_serial
            return raptor.run_test(sys.argv[2:], kwargs)
        except Exception as e:
            print(repr(e))
            return 1
        finally:
            try:
                if kwargs['app'] in firefox_android_browsers and kwargs[
                        'power_test']:
                    raw_input(
                        "Connect device via USB and press Enter/return...")
                    device = ADBAndroid(device=device_serial, verbose=True)
                    device.command_output(["usb"])
                    adbhost.command_output(["disconnect", device_serial])
            except Exception:
                adbhost.command_output(["kill-server"])
Example #8
0
    def run_raptor(self, **kwargs):
        build_obj = self

        is_android = Conditions.is_android(build_obj) or \
            kwargs['app'] in FIREFOX_ANDROID_BROWSERS

        if is_android:
            from mozrunner.devices.android_device import (
                verify_android_device, InstallIntent)
            from mozdevice import ADBAndroid, ADBHost
            install = InstallIntent.NO if kwargs.pop(
                'noinstall', False) else InstallIntent.PROMPT
            if not verify_android_device(
                    build_obj, install=install, app=kwargs['binary'],
                    xre=True):  # Equivalent to 'run_local' = True.
                return 1

        debug_command = '--debug-command'
        if debug_command in sys.argv:
            sys.argv.remove(debug_command)

        raptor = self._spawn(RaptorRunner)

        try:
            if is_android and kwargs['power_test']:
                device = ADBAndroid(verbose=True)
                adbhost = ADBHost(verbose=True)
                device_serial = "{}:5555".format(device.get_ip_address())
                device.command_output(["tcpip", "5555"])
                six.input(
                    "Please disconnect your device from USB then press Enter/return..."
                )
                adbhost.command_output(["connect", device_serial])
                while len(adbhost.devices()) > 1:
                    six.input(
                        "You must disconnect your device from USB before continuing."
                    )
                # must reset the environment DEVICE_SERIAL which was set during
                # verify_android_device to match our new tcpip value.
                os.environ["DEVICE_SERIAL"] = device_serial
            return raptor.run_test(sys.argv[2:], kwargs)
        except Exception as e:
            print(repr(e))
            return 1
        finally:
            try:
                if is_android and kwargs['power_test']:
                    six.input(
                        "Connect device via USB and press Enter/return...")
                    device = ADBAndroid(device=device_serial, verbose=True)
                    device.command_output(["usb"])
                    adbhost.command_output(["disconnect", device_serial])
            except Exception:
                adbhost.command_output(["kill-server"])
Example #9
0
class FennecLauncher(Launcher):
    app_info = None

    def _get_device_status(self):
        self.adbhost = ADBHost()
        if self.adbhost.devices():
            return True
        if "y" == raw_input("WARNING: no device connected."
                            " Connect a device and try again.\n"
                            "Try again? (y or n): "):
            return self.get_device_status()
        raise Exception("Aborting!")

    def _install(self, dest):
        if self._get_device_status():
            self.adb = ADBAndroid()
            if "y" != raw_input("WARNING: bisecting nightly fennec builds will"
                                " clobber your existing nightly profile."
                                " Continue? (y or n)"):
                raise Exception("Aborting!")
        self.adb.uninstall_app("org.mozilla.fennec")
        self.adb.install_app(dest)
        # get info now, as dest may be removed
        self.app_info = mozversion.get_version(binary=dest)

    def _start(self, **args):
        self.adb.launch_fennec("org.mozilla.fennec")

    def _stop(self):
        self.adb.stop_application("org.mozilla.fennec")

    def _get_app_info(self):
        return self.app_info
Example #10
0
 def is_running(self):
     """
     Returns True if the Android emulator is running.
     """
     adb_path = _find_sdk_exe(self.substs, "adb", False)
     if not adb_path:
         adb_path = "adb"
     adbhost = ADBHost(adb=adb_path,
                       verbose=verbose_logging,
                       timeout=SHORT_TIMEOUT)
     devs = adbhost.devices(timeout=SHORT_TIMEOUT)
     devs = [(d["device_serial"], d["state"]) for d in devs]
     _log_debug(devs)
     if ("emulator-5554", "device") in devs:
         return True
     return False
Example #11
0
class FennecLauncher(Launcher):
    app_info = None

    def _get_device_status(self):
        self.adbhost = ADBHost()
        if self.adbhost.devices():
            return True
        if "y" == raw_input("WARNING: no device connected."
                            " Connect a device and try again.\n"
                            "Try again? (y or n): "):
            return self.get_device_status()
        raise Exception("Aborting!")

    def _install(self, dest):
        if self._get_device_status():
            self.adb = ADBAndroid()
            if "y" != raw_input("WARNING: bisecting nightly fennec builds will"
                                " clobber your existing nightly profile."
                                " Continue? (y or n)"):
                raise Exception("Aborting!")
        self.adb.uninstall_app("org.mozilla.fennec")
        self.adb.install_app(dest)
        # get info now, as dest may be removed
        self.app_info = mozversion.get_version(binary=dest)

    def _start(self, **args):
        self.adb.launch_fennec("org.mozilla.fennec")

    def _stop(self):
        self.adb.stop_application("org.mozilla.fennec")

    def _get_app_info(self):
        return self.app_info
Example #12
0
 def check_is_runnable(cls):
     try:
         devices = ADBHost().devices()
     except ADBError as adb_error:
         raise LauncherNotRunnable(str(adb_error))
     if not devices:
         raise LauncherNotRunnable("No android device connected."
                                   " Connect a device and try again.")
Example #13
0
 def _get_device_status(self):
     self.adbhost = ADBHost()
     if self.adbhost.devices():
         return True
     if "y" == raw_input("WARNING: no device connected."
                         " Connect a device and try again.\n"
                         "Try again? (y or n): "):
         return self.get_device_status()
     raise Exception("Aborting!")
Example #14
0
 def check_is_runnable(cls):
     # ADBHost().devices() seems to raise OSError when adb is not
     # installed and in PATH. TODO: maybe fix this in mozdevice.
     try:
         devices = ADBHost().devices()
     except OSError:
         raise LauncherNotRunnable("adb (Android Debug Bridge) is not"
                                   " installed or not in the PATH.")
     if not devices:
         raise LauncherNotRunnable("No android device connected."
                                   " Connect a device and try again.")
Example #15
0
 def check_is_runnable(cls):
     # ADBHost().devices() seems to raise OSError when adb is not
     # installed and in PATH. TODO: maybe fix this in mozdevice.
     try:
         devices = ADBHost().devices()
     except OSError:
         raise LauncherNotRunnable("adb (Android Debug Bridge) is not"
                                   " installed or not in the PATH.")
     if not devices:
         raise LauncherNotRunnable("No android device connected."
                                   " Connect a device and try again.")
     if not raw_input("WARNING: bisecting fennec builds will clobber your"
                      " existing profile. Type 'y' to continue:") == 'y':
         raise LauncherNotRunnable('Aborted.')
Example #16
0
class FennecNightly(Nightly):
    app_name = 'fennec'
    name = 'fennec'
    profile_class = FirefoxProfile
    build_regex = r'fennec-.*\.apk'
    build_info_regex = r'fennec-.*\.txt'
    binary = 'org.mozilla.fennec/.App'
    bits = None
    build_base_repo_name = "mobile"

    def get_device_status(self):
        self.adbhost = ADBHost()
        if self.adbhost.devices():
            return True
        if "y" == raw_input("WARNING: no device connected."
                            " Connect a device and try again.\n"
                            "Try again? (y or n): "):
            return self.get_device_status()
        raise Exception("Aborting!")

    def __init__(self, inbound_branch=None, bits=mozinfo.bits, persist=None):
        self.inbound_branch = inbound_branch
        self.persist = persist
        if self.get_device_status():
            self.adb = ADBAndroid()
            if "y" != raw_input("WARNING: bisecting nightly fennec builds will"
                                " clobber your existing nightly profile."
                                " Continue? (y or n)"):
                raise Exception("Aborting!")

    def get_inbound_branch(self, date):
        return "mozilla-central-android"

    def install(self):
        self.adb.uninstall_app("org.mozilla.fennec")
        self.adb.install_app(self.dest)
        return True

    def start(self, profile, addons, cmdargs):
        self.adb.launch_fennec("org.mozilla.fennec")
        return True

    def stop(self):
        self.adb.stop_application("org.mozilla.fennec")
        return True

    def get_app_info(self):
        return mozversion.get_version(binary=self.dest)
Example #17
0
def verify_android_device(build_obj,
                          install=InstallIntent.NO,
                          xre=False,
                          debugger=False,
                          network=False,
                          verbose=False,
                          app=None,
                          device_serial=None):
    """
       Determine if any Android device is connected via adb.
       If no device is found, prompt to start an emulator.
       If a device is found or an emulator started and 'install' is
       specified, also check whether Firefox is installed on the
       device; if not, prompt to install Firefox.
       If 'xre' is specified, also check with MOZ_HOST_BIN is set
       to a valid xre/host-utils directory; if not, prompt to set
       one up.
       If 'debugger' is specified, also check that JimDB is installed;
       if JimDB is not found, prompt to set up JimDB.
       If 'network' is specified, also check that the device has basic
       network connectivity.
       Returns True if the emulator was started or another device was
       already connected.
    """
    if "MOZ_DISABLE_ADB_INSTALL" in os.environ:
        install = InstallIntent.NO
        _log_info(
            "Found MOZ_DISABLE_ADB_INSTALL in environment, skipping android app"
            "installation")
    device_verified = False
    emulator = AndroidEmulator('*', substs=build_obj.substs, verbose=verbose)
    adb_path = _find_sdk_exe(build_obj.substs, 'adb', False)
    if not adb_path:
        adb_path = 'adb'
    adbhost = ADBHost(adb=adb_path, verbose=verbose, timeout=SHORT_TIMEOUT)
    devices = adbhost.devices(timeout=SHORT_TIMEOUT)
    if 'device' in [d['state'] for d in devices]:
        device_verified = True
    elif emulator.is_available():
        response = input(
            "No Android devices connected. Start an emulator? (Y/n) ").strip()
        if response.lower().startswith('y') or response == '':
            if not emulator.check_avd():
                _log_info("Fetching AVD...")
                emulator.update_avd()
            _log_info("Starting emulator running %s..." %
                      emulator.get_avd_description())
            emulator.start()
            emulator.wait_for_start()
            device_verified = True

    if device_verified and "DEVICE_SERIAL" not in os.environ:
        devices = adbhost.devices(timeout=SHORT_TIMEOUT)
        for d in devices:
            if d['state'] == 'device':
                os.environ["DEVICE_SERIAL"] = d['device_serial']
                break

    if device_verified and install != InstallIntent.NO:
        # Determine if test app is installed on the device; if not,
        # prompt to install. This feature allows a test command to
        # launch an emulator, install the test app, and proceed with testing
        # in one operation. It is also a basic safeguard against other
        # cases where testing is requested but test app installation has
        # been forgotten.
        # If a test app is installed, there is no way to determine whether
        # the current build is installed, and certainly no way to
        # determine if the installed build is the desired build.
        # Installing every time (without prompting) is problematic because:
        #  - it prevents testing against other builds (downloaded apk)
        #  - installation may take a couple of minutes.
        if not app:
            app = "org.mozilla.geckoview.test"
        device = _get_device(build_obj.substs, device_serial)
        response = ''
        installed = device.is_app_installed(app)

        if not installed:
            _log_info("It looks like %s is not installed on this device." %
                      app)
        if 'fennec' in app or 'firefox' in app:
            if installed:
                device.uninstall_app(app)
            _log_info("Installing Firefox...")
            build_obj._run_make(directory=".",
                                target='install',
                                ensure_exit_code=False)
        elif app == 'org.mozilla.geckoview.test':
            if installed:
                device.uninstall_app(app)
            _log_info("Installing geckoview AndroidTest...")
            sub = 'geckoview:installWithGeckoBinariesDebugAndroidTest'
            build_obj._mach_context.commands.dispatch('gradle',
                                                      build_obj._mach_context,
                                                      args=[sub])
        elif app == 'org.mozilla.geckoview_example':
            if installed:
                device.uninstall_app(app)
            _log_info("Installing geckoview_example...")
            sub = 'install-geckoview_example'
            build_obj._mach_context.commands.dispatch('android',
                                                      build_obj._mach_context,
                                                      subcommand=sub,
                                                      args=[])
        elif not installed:
            response = input(
                "It looks like %s is not installed on this device,\n"
                "but I don't know how to install it.\n"
                "Install it now, then hit Enter " % app)

        device.run_as_package = app

    if device_verified and xre:
        # Check whether MOZ_HOST_BIN has been set to a valid xre; if not,
        # prompt to install one.
        xre_path = os.environ.get('MOZ_HOST_BIN')
        err = None
        if not xre_path:
            err = "environment variable MOZ_HOST_BIN is not set to a directory " \
                  "containing host xpcshell"
        elif not os.path.isdir(xre_path):
            err = '$MOZ_HOST_BIN does not specify a directory'
        elif not os.path.isfile(os.path.join(xre_path, _get_xpcshell_name())):
            err = '$MOZ_HOST_BIN/xpcshell does not exist'
        if err:
            _maybe_update_host_utils(build_obj)
            xre_path = glob.glob(os.path.join(EMULATOR_HOME_DIR,
                                              'host-utils*'))
            for path in xre_path:
                if os.path.isdir(path) and os.path.isfile(
                        os.path.join(path, _get_xpcshell_name())):
                    os.environ["MOZ_HOST_BIN"] = path
                    err = None
                    break
        if err:
            _log_info("Host utilities not found: %s" % err)
            response = input(
                "Download and setup your host utilities? (Y/n) ").strip()
            if response.lower().startswith('y') or response == '':
                _install_host_utils(build_obj)

    if device_verified and network:
        # Optionally check the network: If on a device that does not look like
        # an emulator, verify that the device IP address can be obtained
        # and check that this host can ping the device.
        serial = device_serial or os.environ.get('DEVICE_SERIAL')
        if not serial or ('emulator' not in serial):
            device = _get_device(build_obj.substs, serial)
            device.run_as_package = app
            try:
                addr = device.get_ip_address()
                if not addr:
                    _log_warning("unable to get Android device's IP address!")
                    _log_warning(
                        "tests may fail without network connectivity to the device!"
                    )
                else:
                    _log_info("Android device's IP address: %s" % addr)
                    response = subprocess.check_output(
                        ["ping", "-c", "1", addr])
                    _log_debug(response)
            except Exception as e:
                _log_warning(
                    "unable to verify network connection to device: %s" %
                    str(e))
                _log_warning(
                    "tests may fail without network connectivity to the device!"
                )
        else:
            _log_debug("network check skipped on emulator")

    if debugger:
        _log_warning("JimDB is no longer supported")

    return device_verified
Example #18
0
def main():
    parser = argparse.ArgumentParser(
        usage='%(prog)s [options] <test command> (<test command option> ...)',
        description="Wrapper script for tests run on physical Android devices at Bitbar. Runs the provided command "
                    "wrapped with required setup and teardown.")
    _args, extra_args = parser.parse_known_args()
    logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s',
                        level=logging.INFO,
                        stream=sys.stdout)

    print('\nscript.py: starting')
    with open('/builds/worker/version') as versionfile:
        version = versionfile.read().strip()
    print('\nDockerfile version {}'.format(version))

    taskcluster_debug = '*'

    task_cwd = os.getcwd()
    print('Current working directory: {}'.format(task_cwd))

    with open('/builds/taskcluster/scriptvars.json') as scriptvars:
        scriptvarsenv = json.loads(scriptvars.read())
        print('Bitbar test run: https://mozilla.testdroid.com/#testing/device-session/{}/{}/{}'.format(
            scriptvarsenv['TESTDROID_PROJECT_ID'],
            scriptvarsenv['TESTDROID_BUILD_ID'],
            scriptvarsenv['TESTDROID_RUN_ID']))

    env = dict(os.environ)

    if 'PATH' in os.environ:
        path = os.environ['PATH']
    else:
        path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'

    path += ':/builds/worker/android-sdk-linux/tools/bin:/builds/worker/android-sdk-linux/platform-tools'

    env['PATH'] = os.environ['PATH'] = path
    env['NEED_XVFB'] = 'false'
    env['DEVICE_NAME'] = scriptvarsenv['DEVICE_NAME']
    env['ANDROID_DEVICE'] = scriptvarsenv['ANDROID_DEVICE']
    env['DEVICE_SERIAL'] = scriptvarsenv['DEVICE_SERIAL']
    env['HOST_IP'] = scriptvarsenv['HOST_IP']
    env['DEVICE_IP'] = scriptvarsenv['DEVICE_IP']
    env['DOCKER_IMAGE_VERSION'] = scriptvarsenv['DOCKER_IMAGE_VERSION']

    if 'HOME' not in env:
        env['HOME'] = '/builds/worker'
        print('setting HOME to {}'.format(env['HOME']))

    show_df()

    # If we are running normal tests we will be connected via usb and
    # there should be only one device connected.  If we are running
    # power tests, the framework will have already called adb tcpip
    # 5555 on the device before it disconnected usb. There should be
    # no devices connected and we will need to perform an adb connect
    # to connect to the device. DEVICE_SERIAL will be set to either
    # the device's serial number or its ipaddress:5555 by the framework.
    try:
        adbhost = ADBHost(verbose=True)
        if env['DEVICE_SERIAL'].endswith(':5555'):
            # Power testing with adb over wifi.
            adbhost.command_output(["connect", env['DEVICE_SERIAL']])
        devices = adbhost.devices()
        print(json.dumps(devices, indent=4))
        if len(devices) != 1:
            fatal('Must have exactly one connected device. {} found.'.format(len(devices)), retry=True)
    except (ADBError, ADBTimeoutError) as e:
        fatal('{} Unable to obtain attached devices'.format(e), retry=True)

    try:
        for f in glob('/tmp/adb.*.log'):
            print('\n{}:\n'.format(f))
            with open(f) as afile:
                print(afile.read())
    except Exception as e:
        print('{} while reading adb logs'.format(e))

    print('Connecting to Android device {}'.format(env['DEVICE_SERIAL']))
    try:
        device = ADBDevice(device=env['DEVICE_SERIAL'])
        android_version = device.get_prop('ro.build.version.release')
        print('Android device version (ro.build.version.release):  {}'.format(android_version))
        # this can explode if an unknown device, explode now vs in an hour...
        device_type = get_device_type(device)
        # set device to UTC
        if device.is_rooted:
            device.shell_output('setprop persist.sys.timezone "UTC"', timeout=ADB_COMMAND_TIMEOUT)
        # show date for visual confirmation
        device_datetime = device.shell_output("date", timeout=ADB_COMMAND_TIMEOUT)
        print('Android device datetime:  {}'.format(device_datetime))

        # clean up the device.
        device.rm('/data/local/tests', recursive=True, force=True)
        device.rm('/data/local/tmp/*', recursive=True, force=True)
        device.rm('/data/local/tmp/xpcb', recursive=True, force=True)
        device.rm('/sdcard/tests', recursive=True, force=True)
        device.rm('/sdcard/raptor-profile', recursive=True, force=True)
    except (ADBError, ADBTimeoutError) as e:
        fatal("{} attempting to clean up device".format(e), retry=True)

    if taskcluster_debug:
        env['DEBUG'] = taskcluster_debug

    print('environment = {}'.format(json.dumps(env, indent=4)))

    # run the payload's command and ensure that:
    # - all output is printed
    # - no deadlock occurs between proc.poll() and sys.stdout.readline()
    #   - more info
    #     - https://bugzilla.mozilla.org/show_bug.cgi?id=1611936
    #     - https://stackoverflow.com/questions/58471094/python-subprocess-readline-hangs-cant-use-normal-options
    print("script.py: running command '%s'" % ' '.join(extra_args))
    rc = None
    proc = subprocess.Popen(extra_args,
                            # use standard os buffer size
                            bufsize=-1,
                            env=env,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            close_fds=True)
    # Create the queue instance
    q = queue.Queue()
    # Kick off the monitoring thread
    thread = threading.Thread(target=_monitor_readline, args=(proc, q))
    thread.daemon = True
    thread.start()
    start = datetime.now()
    while True:
        time.sleep(0.1)
        bail = True
        rc = proc.poll()
        if rc is None:
            bail = False
            # Re-set the thread timer
            start = datetime.now()
        out = ""
        while not q.empty():
            out += q.get()
        if out:
            print(out.rstrip())

        # In the case where the thread is still alive and reading, and
        # the process has exited and finished, give it up to X seconds
        # to finish reading
        if bail and thread.is_alive() and (datetime.now() - start).total_seconds() < 5:
            bail = False
        if bail:
            break
    print("script.py: command finished")

    # enable charging on device if it is disabled
    #   see https://bugzilla.mozilla.org/show_bug.cgi?id=1565324
    enable_charging(device, device_type)

    try:
        if env['DEVICE_SERIAL'].endswith(':5555'):
            device.command_output(["usb"])
            adbhost.command_output(["disconnect", env['DEVICE_SERIAL']])
        adbhost.kill_server()
    except (ADBError, ADBTimeoutError) as e:
        print('{} attempting adb kill-server'.format(e))

    try:
        print('\nnetstat -aop\n%s\n\n' % subprocess.check_output(
            ['netstat', '-aop'],
            stderr=subprocess.STDOUT).decode())
    except subprocess.CalledProcessError as e:
        print('{} attempting netstat'.format(e))

    show_df()

    print('script.py: exiting with exitcode {}.'.format(rc))
    return rc
Example #19
0
def main():
    parser = argparse.ArgumentParser(
        usage='%(prog)s [options] <test command> (<test command option> ...)',
        description=
        "Wrapper script for tests run on physical Android devices at Bitbar. Runs the provided command wrapped with required setup and teardown."
    )
    _args, extra_args = parser.parse_known_args()
    logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s',
                        level=logging.INFO,
                        stream=sys.stdout)

    print('\nBegin script.py')
    with open('/builds/worker/version') as versionfile:
        version = versionfile.read().strip()
    print('\nDockerfile version {}'.format(version))

    taskcluster_debug = '*'

    task_cwd = os.getcwd()
    print('Current working directory: {}'.format(task_cwd))

    with open('/builds/taskcluster/scriptvars.json') as scriptvars:
        scriptvarsenv = json.loads(scriptvars.read())
        print(
            'Bitbar test run: https://mozilla.testdroid.com/#testing/device-session/{}/{}/{}'
            .format(scriptvarsenv['TESTDROID_PROJECT_ID'],
                    scriptvarsenv['TESTDROID_BUILD_ID'],
                    scriptvarsenv['TESTDROID_RUN_ID']))

    env = dict(os.environ)

    if 'PATH' in os.environ:
        path = os.environ['PATH']
    else:
        path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'

    path += ':/builds/worker/android-sdk-linux/tools/bin:/builds/worker/android-sdk-linux/platform-tools'

    env['PATH'] = os.environ['PATH'] = path
    env['NEED_XVFB'] = 'false'
    env['DEVICE_NAME'] = scriptvarsenv['DEVICE_NAME']
    env['ANDROID_DEVICE'] = scriptvarsenv['ANDROID_DEVICE']
    env['DEVICE_SERIAL'] = scriptvarsenv['DEVICE_SERIAL']
    env['HOST_IP'] = scriptvarsenv['HOST_IP']
    env['DEVICE_IP'] = scriptvarsenv['DEVICE_IP']
    env['DOCKER_IMAGE_VERSION'] = scriptvarsenv['DOCKER_IMAGE_VERSION']

    if 'HOME' not in env:
        env['HOME'] = '/builds/worker'
        print('setting HOME to {}'.format(env['HOME']))

    # If we are running normal tests we will be connected via usb and
    # there should be only one device connected.  If we are running
    # power tests, the framework will have already called adb tcpip
    # 5555 on the device before it disconnected usb. There should be
    # no devices connected and we will need to perform an adb connect
    # to connect to the device. DEVICE_SERIAL will be set to either
    # the device's serial number or its ipaddress:5555 by the framework.
    try:
        adbhost = ADBHost()
        if env['DEVICE_SERIAL'].endswith(':5555'):
            # Power testing with adb over wifi.
            adbhost.command_output(["connect", env['DEVICE_SERIAL']])
        devices = adbhost.devices()
        print(json.dumps(devices, indent=4))
        if len(devices) != 1:
            fatal('Must have exactly one connected device. {} found.'.format(
                len(devices)))
    except ADBError as e:
        fatal('{} Unable to obtain attached devices'.format(e))

    try:
        for f in glob('/tmp/adb.*.log'):
            print('\n{}:\n'.format(f))
            with open(f) as afile:
                print(afile.read())
    except Exception as e:
        print('{} while reading adb logs'.format(e))

    print('Connecting to Android device {}'.format(env['DEVICE_SERIAL']))
    try:
        device = ADBDevice(device=env['DEVICE_SERIAL'])
        android_version = device.get_prop('ro.build.version.release')
        print('Android device version (ro.build.version.release):  {}'.format(
            android_version))
        # this can explode if an unknown device, explode now vs in an hour...
        device_type = get_device_type(device)

        # clean up the device.
        device.rm('/data/local/tests', recursive=True, force=True, root=True)
        device.rm('/data/local/tmp/*', recursive=True, force=True, root=True)
        device.rm('/data/local/tmp/xpcb',
                  recursive=True,
                  force=True,
                  root=True)
        device.rm('/sdcard/tests', recursive=True, force=True, root=True)
        device.rm('/sdcard/raptor-profile',
                  recursive=True,
                  force=True,
                  root=True)
    except ADBError as e:
        fatal("{} attempting to clean up device".format(e))

    if taskcluster_debug:
        env['DEBUG'] = taskcluster_debug

    print('environment = {}'.format(json.dumps(env, indent=4)))

    # run the payload's command
    print(' '.join(extra_args))
    rc = None
    proc = subprocess.Popen(extra_args,
                            env=env,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT)
    while rc == None:
        line = proc.stdout.readline()
        sys.stdout.write(line)
        rc = proc.poll()

    # enable charging on device if it is disabled
    #   see https://bugzilla.mozilla.org/show_bug.cgi?id=1565324
    enable_charging(device, device_type)

    try:
        if env['DEVICE_SERIAL'].endswith(':5555'):
            device.command_output(["usb"])
            adbhost.command_output(["disconnect", env['DEVICE_SERIAL']])
        adbhost.kill_server()
    except ADBError as e:
        print('{} attempting adb kill-server'.format(e))

    try:
        print('\nnetstat -aop\n%s\n\n' % subprocess.check_output(
            ['netstat', '-aop'], stderr=subprocess.STDOUT))
    except subprocess.CalledProcessError as e:
        print('{} attempting netstat'.format(e))

    print('script.py exitcode {}'.format(rc))
    return rc
Example #20
0
def verify_android_device(build_obj,
                          install=False,
                          xre=False,
                          debugger=False,
                          verbose=False,
                          app=None,
                          device_serial=None):
    """
       Determine if any Android device is connected via adb.
       If no device is found, prompt to start an emulator.
       If a device is found or an emulator started and 'install' is
       specified, also check whether Firefox is installed on the
       device; if not, prompt to install Firefox.
       If 'xre' is specified, also check with MOZ_HOST_BIN is set
       to a valid xre/host-utils directory; if not, prompt to set
       one up.
       If 'debugger' is specified, also check that JimDB is installed;
       if JimDB is not found, prompt to set up JimDB.
       Returns True if the emulator was started or another device was
       already connected.
    """
    device_verified = False
    emulator = AndroidEmulator('*', substs=build_obj.substs, verbose=verbose)
    adb_path = _find_sdk_exe(build_obj.substs, 'adb', False)
    if not adb_path:
        adb_path = 'adb'
    adbhost = ADBHost(adb=adb_path, verbose=verbose, timeout=10)
    devices = adbhost.devices(timeout=10)
    if 'device' in [d['state'] for d in devices]:
        device_verified = True
    elif emulator.is_available():
        response = raw_input(
            "No Android devices connected. Start an emulator? (Y/n) ").strip()
        if response.lower().startswith('y') or response == '':
            if not emulator.check_avd():
                _log_info("Fetching AVD. This may take a while...")
                emulator.update_avd()
            _log_info("Starting emulator running %s..." %
                      emulator.get_avd_description())
            emulator.start()
            emulator.wait_for_start()
            device_verified = True

    if device_verified and install:
        # Determine if Firefox is installed on the device; if not,
        # prompt to install. This feature allows a test command to
        # launch an emulator, install Firefox, and proceed with testing
        # in one operation. It is also a basic safeguard against other
        # cases where testing is requested but Firefox installation has
        # been forgotten.
        # If Firefox is installed, there is no way to determine whether
        # the current build is installed, and certainly no way to
        # determine if the installed build is the desired build.
        # Installing every time is problematic because:
        #  - it prevents testing against other builds (downloaded apk)
        #  - installation may take a couple of minutes.
        if not app:
            app = build_obj.substs["ANDROID_PACKAGE_NAME"]
        device = _get_device(build_obj.substs, device_serial)
        if not device.is_app_installed(app):
            if 'fennec' not in app and 'firefox' not in app:
                raw_input("It looks like %s is not installed on this device,\n"
                          "but I don't know how to install it.\n"
                          "Install it now, then hit Enter " % app)
            else:
                response = raw_input(
                    "It looks like %s is not installed on this device.\n"
                    "Install Firefox? (Y/n) " % app).strip()
                if response.lower().startswith('y') or response == '':
                    _log_info("Installing Firefox. This may take a while...")
                    build_obj._run_make(directory=".",
                                        target='install',
                                        ensure_exit_code=False)

    if device_verified and xre:
        # Check whether MOZ_HOST_BIN has been set to a valid xre; if not,
        # prompt to install one.
        xre_path = os.environ.get('MOZ_HOST_BIN')
        err = None
        if not xre_path:
            err = "environment variable MOZ_HOST_BIN is not set to a directory " \
                  "containing host xpcshell"
        elif not os.path.isdir(xre_path):
            err = '$MOZ_HOST_BIN does not specify a directory'
        elif not os.path.isfile(os.path.join(xre_path, 'xpcshell')):
            err = '$MOZ_HOST_BIN/xpcshell does not exist'
        if err:
            _maybe_update_host_utils(build_obj)
            xre_path = glob.glob(os.path.join(EMULATOR_HOME_DIR,
                                              'host-utils*'))
            for path in xre_path:
                if os.path.isdir(path) and os.path.isfile(
                        os.path.join(path, 'xpcshell')):
                    os.environ['MOZ_HOST_BIN'] = path
                    err = None
                    break
        if err:
            _log_info("Host utilities not found: %s" % err)
            response = raw_input(
                "Download and setup your host utilities? (Y/n) ").strip()
            if response.lower().startswith('y') or response == '':
                _install_host_utils(build_obj)

    if debugger:
        # Optionally set up JimDB. See https://wiki.mozilla.org/Mobile/Fennec/Android/GDB.
        build_platform = _get_device_platform(build_obj.substs)
        jimdb_path = os.path.join(EMULATOR_HOME_DIR,
                                  'jimdb-%s' % build_platform)
        jimdb_utils_path = os.path.join(jimdb_path, 'utils')
        gdb_path = os.path.join(jimdb_path, 'bin', 'gdb')
        err = None
        if not os.path.isdir(jimdb_path):
            err = '%s does not exist' % jimdb_path
        elif not os.path.isfile(gdb_path):
            err = '%s not found' % gdb_path
        if err:
            _log_info("JimDB (%s) not found: %s" % (build_platform, err))
            response = raw_input("Download and setup JimDB (%s)? (Y/n) " %
                                 build_platform).strip()
            if response.lower().startswith('y') or response == '':
                host_platform = _get_host_platform()
                if host_platform:
                    _log_info(
                        "Installing JimDB (%s/%s). This may take a while..." %
                        (host_platform, build_platform))
                    path = os.path.join(MANIFEST_PATH, host_platform,
                                        'jimdb-%s.manifest' % build_platform)
                    _get_tooltool_manifest(build_obj.substs, path,
                                           EMULATOR_HOME_DIR,
                                           'releng.manifest')
                    _tooltool_fetch()
                    if os.path.isfile(gdb_path):
                        # Get JimDB utilities from git repository
                        proc = ProcessHandler(['git', 'pull'],
                                              cwd=jimdb_utils_path)
                        proc.run()
                        git_pull_complete = False
                        try:
                            proc.wait()
                            if proc.proc.returncode == 0:
                                git_pull_complete = True
                        except Exception:
                            if proc.poll() is None:
                                proc.kill(signal.SIGTERM)
                        if not git_pull_complete:
                            _log_warning(
                                "Unable to update JimDB utils from git -- "
                                "some JimDB features may be unavailable.")
                    else:
                        _log_warning(
                            "Unable to install JimDB -- unable to fetch from tooltool."
                        )
                else:
                    _log_warning(
                        "Unable to install JimDB -- your platform is not supported!"
                    )
        if os.path.isfile(gdb_path):
            # sync gdbinit.local with build settings
            _update_gdbinit(build_obj.substs,
                            os.path.join(jimdb_utils_path, "gdbinit.local"))
            # ensure JimDB is in system path, so that mozdebug can find it
            bin_path = os.path.join(jimdb_path, 'bin')
            os.environ['PATH'] = "%s:%s" % (bin_path, os.environ['PATH'])

    return device_verified
Example #21
0
    def configure_devices(self):
        """
           Ensure devices.ini is set up.
        """
        keep_going = True
        device_ini = os.path.join(self.config['base-dir'], 'devices.ini')
        if os.path.exists(device_ini):
            response = raw_input(
                "Use existing device configuration at %s? (Y/n) " % device_ini).strip()
            if 'n' not in response.lower():
                self.build_obj.log(logging.INFO, "autophone", {},
                                   "Using device configuration at %s" % device_ini)
                return keep_going
        keep_going = False
        self.build_obj.log(logging.INFO, "autophone", {},
                           "You must configure at least one Android device "
                           "before running autophone.")
        response = raw_input(
            "Configure devices now? (Y/n) ").strip()
        if response.lower().startswith('y') or response == '':
            response = raw_input(
                "Connect your rooted Android test device(s) with usb and press Enter ")
            adb_path = 'adb'
            try:
                if os.path.exists(self.build_obj.substs["ADB"]):
                    adb_path = self.build_obj.substs["ADB"]
            except Exception:
                if self.verbose:
                    self.build_obj.log(logging.ERROR, "autophone", {},
                                       str(sys.exc_info()[0]))
                # No build environment?
                try:
                    adb_path = which.which('adb')
                except which.WhichError:
                    adb_path = raw_input(
                        "adb not found. Enter path to adb: ").strip()
            if self.verbose:
                print("Using adb at %s" % adb_path)

            adbhost = ADBHost(adb=adb_path, timeout=10)
            device_index = 1
            try:
                with open(os.path.join(self.config['base-dir'], 'devices.ini'), 'w') as f:
                    for device in adbhost.devices():
                        serial = device['device_serial']
                        if self.verify_device(adb_path, serial):
                            f.write("[device-%d]\nserialno=%s\n" % (device_index, serial))
                            device_index += 1
                            self.build_obj.log(logging.INFO, "autophone", {},
                                               "Added '%s' to device configuration." % serial)
                            keep_going = True
                        else:
                            self.build_obj.log(logging.WARNING, "autophone", {},
                                               "Device '%s' is not rooted - skipping" % serial)
            except Exception:
                self.build_obj.log(logging.ERROR, "autophone", {},
                                   "Failed to get list of connected Android devices.")
                if self.verbose:
                    self.build_obj.log(logging.ERROR, "autophone", {},
                                       str(sys.exc_info()[0]))
                keep_going = False
            if device_index <= 1:
                self.build_obj.log(logging.ERROR, "autophone", {},
                                   "No devices configured! (Can you see your rooted test device(s)"
                                   " in 'adb devices'?")
                keep_going = False
            if keep_going:
                self.config['devices-configured'] = True
        return keep_going