#!/usr/bin/env python3
# Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

import argparse
import datetime
import os
import re
import statistics
import sys
import time

try:
  from perfetto.trace_processor import TraceProcessor
except ImportError:
  sys.exit(
      'Unable to analyze perfetto trace without the perfetto library. '
      'Install instructions:\n'
      '    sudo apt install python3-pip\n'
      '    pip3 install perfetto')

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import adb_utils
import apk_utils
import perfetto_utils
import utils

def setup(options):
  # Increase screen off timeout to avoid device screen turns off.
  twenty_four_hours_in_millis = 24 * 60 * 60 * 1000
  previous_screen_off_timeout = adb_utils.get_screen_off_timeout(
      options.device_id)
  adb_utils.set_screen_off_timeout(
      twenty_four_hours_in_millis, options.device_id)

  # Unlock device.
  adb_utils.unlock(options.device_id, options.device_pin)

  teardown_options = {
    'previous_screen_off_timeout': previous_screen_off_timeout
  }
  return teardown_options

def teardown(options, teardown_options):
  # Reset screen off timeout.
  adb_utils.set_screen_off_timeout(
      teardown_options['previous_screen_off_timeout'],
      options.device_id)

def run_all(apk_or_apks, options, tmp_dir):
  # Launch app while collecting information.
  data_total = {}
  for iteration in range(1, options.iterations + 1):
    print('Starting iteration %i' % iteration)
    out_dir = os.path.join(options.out_dir, str(iteration))
    teardown_options = setup_for_run(apk_or_apks, out_dir, options)
    data = run(out_dir, options, tmp_dir)
    teardown_for_run(out_dir, options, teardown_options)
    add_data(data_total, data)
    print('Result:')
    print(data)
    print(compute_data_summary(data_total))
    print('Done')
  print('Average result:')
  data_summary = compute_data_summary(data_total)
  print(data_summary)
  write_data(options.out_dir, data_summary)

def compute_data_summary(data_total):
  data_summary = {}
  for key, value in data_total.items():
    if not isinstance(value, list):
      data_summary[key] = value
      continue
    data_summary['%s_avg' % key] = round(statistics.mean(value), 1)
    data_summary['%s_med' % key] = statistics.median(value)
  return data_summary

def setup_for_run(apk_or_apks, out_dir, options):
  adb_utils.root(options.device_id)

  print('Installing')
  adb_utils.uninstall(options.app_id, options.device_id)
  if apk_or_apks['apk']:
    adb_utils.install(apk_or_apks['apk'], options.device_id)
  else:
    assert apk_or_apks['apks']
    adb_utils.install_apks(apk_or_apks['apks'], options.device_id)

  os.makedirs(out_dir, exist_ok=True)

  # AOT compile.
  if options.aot:
    print('AOT compiling')
    if options.baseline_profile:
      adb_utils.clear_profile_data(options.app_id, options.device_id)
      adb_utils.install_profile(options.app_id, options.device_id)
    else:
      adb_utils.force_compilation(options.app_id, options.device_id)

  # Cooldown and then unlock device.
  if options.cooldown > 0:
    print('Cooling down for %i seconds' % options.cooldown)
    assert adb_utils.get_screen_state(options.device_id).is_off()
    time.sleep(options.cooldown)
    teardown_options = adb_utils.prepare_for_interaction_with_device(
        options.device_id, options.device_pin)
  else:
    teardown_options = None

  # Prelaunch for hot startup.
  if options.hot_startup:
    print('Prelaunching')
    adb_utils.launch_activity(
        options.app_id,
        options.main_activity,
        options.device_id,
        wait_for_activity_to_launch=False)
    time.sleep(options.startup_duration)
    adb_utils.navigate_to_home_screen(options.device_id)
    time.sleep(1)

  # Drop caches before run.
  adb_utils.drop_caches(options.device_id)
  return teardown_options

def teardown_for_run(out_dir, options, teardown_options):
  assert adb_utils.get_screen_state(options.device_id).is_on_and_unlocked()

  if options.capture_screen:
    target = os.path.join(out_dir, 'screen.png')
    adb_utils.capture_screen(target, options.device_id)

  if options.cooldown > 0:
    adb_utils.teardown_after_interaction_with_device(
        teardown_options, options.device_id)
    adb_utils.ensure_screen_off(options.device_id)
  else:
    assert teardown_options is None

