Scripts for getting data from app startup

Change-Id: I7433b2dbf6cc18625fa600df17bfeffe817952db
diff --git a/tools/startup/adb_utils.py b/tools/startup/adb_utils.py
new file mode 100644
index 0000000..cbcd724
--- /dev/null
+++ b/tools/startup/adb_utils.py
@@ -0,0 +1,161 @@
+#!/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.
+
+from enum import Enum
+import subprocess
+import time
+
+DEVNULL=subprocess.DEVNULL
+
+class ScreenState(Enum):
+  OFF_LOCKED = 1,
+  OFF_UNLOCKED = 2
+  ON_LOCKED = 3
+  ON_UNLOCKED = 4
+
+  def is_off(self):
+    return self == ScreenState.OFF_LOCKED or self == ScreenState.OFF_UNLOCKED
+
+  def is_on(self):
+    return self == ScreenState.ON_LOCKED or self == ScreenState.ON_UNLOCKED
+
+  def is_on_and_locked(self):
+    return self == ScreenState.ON_LOCKED
+
+  def is_on_and_unlocked(self):
+    return self == ScreenState.ON_UNLOCKED
+
+def create_adb_cmd(arguments, device_id=None):
+  assert isinstance(arguments, list) or isinstance(arguments, str)
+  cmd = ['adb']
+  if device_id is not None:
+    cmd.append('-s')
+    cmd.append(device_id)
+  cmd.extend(arguments if isinstance(arguments, list) else arguments.split(' '))
+  return cmd
+
+def clear_profile_data(app_id, device_id=None):
+  cmd = create_adb_cmd(
+      'shell cmd package compile --reset %s' % app_id, device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def drop_caches(device_id=None):
+  cmd = create_adb_cmd(
+      ['shell', 'echo 3 > /proc/sys/vm/drop_caches'], device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def force_compilation(app_id, device_id=None):
+  cmd = create_adb_cmd(
+      'shell cmd package compile -m speed -f %s' % app_id, device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def force_profile_compilation(app_id, device_id=None):
+  cmd = create_adb_cmd(
+      'shell cmd package compile -m speed-profile -f %s' % app_id, device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def get_minor_major_page_faults(app_id, device_id=None):
+  pid = get_pid(app_id, device_id)
+  cmd = create_adb_cmd('shell ps -p %i -o MINFL,MAJFL' % pid)
+  stdout = subprocess.check_output(cmd).decode('utf-8')
+  lines_it = iter(stdout.splitlines())
+  first_line = next(lines_it)
+  assert first_line == ' MINFL  MAJFL'
+  second_line = next(lines_it)
+  minfl, majfl = second_line.split()
+  assert minfl.isdigit()
+  assert majfl.isdigit()
+  return (int(minfl), int(majfl))
+
+def get_pid(app_id, device_id=None):
+  cmd = create_adb_cmd('shell pidof %s' % app_id, device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  assert stdout.isdigit()
+  pid = int(stdout)
+  return pid
+
+def get_screen_state(device_id=None):
+  cmd = create_adb_cmd('shell dumpsys nfc', device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  screen_state_value = None
+  for line in stdout.splitlines():
+    if line.startswith('mScreenState='):
+      value_start_index = len('mScreenState=')
+      screen_state_value=line[value_start_index:]
+  if screen_state_value is None:
+    raise ValueError('Expected to find mScreenState in: adb shell dumpsys nfc')
+  if not hasattr(ScreenState, screen_state_value):
+    raise ValueError(
+        'Expected mScreenState to be a value of ScreenState, was: %s'
+            % screen_state_value)
+  return ScreenState[screen_state_value]
+
+def get_screen_off_timeout(device_id=None):
+  cmd = create_adb_cmd(
+      'shell settings get system screen_off_timeout', device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  assert stdout.isdigit()
+  screen_off_timeout = int(stdout)
+  return screen_off_timeout
+
+def install(apk, device_id=None):
+  cmd = create_adb_cmd('install %s' % apk, device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8')
+  assert 'Success' in stdout
+
+def issue_key_event(key_event, device_id=None, sleep_in_seconds=1):
+  cmd = create_adb_cmd('shell input keyevent %s' % key_event, device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  assert len(stdout) == 0
+  time.sleep(sleep_in_seconds)
+
+def launch_activity(app_id, activity, device_id=None):
+  cmd = create_adb_cmd(
+    'shell am start -n %s/%s' % (app_id, activity), device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  expected_stdout = (
+      'Starting: Intent { cmp=%s/.%s }' % (app_id, activity[len(app_id)+1:]))
+  assert stdout == expected_stdout, 'was %s' % stdout
+
+def root(device_id=None):
+  cmd = create_adb_cmd('root', device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def set_screen_off_timeout(screen_off_timeout_in_millis, device_id=None):
+  cmd = create_adb_cmd(
+      'shell settings put system screen_off_timeout %i'
+          % screen_off_timeout_in_millis,
+      device_id)
+  stdout = subprocess.check_output(cmd).decode('utf-8').strip()
+  assert len(stdout) == 0
+
+def stop_app(app_id, device_id=None):
+  cmd = create_adb_cmd('shell am force-stop %s' % apk, device_id)
+  subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
+
+def uninstall(app_id, device_id=None):
+  cmd = create_adb_cmd('uninstall %s' % app_id, device_id)
+  process_result = subprocess.run(cmd, capture_output=True)
+  stdout = process_result.stdout.decode('utf-8')
+  stderr = process_result.stderr.decode('utf-8')
+  if process_result.returncode == 0:
+    assert 'Success' in stdout
+  else:
+    expected_error = (
+        'java.lang.IllegalArgumentException: Unknown package: %s' % app_id)
+    assert expected_error in stderr
+
+def unlock(device_id=None, device_pin=None):
+  screen_state = get_screen_state(device_id)
+  if screen_state.is_off():
+    issue_key_event('KEYCODE_POWER', device_id)
+    screen_state = get_screen_state(device_id)
+  assert screen_state.is_on(), 'was %s' % screen_state
+  if screen_state.is_on_and_locked():
+    if device_pin is not None:
+      raise NotImplementedError('Device unlocking with pin not implemented')
+    issue_key_event('KEYCODE_MENU', device_id)
+    screen_state = get_screen_state(device_id)
+  assert screen_state.is_on_and_unlocked(), 'was %s' % screen_state