# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import atexit
import hashlib
import logging
import os
import os.path
import random
import re
import subprocess
import sys
import tempfile
import threading
import time
import uuid

from devtoolslib import http_server
from devtoolslib.shell import Shell
from devtoolslib.utils import overrides


# Tags used by mojo shell Java logging.
_LOGCAT_JAVA_TAGS = [
    'AndroidHandler',
    'MojoFileHelper',
    'MojoMain',
    'MojoShellActivity',
    'MojoShellApplication',
]

# Tags used by native logging reflected in the logcat.
_LOGCAT_NATIVE_TAGS = [
    'chromium',
    'sky',
]

_MOJO_SHELL_PACKAGE_NAME = 'org.chromium.mojo.shell'

# Used to parse the output of `adb devices`.
_ADB_DEVICES_HEADER = 'List of devices attached'


_logger = logging.getLogger()


def _exit_if_needed(process):
  """Exits |process| if it is still alive."""
  if process.poll() is None:
    process.kill()


def _find_available_port(netstat_output, max_attempts=10000):
  opened = [int(x.strip().split()[3].split(':')[1])
            for x in netstat_output if x.startswith(' tcp')]
  for _ in xrange(max_attempts):
    port = random.randint(4096, 16384)
    if port not in opened:
      return port
  else:
    raise Exception('Failed to identify an available port.')


def _find_available_host_port():
  netstat_output = subprocess.check_output(['netstat'])
  return _find_available_port(netstat_output)


def parse_adb_devices_output(adb_devices_output):
  """Parses the output of the `adb devices` command, returning a dictionary
  mapping device id to the status of the device, as printed by `adb devices`.
  """
  # Split into lines skipping empty ones.
  lines = [line.strip() for line in adb_devices_output.split('\n')
           if line.strip()]

  if _ADB_DEVICES_HEADER not in lines:
    return None

  # The header can be preceeded by output informing of adb server being spawned,
  # but all non-empty lines after the header describe connected devices.
  device_specs = lines[lines.index(_ADB_DEVICES_HEADER) + 1:]
  split_specs = [spec.split() for spec in device_specs]
  return {split_spec[0]: split_spec[1] for split_spec in split_specs
          if len(split_spec) == 2}