def run(out_dir, options, tmp_dir):
  assert adb_utils.get_screen_state(options.device_id).is_on_and_unlocked()

  # Start logcat for time to fully drawn.
  logcat_process = None
  if options.fully_drawn_logcat_message:
    adb_utils.clear_logcat(options.device_id)
    logcat_process = adb_utils.start_logcat(
        options.device_id,
        format='time',
        filter='%s ActivityTaskManager:I' % options.fully_drawn_logcat_filter,
        silent=True)

  # Start perfetto trace collector.
  perfetto_process = None
  perfetto_trace_path = None
  if options.perfetto:
    perfetto_process, perfetto_trace_path = perfetto_utils.record_android_trace(
        out_dir, tmp_dir, options.device_id)

  # Launch main activity.
  launch_activity_result = adb_utils.launch_activity(
      options.app_id,
      options.main_activity,
      options.device_id,
      intent_data_uri=options.intent_data_uri,
      wait_for_activity_to_launch=True)

  # Wait for app to be fully drawn.
  logcat = None
  if logcat_process is not None:
    wait_until_fully_drawn(logcat_process, options)
    logcat = adb_utils.stop_logcat(logcat_process)

  # Wait for perfetto trace collector to stop.
  if options.perfetto:
    perfetto_utils.stop_record_android_trace(perfetto_process, out_dir)

  # Get minor and major page faults from app process.
  data = compute_data(
    launch_activity_result, logcat, perfetto_trace_path, options)
  write_data(out_dir, data)
  return data

def wait_until_fully_drawn(logcat_process, options):
  print('Waiting until app is fully drawn')
  while True:
    is_fully_drawn = any(
        is_app_fully_drawn_logcat_message(line, options) \
        for line in logcat_process.lines)
    if is_fully_drawn:
      break
    time.sleep(1)
  print('Done')

def compute_time_to_fully_drawn_from_time_to_first_frame(logcat, options):
  displayed_time = None
  fully_drawn_time = None
  for line in logcat:
    if is_app_displayed_logcat_message(line, options):
      displayed_time = get_timestamp_from_logcat_message(line)
    elif is_app_fully_drawn_logcat_message(line, options):
      fully_drawn_time = get_timestamp_from_logcat_message(line)
  assert displayed_time is not None
  assert fully_drawn_time is not None
  assert fully_drawn_time > displayed_time
  return fully_drawn_time - displayed_time

def get_timestamp_from_logcat_message(line):
  time_end_index = len('00-00 00:00:00.000')
  time_format = '%m-%d %H:%M:%S.%f'
  time_str = line[0:time_end_index] + '000'
  time_seconds = datetime.datetime.strptime(time_str, time_format).timestamp()
  return int(time_seconds * 1000)

def is_app_displayed_logcat_message(line, options):
  substring = 'Displayed %s' % adb_utils.get_component_name(
      options.app_id, options.main_activity)
  return substring in line

def is_app_fully_drawn_logcat_message(line, options):
  return re.search(options.fully_drawn_logcat_message, line)

def add_data(data_total, data):
  for key, value in data.items():
    if key == 'app_id':
      assert data_total.get(key, value) == value
      data_total[key] = value
    if key == 'time':
      continue
    if key in data_total:
      if key == 'app_id':
        assert data_total[key] == value
      else:
        existing_value = data_total[key]
        assert isinstance(value, int)
        assert isinstance(existing_value, list)
        existing_value.append(value)
    else:
      assert isinstance(value, int), key
      data_total[key] = [value]

def compute_data(launch_activity_result, logcat, perfetto_trace_path, options):
  minfl, majfl = adb_utils.get_minor_major_page_faults(
      options.app_id, options.device_id)
  meminfo = adb_utils.get_meminfo(options.app_id, options.device_id)
  data = {
    'app_id': options.app_id,
    'time': time.ctime(time.time()),
    'minfl': minfl,
    'majfl': majfl
  }
  data.update(meminfo)
  startup_data = compute_startup_data(
      launch_activity_result, logcat, perfetto_trace_path, options)
  return data | startup_data

def compute_startup_data(
    launch_activity_result, logcat, perfetto_trace_path, options):
  time_to_first_frame = launch_activity_result.get('total_time')
  startup_data = {
    'adb_startup': time_to_first_frame
  }

  # Time to fully drawn.
  if options.fully_drawn_logcat_message:
    startup_data['time_to_fully_drawn'] = \
        compute_time_to_fully_drawn_from_time_to_first_frame(logcat, options) \
            + time_to_first_frame

  # Perfetto stats.
  perfetto_startup_data = {}
  if options.perfetto:
    trace_processor = TraceProcessor(file_path=perfetto_trace_path)

    # Compute time to first frame according to the builtin android_startup
    # metric.
    startup_metric = trace_processor.metric(['android_startup'])
    time_to_first_frame_ms = \
        startup_metric.android_startup.startup[0].to_first_frame.dur_ms
    perfetto_startup_data['perfetto_startup'] = round(time_to_first_frame_ms)

    if not options.hot_startup:
      # Compute time to first and last doFrame event.
      bind_application_slice = perfetto_utils.find_unique_slice_by_name(
          'bindApplication', options, trace_processor)
      activity_start_slice = perfetto_utils.find_unique_slice_by_name(
          'activityStart', options, trace_processor)
      do_frame_slices = perfetto_utils.find_slices_by_name(
          'Choreographer#doFrame', options, trace_processor)
      first_do_frame_slice = next(do_frame_slices)
      *_, last_do_frame_slice = do_frame_slices

      perfetto_startup_data.update({
        'time_to_first_choreographer_do_frame_ms':
            round(perfetto_utils.get_slice_end_since_start(
                first_do_frame_slice, bind_application_slice)),
        'time_to_last_choreographer_do_frame_ms':
            round(perfetto_utils.get_slice_end_since_start(
                last_do_frame_slice, bind_application_slice))
      })

  # Return combined startup data.
  return startup_data | perfetto_startup_data

