# 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.

# Tracing agent that captures periodic per-process memory dumps and other
# useful information from ProcFS like utime, stime, OOM stats, etc.

import json
import logging
import optparse
import py_utils

from devil.android import device_utils
from devil.android.device_errors import AdbShellCommandFailedError
from py_trace_event import trace_time as trace_time_module
from systrace import tracing_agents
from systrace import trace_result

TRACE_HEADER = 'ATRACE_PROCESS_DUMP'
TRACE_RESULT_NAME = 'atraceProcessDump'

HELPER_COMMAND = '/data/local/tmp/atrace_helper'
HELPER_STOP_COMMAND = 'kill -TERM `pidof atrace_helper`'
HELPER_DUMP_JSON = '/data/local/tmp/procdump.json'


class AtraceProcessDumpAgent(tracing_agents.TracingAgent):
  def __init__(self):
    super(AtraceProcessDumpAgent, self).__init__()
    self._device = None
    self._dump = None
    self._clock_sync_markers = {}

  @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
  def StartAgentTracing(self, config, timeout=None):
    self._device = device_utils.DeviceUtils(config.device_serial_number)
    cmd = [HELPER_COMMAND, '-b', '-g',
        '-t', str(config.dump_interval_ms),
        '-o', HELPER_DUMP_JSON]
    if config.full_dump_config:
      cmd += ['-m', config.full_dump_config]
    if config.enable_mmaps:
      cmd += ['-s']
    self._device.RunShellCommand(cmd, check_return=True, as_root=True)
    return True

  @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
  def StopAgentTracing(self, timeout=None):
    self._device.RunShellCommand(
        HELPER_STOP_COMMAND,
        shell=True, check_return=True, as_root=True)
    try:
      self._device.RunShellCommand(['test', '-f', HELPER_DUMP_JSON],
          check_return=True, as_root=True)
      self._dump = self._device.ReadFile(HELPER_DUMP_JSON, force_pull=True)
      self._device.RunShellCommand(['rm', HELPER_DUMP_JSON],
          check_return=True, as_root=True)
    except AdbShellCommandFailedError:
      logging.error('AtraceProcessDumpAgent failed to pull data. Check device storage.')
      return False
    return True

  @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
  def GetResults(self, timeout=None):
    result = TRACE_HEADER + '\n' + self._dump
    cs = json.dumps(self._clock_sync_markers)
    result = TRACE_HEADER + \
        '\n{\"clock_sync_markers\":' + cs + ',\n\"dump\":' + self._dump + '}'
    return trace_result.TraceResult(TRACE_RESULT_NAME, result)

  def SupportsExplicitClockSync(self):
    return True

  def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
    with self._device.adb.PersistentShell(self._device.serial) as shell:
      ts_in_controller_domain = trace_time_module.Now()
      output = shell.RunCommand(HELPER_COMMAND + ' --echo-ts', close=True)
      ts_in_agent_domain = int(output[0][0])
      self._clock_sync_markers[sync_id] = ts_in_agent_domain
      did_record_sync_marker_callback(ts_in_controller_domain, sync_id)


class AtraceProcessDumpConfig(tracing_agents.TracingConfig):
  def __init__(self, enabled, device_serial_number,
               dump_interval_ms, full_dump_config, enable_mmaps):
    tracing_agents.TracingConfig.__init__(self)
    self.enabled = enabled
    self.device_serial_number = device_serial_number
    self.dump_interval_ms = dump_interval_ms
    self.full_dump_config = full_dump_config
    self.enable_mmaps = enable_mmaps


def add_options(parser):
  options = optparse.OptionGroup(parser, 'Atrace process dump options')
  options.add_option('--process-dump', dest='process_dump_enable',
                     default=False, action='store_true',
                     help='Capture periodic per-process memory dumps.')
  options.add_option('--process-dump-interval', dest='process_dump_interval_ms',
                     default=5000,
                     help='Interval between memory dumps in milliseconds.')
  options.add_option('--process-dump-full', dest='process_dump_full_config',
                     default=None,
                     help='Capture full memory dumps for some processes.\n' \
                          'Value: all, apps or comma-separated process names.')
  options.add_option('--process-dump-mmaps', dest='process_dump_mmaps',
                     default=False, action='store_true',
                     help='Capture VM regions and memory-mapped files.\n' \
                          'It increases dump size dramatically, hence only ' \
                          'has effect if --process-dump-full is a whitelist.')
  return options


def get_config(options):
  can_enable = (options.target == 'android') and (not options.from_file)
  return AtraceProcessDumpConfig(
    enabled=(options.process_dump_enable and can_enable),
    device_serial_number=options.device_serial_number,
    dump_interval_ms=options.process_dump_interval_ms,
    full_dump_config=options.process_dump_full_config,
    enable_mmaps=options.process_dump_mmaps
  )


def try_create_agent(config):
  if config.enabled:
    return AtraceProcessDumpAgent()
  return None
