# Copyright 2017 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 logging
import os
import subprocess
import threading
import time
import uuid

from devil.utils import reraiser_thread
from pylib import constants


_MINIUMUM_TIMEOUT = 3.0
_PER_LINE_TIMEOUT = .002  # Should be able to process 500 lines per second.
_PROCESS_START_TIMEOUT = 10.0
_MAX_RESTARTS = 10  # Should be plenty unless tool is crashing on start-up.


class Deobfuscator(object):
  def __init__(self, mapping_path):
    script_path = os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android',
                               'stacktrace', 'java_deobfuscate.py')
    cmd = [script_path, mapping_path]
    # Allow only one thread to call TransformLines() at a time.
    self._lock = threading.Lock()
    # Ensure that only one thread attempts to kill self._proc in Close().
    self._close_lock = threading.Lock()
    self._closed_called = False
    # Assign to None so that attribute exists if Popen() throws.
    self._proc = None
    # Start process eagerly to hide start-up latency.
    self._proc_start_time = time.time()
    self._proc = subprocess.Popen(
        cmd, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
        close_fds=True)

  def IsClosed(self):
    return self._closed_called or self._proc.returncode is not None

  def IsBusy(self):
    return self._lock.locked()

  def IsReady(self):
    return not self.IsClosed() and not self.IsBusy()

  def TransformLines(self, lines):
    """Deobfuscates obfuscated names found in the given lines.

    If anything goes wrong (process crashes, timeout, etc), returns |lines|.

    Args:
      lines: A list of strings without trailing newlines.

    Returns:
      A list of strings without trailing newlines.
    """
    if not lines:
      return []

    # Deobfuscated stacks contain more frames than obfuscated ones when method
    # inlining occurs. To account for the extra output lines, keep reading until
    # this eof_line token is reached.
    eof_line = uuid.uuid4().hex
    out_lines = []

    def deobfuscate_reader():
      while True:
        line = self._proc.stdout.readline()
        # Return an empty string at EOF (when stdin is closed).
        if not line:
          break
        line = line[:-1]
        if line == eof_line:
          break
        out_lines.append(line)

    if self.IsBusy():
      logging.warning('deobfuscator: Having to wait for Java deobfuscation.')

    # Allow only one thread to operate at a time.
    with self._lock:
      if self.IsClosed():
        if not self._closed_called:
          logging.warning('deobfuscator: Process exited with code=%d.',
                          self._proc.returncode)
          self.Close()
        return lines

      # TODO(agrieve): Can probably speed this up by only sending lines through
      #     that might contain an obfuscated name.
      reader_thread = reraiser_thread.ReraiserThread(deobfuscate_reader)
      reader_thread.start()

      try:
        self._proc.stdin.write('\n'.join(lines))
        self._proc.stdin.write('\n{}\n'.format(eof_line))
        self._proc.stdin.flush()
        time_since_proc_start = time.time() - self._proc_start_time
        timeout = (max(0, _PROCESS_START_TIMEOUT - time_since_proc_start) +
                   max(_MINIUMUM_TIMEOUT, len(lines) * _PER_LINE_TIMEOUT))
        reader_thread.join(timeout)
        if self.IsClosed():
          logging.warning(
              'deobfuscator: Close() called by another thread during join().')
          return lines
        if reader_thread.is_alive():
          logging.error('deobfuscator: Timed out.')
          self.Close()
          return lines
        return out_lines
      except IOError:
        logging.exception('deobfuscator: Exception during java_deobfuscate')
        self.Close()
        return lines

  def Close(self):
    with self._close_lock:
      needs_closing = not self.IsClosed()
      self._closed_called = True

    if needs_closing:
      self._proc.stdin.close()
      self._proc.kill()
      self._proc.wait()

  def __del__(self):
    # self._proc is None when Popen() fails.
    if not self._closed_called and self._proc:
      logging.error('deobfuscator: Forgot to Close()')
      self.Close()


class DeobfuscatorPool(object):
  # As of Sep 2017, each instance requires about 500MB of RAM, as measured by:
  # /usr/bin/time -v build/android/stacktrace/java_deobfuscate.py \
  #     out/Release/apks/ChromePublic.apk.mapping
  def __init__(self, mapping_path, pool_size=4):
    self._mapping_path = mapping_path
    self._pool = [Deobfuscator(mapping_path) for _ in xrange(pool_size)]
    # Allow only one thread to select from the pool at a time.
    self._lock = threading.Lock()
    self._num_restarts = 0

  def TransformLines(self, lines):
    with self._lock:
      assert self._pool, 'TransformLines() called on a closed DeobfuscatorPool.'

      # De-obfuscation is broken.
      if self._num_restarts == _MAX_RESTARTS:
        raise Exception('Deobfuscation seems broken.')

      # Restart any closed Deobfuscators.
      for i, d in enumerate(self._pool):
        if d.IsClosed():
          logging.warning('deobfuscator: Restarting closed instance.')
          self._pool[i] = Deobfuscator(self._mapping_path)
          self._num_restarts += 1
          if self._num_restarts == _MAX_RESTARTS:
            logging.warning('deobfuscator: MAX_RESTARTS reached.')

      selected = next((x for x in self._pool if x.IsReady()), self._pool[0])
      # Rotate the order so that next caller will not choose the same one.
      self._pool.remove(selected)
      self._pool.append(selected)

    return selected.TransformLines(lines)

  def Close(self):
    with self._lock:
      for d in self._pool:
        d.Close()
      self._pool = None