class AndroidShell(Shell):
  """Wrapper around Mojo shell running on an Android device.

  Args:
    adb_path: Path to adb, optional if adb is in PATH.
    target_device: Device to run on, if multiple devices are connected.
    logcat_tags: Comma-separated list of additional logcat tags to use.
  """

  def __init__(self, adb_path="adb", target_device=None, logcat_tags=None,
               verbose_pipe=None):
    self.adb_path = adb_path
    self.target_device = target_device
    self.stop_shell_registered = False
    self.adb_running_as_root = None
    self.additional_logcat_tags = logcat_tags
    self.verbose_pipe = verbose_pipe if verbose_pipe else open(os.devnull, 'w')

  def _adb_command(self, args):
    """Forms an adb command from the given arguments, prepending the adb path
    and adding a target device specifier, if needed.
    """
    adb_command = [self.adb_path]
    if self.target_device:
      adb_command.extend(['-s', self.target_device])
    adb_command.extend(args)
    return adb_command

  def _read_fifo(self, fifo_path, pipe, on_fifo_closed, max_attempts=5):
    """Reads |fifo_path| on the device and write the contents to |pipe|.

    Calls |on_fifo_closed| when the fifo is closed. This method will try to find
    the path up to |max_attempts|, waiting 1 second between each attempt. If it
    cannot find |fifo_path|, a exception will be raised.
    """
    fifo_command = self._adb_command(
        ['shell', 'test -e "%s"; echo $?' % fifo_path])

    def _run():
      def _wait_for_fifo():
        for _ in xrange(max_attempts):
          if subprocess.check_output(fifo_command)[0] == '0':
            return
          time.sleep(1)
        if on_fifo_closed:
          on_fifo_closed()
        raise Exception("Unable to find fifo.")
      _wait_for_fifo()
      stdout_cat = subprocess.Popen(
          self._adb_command(['shell', 'cat', fifo_path]), stdout=pipe)
      atexit.register(_exit_if_needed, stdout_cat)
      stdout_cat.wait()
      if on_fifo_closed:
        on_fifo_closed()

    thread = threading.Thread(target=_run, name="StdoutRedirector")
    thread.start()

  def _find_available_device_port(self):
    netstat_output = subprocess.check_output(
        self._adb_command(['shell', 'netstat']))
    return _find_available_port(netstat_output)

  def _forward_device_port_to_host(self, device_port, host_port):
    """Maps the device port to the host port. If |device_port| is 0, a random
    available port is chosen.

    Returns:
      The device port.
    """
    assert host_port
    # Root is not required for `adb forward` (hence we don't check the return
    # value), but if we can run adb as root, we have to do it now, because
    # restarting adbd as root clears any port mappings. See
    # https://github.com/domokit/devtools/issues/20.
    self._run_adb_as_root()

    if device_port == 0:
      # TODO(ppi): Should we have a retry loop to handle the unlikely races?
      device_port = self._find_available_device_port()
    subprocess.check_call(self._adb_command([
        "reverse", "tcp:%d" % device_port, "tcp:%d" % host_port]))

    def _unmap_port():
      unmap_command = self._adb_command([
          "reverse", "--remove", "tcp:%d" % device_port])
      subprocess.Popen(unmap_command)
    atexit.register(_unmap_port)
    return device_port

  def _forward_host_port_to_device(self, host_port, device_port):
    """Maps the host port to the device port. If |host_port| is 0, a random
    available port is chosen.

    Returns:
      The host port.
    """
    assert device_port
    self._run_adb_as_root()

    if host_port == 0:
      # TODO(ppi): Should we have a retry loop to handle the unlikely races?
      host_port = _find_available_host_port()
    subprocess.check_call(self._adb_command([
        "forward", 'tcp:%d' % host_port, 'tcp:%d' % device_port]))

    def _unmap_port():
      unmap_command = self._adb_command([
          "forward", "--remove", "tcp:%d" % device_port])
      subprocess.Popen(unmap_command)
    atexit.register(_unmap_port)
    return host_port

  def _run_adb_as_root(self):
    if self.adb_running_as_root is not None:
      return self.adb_running_as_root

    if ('cannot run as root' not in subprocess.check_output(
        self._adb_command(['root']))):
      # Wait for adbd to restart.
      subprocess.check_call(
          self._adb_command(['wait-for-device']),
          stdout=self.verbose_pipe)
      self.adb_running_as_root = True
    else:
      self.adb_running_as_root = False

    return self.adb_running_as_root

  def _is_shell_package_installed(self):
    # Adb should print one line if the package is installed and return empty
    # string otherwise.
    return len(subprocess.check_output(self._adb_command([
        'shell', 'pm', 'list', 'packages', _MOJO_SHELL_PACKAGE_NAME]))) > 0

  @staticmethod
  def get_tmp_dir_path():
    """Returns a path to a cache directory owned by the shell where temporary
    files can be stored.
    """
    return '/data/data/%s/cache/tmp/' % _MOJO_SHELL_PACKAGE_NAME

  def pull_file(self, device_path, destination_path, remove_original=False):
    """Copies or moves the specified file on the device to the host."""
    subprocess.check_call(self._adb_command([
        'pull', device_path, destination_path]))
    if remove_original:
      subprocess.check_call(self._adb_command([
          'shell', 'rm', device_path]))

  def check_device(self, require_root=False):
    """Verifies if the device configuration allows adb to run.

    If a target device was indicated in the constructor, it checks that the
    device is available. Otherwise, it checks that there is exactly one
    available device.

    Returns:
      A tuple of (result, msg). |result| is True iff if the device is correctly
      configured and False otherwise. |msg| is the reason for failure if
      |result| is False and None otherwise.
    """
    adb_devices_output = subprocess.check_output(
        self._adb_command(['devices']))
    devices = parse_adb_devices_output(adb_devices_output)

    if not devices:
      return False, 'No devices connected.'

    if self.target_device:
      if (self.target_device in devices and
          devices[self.target_device] == 'device'):
        return True, None
      else:
        return False, ('Cannot connect to the selected device, status: ' +
                       devices[self.target_device])

    if len(devices) > 1:
      return False, ('More than one device connected and target device not '
                     'specified.')

    if not devices.itervalues().next() == 'device':
      return False, 'Connected device is not available.'

    if require_root and not self._run_adb_as_root():
      return False, 'Cannot run on an unrooted device.'

    return True, None

  def install_apk(self, shell_apk_path):
    """Installs the apk on the device.

    This method computes checksum of the APK and skips the installation if the
    fingerprint matches the one saved on the device upon the previous
    installation.

    Args:
      shell_apk_path: Path to the shell Android binary.
    """
    device_sha1_path = '/sdcard/%s/%s.sha1' % (_MOJO_SHELL_PACKAGE_NAME,
                                               'MojoShell')
    apk_sha1 = hashlib.sha1(open(shell_apk_path, 'rb').read()).hexdigest()
    device_apk_sha1 = subprocess.check_output(self._adb_command([
        'shell', 'cat', device_sha1_path]))
    do_install = (apk_sha1 != device_apk_sha1 or
                  not self._is_shell_package_installed())

    if do_install:
      subprocess.check_call(
          self._adb_command(['install', '-r', shell_apk_path, '-i',
                            _MOJO_SHELL_PACKAGE_NAME]),
          stdout=self.verbose_pipe)

      # Update the stamp on the device.
      with tempfile.NamedTemporaryFile() as fp:
        fp.write(apk_sha1)
        fp.flush()
        subprocess.check_call(self._adb_command(['push', fp.name,
                                                device_sha1_path]),
                              stdout=self.verbose_pipe)
    else:
      # To ensure predictable state after running install_apk(), we need to stop
      # the shell here, as this is what "adb install" implicitly does.
      self.stop_shell()

  def start_shell(self,
                 arguments,
                 stdout=None,
                 on_application_stop=None):
    """Starts the mojo shell, passing it the given arguments.

    Args:
      arguments: List of arguments for the shell.
      stdout: Valid argument for subprocess.Popen() or None.
    """
    if not self.stop_shell_registered:
      atexit.register(self.stop_shell)
      self.stop_shell_registered = True

    STDOUT_PIPE = "/data/data/%s/stdout.fifo" % _MOJO_SHELL_PACKAGE_NAME

    cmd = self._adb_command(['shell', 'am', 'start',
                            '-S',
                            '-a', 'android.intent.action.VIEW',
                            '-n', '%s/.MojoShellActivity' %
                            _MOJO_SHELL_PACKAGE_NAME])

    parameters = []
    if stdout or on_application_stop:
      # We need to run as root to access the fifo file we use for stdout
      # redirection.
      if self._run_adb_as_root():
        # Remove any leftover fifo file after the previous run.
        subprocess.check_call(self._adb_command(
            ['shell', 'rm', '-f', STDOUT_PIPE]))

        parameters.append('--fifo-path=%s' % STDOUT_PIPE)
        self._read_fifo(STDOUT_PIPE, stdout, on_application_stop)
      else:
        _logger.warning("Running without root access, full stdout of the "
                        "shell won't be available.")
    parameters.extend(arguments)

    if parameters:
      device_filename = (
          '/sdcard/%s/args_%s' % (_MOJO_SHELL_PACKAGE_NAME, str(uuid.uuid4())))
      with tempfile.NamedTemporaryFile(delete=False) as temp:
        try:
          for parameter in parameters:
            temp.write(parameter)
            temp.write('\n')
          temp.close()
          subprocess.check_call(self._adb_command(
              ['push', temp.name, device_filename]))
        finally:
          os.remove(temp.name)

      cmd += ['--es', 'argsFile', device_filename]

    subprocess.check_call(cmd, stdout=self.verbose_pipe)

  def stop_shell(self):
    """Stops the mojo shell."""
    subprocess.check_call(self._adb_command(['shell',
                                            'am',
                                            'force-stop',
                                            _MOJO_SHELL_PACKAGE_NAME]))

  def clean_logs(self):
    """Cleans the logs on the device."""
    subprocess.check_call(self._adb_command(['logcat', '-c']))

  def show_logs(self, include_native_logs=True):
    """Displays the log for the mojo shell.

    Returns:
      The process responsible for reading the logs.
    """
    tags = _LOGCAT_JAVA_TAGS
    if include_native_logs:
      tags.extend(_LOGCAT_NATIVE_TAGS)
    if self.additional_logcat_tags is not None:
      tags.extend(self.additional_logcat_tags.split(","))
    logcat = subprocess.Popen(
        self._adb_command(['logcat', '-s', ' '.join(tags)]),
        stdout=sys.stdout)
    atexit.register(_exit_if_needed, logcat)
    return logcat

  def forward_observatory_ports(self):
    """Forwards the ports used by the dart observatories to the host machine.
    """
    logcat = subprocess.Popen(self._adb_command(['logcat']),
                              stdout=subprocess.PIPE)
    atexit.register(_exit_if_needed, logcat)

    def _forward_observatories_as_needed():
      while True:
        line = logcat.stdout.readline()
        if not line:
          break
        match = re.search(r'Observatory listening on http://127.0.0.1:(\d+)',
                          line)
        if match:
          device_port = int(match.group(1))
          host_port = self._forward_host_port_to_device(0, device_port)
          print ("Dart observatory available at the host at http://127.0.0.1:%d"
                 % host_port)

    logcat_watch_thread = threading.Thread(
        target=_forward_observatories_as_needed)
    logcat_watch_thread.daemon = True
    logcat_watch_thread.start()

  @overrides(Shell)
  def serve_local_directories(self, mappings, port=0, reuse_servers=False):
    assert mappings
    if reuse_servers:
      assert port, 'Cannot reuse the server when |port| is 0.'
      server_address = ('127.0.0.1', port)
    else:
      server_address = http_server.start_http_server(mappings, port)

    return 'http://127.0.0.1:%d/' % self._forward_device_port_to_host(
        port, server_address[1])

  @overrides(Shell)
  def forward_host_port_to_shell(self, host_port):
    self._forward_host_port_to_device(host_port, host_port)

  @overrides(Shell)
  def run(self, arguments):
    self.clean_logs()
    self.forward_observatory_ports()

    # If we are running as root, don't carry over the native logs from logcat -
    # we will have these in the stdout.
    p = self.show_logs(include_native_logs=(not self._run_adb_as_root()))
    self.start_shell(arguments, sys.stdout, p.terminate)
    p.wait()
    return None

  @overrides(Shell)
  def run_and_get_output(self, arguments, timeout=None):
    class Results:
      """Workaround for Python scoping rules that prevent assigning to variables
      from the outer scope.
      """
      output = None

    def do_run():
      (r, w) = os.pipe()
      with os.fdopen(r, "r") as rf:
        with os.fdopen(w, "w") as wf:
          self.start_shell(arguments, wf, wf.close)
          Results.output = rf.read()

    run_thread = threading.Thread(target=do_run)
    run_thread.start()
    run_thread.join(timeout)

    if run_thread.is_alive():
      self.stop_shell()
      return None, Results.output, True
    return None, Results.output, False
