Exemplo n.º 1
0
class AdbConnection:
    device = None
    TMP_PATH = '/data/local/tmp'
    server = None
    port = 0
    signer = None
    connected = False
    apks = None

    def __init__(self, server, port, signer=None):
        self.server = server
        self.port = port
        self.signer = signer

    def connect(self):
        self.device = AdbDeviceTcp(self.server, self.port)

        try:
            if self.signer:
                self.device.connect(rsa_keys=[self.signer], timeout_s=10.0)
            else:
                self.device.connect(timeout_s=10.0)

        except OSError as e:
            logger.error("OSError: {}".format(e))
            raise AdbConnectionError(e)

        except (DeviceAuthError, TcpTimeoutException) as e:
            logger.error("Could not authenticate to the ADB server: {}".format(e))
            raise AdbConnectionError(e)

    def install_apk(self, apk):
        apk.progress.set_fraction(0.0)
        apk.info('Copying...')

        # Copy the APK to the target
        dst_filename = ''.join(random.choice(string.ascii_lowercase) for i in range(16)) + '.apk'

        dst_path = os.path.join(AdbConnection.TMP_PATH, dst_filename)
        logger.debug("dst_path: {}".format(dst_path))
        self.device.push(apk.src_path, dst_path, total_timeout_s=10.0, progress_callback=apk.update_progress)
        apk.progress.set_fraction(1.0)

        apk.info('Installing...')

        # Install the APK on the target
        try:
            output = self.device.shell('pm install -r {}'.format(dst_path))
        except Exception as e:
            logger.error("Installation failed: {}".format(e))
            raise

        if output != "Success\n":
            apk.fail(output.split('\n')[0])

        else:
            apk.succeed()
Exemplo n.º 2
0
class ADBPython(object):
    """A manager for ADB connections that uses a Python implementation of the ADB protocol.

    Parameters
    ----------
    host : str
        The address of the device; may be an IP address or a host name
    port : int
        The device port to which we are connecting (default is 5555)
    adbkey : str
        The path to the ``adbkey`` file for ADB authentication

    """
    def __init__(self, host, port, adbkey=''):
        self.host = host
        self.port = int(port)
        self.adbkey = adbkey
        self._adb = AdbDeviceTcp(host=self.host,
                                 port=self.port,
                                 default_timeout_s=9.)

        # keep track of whether the ADB connection is intact
        self._available = False

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()

    @property
    def available(self):
        """Check whether the ADB connection is intact.

        Returns
        -------
        bool
            Whether or not the ADB connection is intact

        """
        return self._adb.available

    def close(self):
        """Close the ADB socket connection.

        """
        self._adb.close()

    def connect(self,
                always_log_errors=True,
                auth_timeout_s=DEFAULT_AUTH_TIMEOUT_S):
        """Connect to an Android TV / Fire TV device.

        Parameters
        ----------
        always_log_errors : bool
            If True, errors will always be logged; otherwise, errors will only be logged on the first failed reconnect attempt
        auth_timeout_s : float
            Authentication timeout (in seconds)

        Returns
        -------
        bool
            Whether or not the connection was successfully established and the device is available

        """
        try:
            with _acquire(self._adb_lock):
                # Catch exceptions
                try:
                    # Connect with authentication
                    if self.adbkey:
                        # private key
                        with open(self.adbkey) as f:
                            priv = f.read()

                        # public key
                        try:
                            with open(self.adbkey + '.pub') as f:
                                pub = f.read()
                        except FileNotFoundError:
                            pub = ''

                        signer = PythonRSASigner(pub, priv)

                        self._adb.connect(rsa_keys=[signer],
                                          auth_timeout_s=auth_timeout_s)

                    # Connect without authentication
                    else:
                        self._adb.connect(auth_timeout_s=auth_timeout_s)

                    # ADB connection successfully established
                    _LOGGER.debug(
                        "ADB connection to %s:%d successfully established",
                        self.host, self.port)
                    self._available = True
                    return True

                except OSError as exc:
                    if self._available or always_log_errors:
                        if exc.strerror is None:
                            exc.strerror = "Timed out trying to connect to ADB device."
                        _LOGGER.warning("Couldn't connect to %s:%d.  %s: %s",
                                        self.host, self.port,
                                        exc.__class__.__name__, exc.strerror)

                    # ADB connection attempt failed
                    self.close()
                    self._available = False
                    return False

                except Exception as exc:  # pylint: disable=broad-except
                    if self._available or always_log_errors:
                        _LOGGER.warning("Couldn't connect to %s:%d.  %s: %s",
                                        self.host, self.port,
                                        exc.__class__.__name__, exc)

                    # ADB connection attempt failed
                    self.close()
                    self._available = False
                    return False

        except LockNotAcquiredException:
            _LOGGER.warning(
                "Couldn't connect to %s:%d because adb-shell lock not acquired.",
                self.host, self.port)
            self.close()
            self._available = False
            return False

    def pull(self, local_path, device_path):
        """Pull a file from the device using the Python ADB implementation.

        Parameters
        ----------
        local_path : str
            The path where the file will be saved
        device_path : str
            The file on the device that will be pulled

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: pull(%s, %s)",
                self.host, self.port, local_path, device_path)
            return

        with _acquire(self._adb_lock):
            _LOGGER.debug(
                "Sending command to %s:%d via adb-shell: pull(%s, %s)",
                self.host, self.port, local_path, device_path)
            self._adb.pull(device_path, local_path)
            return

    def push(self, local_path, device_path):
        """Push a file to the device using the Python ADB implementation.

        Parameters
        ----------
        local_path : str
            The file that will be pushed to the device
        device_path : str
            The path where the file will be saved on the device

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: push(%s, %s)",
                self.host, self.port, local_path, device_path)
            return

        with _acquire(self._adb_lock):
            _LOGGER.debug(
                "Sending command to %s:%d via adb-shell: push(%s, %s)",
                self.host, self.port, local_path, device_path)
            self._adb.push(local_path, device_path)
            return

    def shell(self, cmd):
        """Send an ADB command using the Python ADB implementation.

        Parameters
        ----------
        cmd : str
            The ADB command to be sent

        Returns
        -------
        str, None
            The response from the device, if there is a response

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: %s",
                self.host, self.port, cmd)
            return None

        with _acquire(self._adb_lock):
            _LOGGER.debug("Sending command to %s:%d via adb-shell: %s",
                          self.host, self.port, cmd)
            return self._adb.shell(cmd)