1#!/usr/bin/env python3
2#
3# Copyright (C) 2023 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import argparse
19import os
20import subprocess
21import sys
22
23def subprocess_run(command, shell=True):
24    try:
25        print(f'subprocess run {command}')
26        result = subprocess.run(command, shell=shell, stdout=subprocess.PIPE, check=True)
27    except Exception as e:
28        raise Exception(f'Execution error for {command}: {e}')
29
30    return result.stdout.decode('utf-8')
31
32def adb_run(ip, cmd):
33    if cmd == ['connect']:
34        adb_cmd = ['adb', 'connect', ip]
35    else:
36        adb_cmd = ['adb', '-s', ip] + cmd
37    return subprocess_run(adb_cmd, False)
38
39def prepare_qnx(tracing_dir, qnx_dev_dir, qnx_ip, filepath):
40    source_file = os.path.join(tracing_dir, 'tooling', 'qnx_perfetto.py')
41    target_file = os.path.join(qnx_dev_dir, 'qnx_perfetto.py')
42    try:
43        os.symlink(source_file, target_file)
44    except FileExistsError:
45        print(f"Symbolic link creation failed: {target_file} already exists.")
46    except Exception as e:
47        sys.exit(f"An error occurred: {type(e).__name__}: {e}")
48
49    # setup qnx environment source qnxsdp-env.sh
50    qnx_env_file = os.path.join(qnx_dev_dir, "qnxsdp-env.sh")
51    clock_util = 'QnxClocktime'
52    command = f'source {qnx_env_file} && qcc -Vgcc_ntoaarch64le {filepath} -o {clock_util}'
53    subprocess_run(command)
54
55    command = f'scp -F /dev/null {clock_util} root@{qnx_ip}:/bin/'
56    subprocess_run(command)
57
58def prepare_android(serial_num, aaos_time_util):
59    adb_run(serial_num, ['connect'])
60    adb_run(serial_num, ['root'])
61    adb_run(serial_num, ['remount'])
62
63    command = ['push', aaos_time_util, '/vendor/bin/android.automotive.time_util']
64    adb_run(serial_num, command)
65
66def parse_arguments():
67    parser = argparse.ArgumentParser(
68        prog = 'prepare_tracing.py',
69        description='Setup environment and tools for cross-VM Android tracing')
70    parser.add_argument('--host_ip', required=True,
71                             help = 'host IP address')
72    parser.add_argument('--qnx_dev_dir', required=True,
73                             help = 'QNX SDK Directory')
74    parser.add_argument('--tracing_tool_dir', required=True,
75                             help = 'Tracing Tool Directory Path')
76    # One can build Anroid time utility function with source code and locates at:
77    # ./target/product/trout_arm64/vendor/bin/android.automotive.time_util
78    parser.add_argument('--aaos_time_util', help = 'Android Clock Executable File')
79    parser.add_argument('--guest_serial', required='--aaos_time_util' in sys.argv,
80                        help = 'Guest VM serial number. Required argument if --aaos_time_util is set')
81    return parser.parse_args()
82
83def main():
84    args = parse_arguments()
85
86    clock_file_path = os.path.join(args.tracing_tool_dir, "time_utility", "ClocktimeMain.cpp")
87    prepare_qnx(args.tracing_tool_dir, args.qnx_dev_dir, args.host_ip, clock_file_path)
88
89    if args.aaos_time_util:
90        prepare_android(args.guest_serial, args.aaos_time_util)
91
92if __name__ == '__main__':
93    main()
94