def write_data(out_dir, data):
  data_path = os.path.join(out_dir, 'data.txt')
  with open(data_path, 'w') as f:
    for key, value in data.items():
      f.write('%s=%s\n' % (key, str(value)))

def parse_options(argv):
  result = argparse.ArgumentParser(
      description='Generate a perfetto trace file.')
  result.add_argument('--app-id',
                      help='The application ID of interest',
                      required=True)
  result.add_argument('--aot',
                      help='Enable force compilation',
                      default=False,
                      action='store_true')
  result.add_argument('--aot-profile',
                      help='Enable force compilation using profiles',
                      default=False,
                      action='store_true')
  result.add_argument('--apk',
                      help='Path to the .apk')
  result.add_argument('--apks',
                      help='Path to the .apks')
  result.add_argument('--bundle',
                      help='Path to the .aab')
  result.add_argument('--capture-screen',
                      help='Take a screenshot after each test',
                      default=False,
                      action='store_true')
  result.add_argument('--cooldown',
                      help='Seconds to wait before running each iteration',
                      default=0,
                      type=int)
  result.add_argument('--device-id',
                      help='Device id (e.g., emulator-5554).')
  result.add_argument('--device-pin',
                      help='Device pin code (e.g., 1234)')
  result.add_argument('--fully-drawn-logcat-filter',
                      help='Logcat filter for the fully drawn message '
                           '(e.g., "tag:I")')
  result.add_argument('--fully-drawn-logcat-message',
                      help='Logcat message that indicates that the app is '
                           'fully drawn (regexp)')
  result.add_argument('--hot-startup',
                      help='Measure hot startup instead of cold startup',
                      default=False,
                      action='store_true')
  result.add_argument('--intent-data-uri',
                      help='Value to use for the -d argument to the intent '
                           'that is used to launch the app')
  result.add_argument('--iterations',
                      help='Number of traces to generate',
                      default=1,
                      type=int)
  result.add_argument('--main-activity',
                      help='Main activity class name',
                      required=True)
  result.add_argument('--no-perfetto',
                      help='Disables perfetto trace generation',
                      action='store_true',
                      default=False)
  result.add_argument('--out-dir',
                      help='Directory to store trace files in',
                      required=True)
  result.add_argument('--baseline-profile',
                      help='Baseline profile to install')
  result.add_argument('--startup-duration',
                      help='Duration in seconds before shutting down app',
                      default=15,
                      type=int)
  options, args = result.parse_known_args(argv)
  setattr(options, 'perfetto', not options.no_perfetto)

  paths = [
      path for path in [options.apk, options.apks, options.bundle]
      if path is not None]
  assert len(paths) == 1, 'Expected exactly one .apk, .apks, or .aab file.'

  # Build .apks file up front to avoid building the bundle upon each install.
  if options.bundle:
    os.makedirs(options.out_dir, exist_ok=True)
    options.apks = os.path.join(options.out_dir, 'Bundle.apks')
    adb_utils.build_apks_from_bundle(
        options.bundle, options.apks, overwrite=True)
    del options.bundle

  # Profile is only used with --aot.
  assert options.aot or not options.baseline_profile

  # Fully drawn logcat filter and message is absent or both present.
  assert (options.fully_drawn_logcat_filter is None) == \
      (options.fully_drawn_logcat_message is None)

  return options, args

def global_setup(options):
  # If there is no cooldown then unlock the screen once. Otherwise we turn off
  # the screen during the cooldown and unlock the screen before each iteration.
  teardown_options = None
  if options.cooldown == 0:
    teardown_options = adb_utils.prepare_for_interaction_with_device(
        options.device_id, options.device_pin)
    assert adb_utils.get_screen_state(options.device_id).is_on()
  else:
    adb_utils.ensure_screen_off(options.device_id)
  return teardown_options

def global_teardown(options, teardown_options):
  if options.cooldown == 0:
    adb_utils.teardown_after_interaction_with_device(
        teardown_options, options.device_id)
  else:
    assert teardown_options is None

def main(argv):
  (options, args) = parse_options(argv)
  with utils.TempDir() as tmp_dir:
    apk_or_apks = { 'apk': options.apk, 'apks': options.apks }
    if options.baseline_profile:
      assert not options.apks, 'Unimplemented'
      apk_or_apks['apk'] = apk_utils.add_baseline_profile_to_apk(
          options.apk, options.baseline_profile, tmp_dir)
    teardown_options = global_setup(options)
    run_all(apk_or_apks, options, tmp_dir)
    global_teardown(options, teardown_options)

if __name__ == '__main__':
  sys.exit(main(sys.argv[1:]))