1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2018 The Chromium Authors 2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 4*8975f5c5SAndroid Build Coastguard Worker 5*8975f5c5SAndroid Build Coastguard Workerimport contextlib 6*8975f5c5SAndroid Build Coastguard Workerimport logging 7*8975f5c5SAndroid Build Coastguard Workerimport os 8*8975f5c5SAndroid Build Coastguard Workerimport shutil 9*8975f5c5SAndroid Build Coastguard Workerimport subprocess 10*8975f5c5SAndroid Build Coastguard Workerimport sys 11*8975f5c5SAndroid Build Coastguard Workerimport tempfile 12*8975f5c5SAndroid Build Coastguard Worker 13*8975f5c5SAndroid Build Coastguard Workerfrom devil import devil_env 14*8975f5c5SAndroid Build Coastguard Workerfrom devil.android import device_signal, device_errors 15*8975f5c5SAndroid Build Coastguard Workerfrom devil.android.sdk import version_codes 16*8975f5c5SAndroid Build Coastguard Workerfrom pylib import constants 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard Worker 19*8975f5c5SAndroid Build Coastguard Workerdef _ProcessType(proc): 20*8975f5c5SAndroid Build Coastguard Worker _, _, suffix = proc.name.partition(':') 21*8975f5c5SAndroid Build Coastguard Worker if not suffix: 22*8975f5c5SAndroid Build Coastguard Worker return 'browser' 23*8975f5c5SAndroid Build Coastguard Worker if suffix.startswith('sandboxed_process'): 24*8975f5c5SAndroid Build Coastguard Worker return 'renderer' 25*8975f5c5SAndroid Build Coastguard Worker if suffix.startswith('privileged_process'): 26*8975f5c5SAndroid Build Coastguard Worker return 'gpu' 27*8975f5c5SAndroid Build Coastguard Worker return None 28*8975f5c5SAndroid Build Coastguard Worker 29*8975f5c5SAndroid Build Coastguard Worker 30*8975f5c5SAndroid Build Coastguard Workerdef _GetSpecifiedPID(device, package_name, process_specifier): 31*8975f5c5SAndroid Build Coastguard Worker if process_specifier is None: 32*8975f5c5SAndroid Build Coastguard Worker return None 33*8975f5c5SAndroid Build Coastguard Worker 34*8975f5c5SAndroid Build Coastguard Worker # Check for numeric PID 35*8975f5c5SAndroid Build Coastguard Worker try: 36*8975f5c5SAndroid Build Coastguard Worker pid = int(process_specifier) 37*8975f5c5SAndroid Build Coastguard Worker return pid 38*8975f5c5SAndroid Build Coastguard Worker except ValueError: 39*8975f5c5SAndroid Build Coastguard Worker pass 40*8975f5c5SAndroid Build Coastguard Worker 41*8975f5c5SAndroid Build Coastguard Worker # Check for exact process name; can be any of these formats: 42*8975f5c5SAndroid Build Coastguard Worker # <package>:<process name>, i.e. 'org.chromium.chrome:sandboxed_process0' 43*8975f5c5SAndroid Build Coastguard Worker # :<process name>, i.e. ':sandboxed_process0' 44*8975f5c5SAndroid Build Coastguard Worker # <process name>, i.e. 'sandboxed_process0' 45*8975f5c5SAndroid Build Coastguard Worker full_process_name = process_specifier 46*8975f5c5SAndroid Build Coastguard Worker if process_specifier.startswith(':'): 47*8975f5c5SAndroid Build Coastguard Worker full_process_name = package_name + process_specifier 48*8975f5c5SAndroid Build Coastguard Worker elif ':' not in process_specifier: 49*8975f5c5SAndroid Build Coastguard Worker full_process_name = '%s:%s' % (package_name, process_specifier) 50*8975f5c5SAndroid Build Coastguard Worker matching_processes = device.ListProcesses(full_process_name) 51*8975f5c5SAndroid Build Coastguard Worker if len(matching_processes) == 1: 52*8975f5c5SAndroid Build Coastguard Worker return matching_processes[0].pid 53*8975f5c5SAndroid Build Coastguard Worker if len(matching_processes) > 1: 54*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Found %d processes with name "%s".' % ( 55*8975f5c5SAndroid Build Coastguard Worker len(matching_processes), process_specifier)) 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Worker # Check for process type (i.e. 'renderer') 58*8975f5c5SAndroid Build Coastguard Worker package_processes = device.ListProcesses(package_name) 59*8975f5c5SAndroid Build Coastguard Worker matching_processes = [p for p in package_processes if ( 60*8975f5c5SAndroid Build Coastguard Worker _ProcessType(p) == process_specifier)] 61*8975f5c5SAndroid Build Coastguard Worker if process_specifier == 'renderer' and len(matching_processes) > 1: 62*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Found %d renderer processes; please re-run with only ' 63*8975f5c5SAndroid Build Coastguard Worker 'one open tab.' % len(matching_processes)) 64*8975f5c5SAndroid Build Coastguard Worker if len(matching_processes) != 1: 65*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Found %d processes of type "%s".' % ( 66*8975f5c5SAndroid Build Coastguard Worker len(matching_processes), process_specifier)) 67*8975f5c5SAndroid Build Coastguard Worker return matching_processes[0].pid 68*8975f5c5SAndroid Build Coastguard Worker 69*8975f5c5SAndroid Build Coastguard Worker 70*8975f5c5SAndroid Build Coastguard Workerdef _ThreadsForProcess(device, pid): 71*8975f5c5SAndroid Build Coastguard Worker # The thread list output format for 'ps' is the same regardless of version. 72*8975f5c5SAndroid Build Coastguard Worker # Here's the column headers, and a sample line for a thread belonging to 73*8975f5c5SAndroid Build Coastguard Worker # pid 12345 (note that the last few columns are not aligned with headers): 74*8975f5c5SAndroid Build Coastguard Worker # 75*8975f5c5SAndroid Build Coastguard Worker # USER PID TID PPID VSZ RSS WCHAN ADDR S CMD 76*8975f5c5SAndroid Build Coastguard Worker # u0_i101 12345 24680 567 1357902 97531 futex_wait_queue_me e85acd9c S \ 77*8975f5c5SAndroid Build Coastguard Worker # CrRendererMain 78*8975f5c5SAndroid Build Coastguard Worker if device.build_version_sdk >= version_codes.OREO: 79*8975f5c5SAndroid Build Coastguard Worker pid_regex = ( 80*8975f5c5SAndroid Build Coastguard Worker r'^[[:graph:]]\{1,\}[[:blank:]]\{1,\}%d[[:blank:]]\{1,\}' % pid) 81*8975f5c5SAndroid Build Coastguard Worker ps_cmd = "ps -T -e | grep '%s'" % pid_regex 82*8975f5c5SAndroid Build Coastguard Worker ps_output_lines = device.RunShellCommand( 83*8975f5c5SAndroid Build Coastguard Worker ps_cmd, shell=True, check_return=True) 84*8975f5c5SAndroid Build Coastguard Worker else: 85*8975f5c5SAndroid Build Coastguard Worker ps_cmd = ['ps', '-p', str(pid), '-t'] 86*8975f5c5SAndroid Build Coastguard Worker ps_output_lines = device.RunShellCommand(ps_cmd, check_return=True) 87*8975f5c5SAndroid Build Coastguard Worker result = [] 88*8975f5c5SAndroid Build Coastguard Worker for l in ps_output_lines: 89*8975f5c5SAndroid Build Coastguard Worker fields = l.split() 90*8975f5c5SAndroid Build Coastguard Worker # fields[2] is tid, fields[-1] is thread name. Output may include an entry 91*8975f5c5SAndroid Build Coastguard Worker # for the process itself with tid=pid; omit that one. 92*8975f5c5SAndroid Build Coastguard Worker if fields[2] == str(pid): 93*8975f5c5SAndroid Build Coastguard Worker continue 94*8975f5c5SAndroid Build Coastguard Worker result.append((int(fields[2]), fields[-1])) 95*8975f5c5SAndroid Build Coastguard Worker return result 96*8975f5c5SAndroid Build Coastguard Worker 97*8975f5c5SAndroid Build Coastguard Worker 98*8975f5c5SAndroid Build Coastguard Workerdef _ThreadType(thread_name): 99*8975f5c5SAndroid Build Coastguard Worker if not thread_name: 100*8975f5c5SAndroid Build Coastguard Worker return 'unknown' 101*8975f5c5SAndroid Build Coastguard Worker if (thread_name.startswith('Chrome_ChildIO') or 102*8975f5c5SAndroid Build Coastguard Worker thread_name.startswith('Chrome_IO')): 103*8975f5c5SAndroid Build Coastguard Worker return 'io' 104*8975f5c5SAndroid Build Coastguard Worker if thread_name.startswith('Compositor'): 105*8975f5c5SAndroid Build Coastguard Worker return 'compositor' 106*8975f5c5SAndroid Build Coastguard Worker if (thread_name.startswith('ChildProcessMai') or 107*8975f5c5SAndroid Build Coastguard Worker thread_name.startswith('CrGpuMain') or 108*8975f5c5SAndroid Build Coastguard Worker thread_name.startswith('CrRendererMain')): 109*8975f5c5SAndroid Build Coastguard Worker return 'main' 110*8975f5c5SAndroid Build Coastguard Worker if thread_name.startswith('RenderThread'): 111*8975f5c5SAndroid Build Coastguard Worker return 'render' 112*8975f5c5SAndroid Build Coastguard Worker raise ValueError('got no matching thread_name') 113*8975f5c5SAndroid Build Coastguard Worker 114*8975f5c5SAndroid Build Coastguard Worker 115*8975f5c5SAndroid Build Coastguard Workerdef _GetSpecifiedTID(device, pid, thread_specifier): 116*8975f5c5SAndroid Build Coastguard Worker if thread_specifier is None: 117*8975f5c5SAndroid Build Coastguard Worker return None 118*8975f5c5SAndroid Build Coastguard Worker 119*8975f5c5SAndroid Build Coastguard Worker # Check for numeric TID 120*8975f5c5SAndroid Build Coastguard Worker try: 121*8975f5c5SAndroid Build Coastguard Worker tid = int(thread_specifier) 122*8975f5c5SAndroid Build Coastguard Worker return tid 123*8975f5c5SAndroid Build Coastguard Worker except ValueError: 124*8975f5c5SAndroid Build Coastguard Worker pass 125*8975f5c5SAndroid Build Coastguard Worker 126*8975f5c5SAndroid Build Coastguard Worker # Check for thread type 127*8975f5c5SAndroid Build Coastguard Worker if pid is not None: 128*8975f5c5SAndroid Build Coastguard Worker matching_threads = [t for t in _ThreadsForProcess(device, pid) if ( 129*8975f5c5SAndroid Build Coastguard Worker _ThreadType(t[1]) == thread_specifier)] 130*8975f5c5SAndroid Build Coastguard Worker if len(matching_threads) != 1: 131*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Found %d threads of type "%s".' % ( 132*8975f5c5SAndroid Build Coastguard Worker len(matching_threads), thread_specifier)) 133*8975f5c5SAndroid Build Coastguard Worker return matching_threads[0][0] 134*8975f5c5SAndroid Build Coastguard Worker 135*8975f5c5SAndroid Build Coastguard Worker return None 136*8975f5c5SAndroid Build Coastguard Worker 137*8975f5c5SAndroid Build Coastguard Worker 138*8975f5c5SAndroid Build Coastguard Workerdef PrepareDevice(device): 139*8975f5c5SAndroid Build Coastguard Worker if device.build_version_sdk < version_codes.NOUGAT: 140*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Simpleperf profiling is only supported on Android N ' 141*8975f5c5SAndroid Build Coastguard Worker 'and later.') 142*8975f5c5SAndroid Build Coastguard Worker 143*8975f5c5SAndroid Build Coastguard Worker # Necessary for profiling 144*8975f5c5SAndroid Build Coastguard Worker # https://android-review.googlesource.com/c/platform/system/sepolicy/+/234400 145*8975f5c5SAndroid Build Coastguard Worker device.SetProp('security.perf_harden', '0') 146*8975f5c5SAndroid Build Coastguard Worker 147*8975f5c5SAndroid Build Coastguard Worker 148*8975f5c5SAndroid Build Coastguard Workerdef InstallSimpleperf(device, package_name): 149*8975f5c5SAndroid Build Coastguard Worker package_arch = device.GetPackageArchitecture(package_name) or 'armeabi-v7a' 150*8975f5c5SAndroid Build Coastguard Worker host_simpleperf_path = devil_env.config.LocalPath('simpleperf', package_arch) 151*8975f5c5SAndroid Build Coastguard Worker if not host_simpleperf_path: 152*8975f5c5SAndroid Build Coastguard Worker raise Exception('Could not get path to simpleperf executable on host.') 153*8975f5c5SAndroid Build Coastguard Worker device_simpleperf_path = '/'.join( 154*8975f5c5SAndroid Build Coastguard Worker ('/data/local/tmp/profilers', package_arch, 'simpleperf')) 155*8975f5c5SAndroid Build Coastguard Worker device.PushChangedFiles([(host_simpleperf_path, device_simpleperf_path)]) 156*8975f5c5SAndroid Build Coastguard Worker return device_simpleperf_path 157*8975f5c5SAndroid Build Coastguard Worker 158*8975f5c5SAndroid Build Coastguard Worker 159*8975f5c5SAndroid Build Coastguard Worker@contextlib.contextmanager 160*8975f5c5SAndroid Build Coastguard Workerdef RunSimpleperf(device, device_simpleperf_path, package_name, 161*8975f5c5SAndroid Build Coastguard Worker process_specifier, thread_specifier, events, 162*8975f5c5SAndroid Build Coastguard Worker profiler_args, host_out_path): 163*8975f5c5SAndroid Build Coastguard Worker pid = _GetSpecifiedPID(device, package_name, process_specifier) 164*8975f5c5SAndroid Build Coastguard Worker tid = _GetSpecifiedTID(device, pid, thread_specifier) 165*8975f5c5SAndroid Build Coastguard Worker if pid is None and tid is None: 166*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Could not find specified process/thread running on ' 167*8975f5c5SAndroid Build Coastguard Worker 'device. Make sure the apk is already running before ' 168*8975f5c5SAndroid Build Coastguard Worker 'attempting to profile.') 169*8975f5c5SAndroid Build Coastguard Worker profiler_args = list(profiler_args) 170*8975f5c5SAndroid Build Coastguard Worker if profiler_args and profiler_args[0] == 'record': 171*8975f5c5SAndroid Build Coastguard Worker profiler_args.pop(0) 172*8975f5c5SAndroid Build Coastguard Worker profiler_args.extend(('-e', events)) 173*8975f5c5SAndroid Build Coastguard Worker if '--call-graph' not in profiler_args and '-g' not in profiler_args: 174*8975f5c5SAndroid Build Coastguard Worker profiler_args.append('-g') 175*8975f5c5SAndroid Build Coastguard Worker if '-f' not in profiler_args: 176*8975f5c5SAndroid Build Coastguard Worker profiler_args.extend(('-f', '1000')) 177*8975f5c5SAndroid Build Coastguard Worker 178*8975f5c5SAndroid Build Coastguard Worker device_out_path = '/data/local/tmp/perf.data' 179*8975f5c5SAndroid Build Coastguard Worker should_remove_device_out_path = True 180*8975f5c5SAndroid Build Coastguard Worker if '-o' in profiler_args: 181*8975f5c5SAndroid Build Coastguard Worker device_out_path = profiler_args[profiler_args.index('-o') + 1] 182*8975f5c5SAndroid Build Coastguard Worker should_remove_device_out_path = False 183*8975f5c5SAndroid Build Coastguard Worker else: 184*8975f5c5SAndroid Build Coastguard Worker profiler_args.extend(('-o', device_out_path)) 185*8975f5c5SAndroid Build Coastguard Worker 186*8975f5c5SAndroid Build Coastguard Worker # Remove the default output to avoid confusion if simpleperf opts not 187*8975f5c5SAndroid Build Coastguard Worker # to update the file. 188*8975f5c5SAndroid Build Coastguard Worker file_exists = True 189*8975f5c5SAndroid Build Coastguard Worker try: 190*8975f5c5SAndroid Build Coastguard Worker device.adb.Shell('readlink -e ' + device_out_path) 191*8975f5c5SAndroid Build Coastguard Worker except device_errors.AdbCommandFailedError: 192*8975f5c5SAndroid Build Coastguard Worker file_exists = False 193*8975f5c5SAndroid Build Coastguard Worker if file_exists: 194*8975f5c5SAndroid Build Coastguard Worker logging.warning('%s output file already exists on device', device_out_path) 195*8975f5c5SAndroid Build Coastguard Worker if not should_remove_device_out_path: 196*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('Specified output file \'{}\' already exists, not ' 197*8975f5c5SAndroid Build Coastguard Worker 'continuing'.format(device_out_path)) 198*8975f5c5SAndroid Build Coastguard Worker device.adb.Shell('rm -f ' + device_out_path) 199*8975f5c5SAndroid Build Coastguard Worker 200*8975f5c5SAndroid Build Coastguard Worker if tid: 201*8975f5c5SAndroid Build Coastguard Worker profiler_args.extend(('-t', str(tid))) 202*8975f5c5SAndroid Build Coastguard Worker else: 203*8975f5c5SAndroid Build Coastguard Worker profiler_args.extend(('-p', str(pid))) 204*8975f5c5SAndroid Build Coastguard Worker 205*8975f5c5SAndroid Build Coastguard Worker adb_shell_simpleperf_process = device.adb.StartShell( 206*8975f5c5SAndroid Build Coastguard Worker [device_simpleperf_path, 'record'] + profiler_args) 207*8975f5c5SAndroid Build Coastguard Worker 208*8975f5c5SAndroid Build Coastguard Worker completed = False 209*8975f5c5SAndroid Build Coastguard Worker try: 210*8975f5c5SAndroid Build Coastguard Worker yield 211*8975f5c5SAndroid Build Coastguard Worker completed = True 212*8975f5c5SAndroid Build Coastguard Worker 213*8975f5c5SAndroid Build Coastguard Worker finally: 214*8975f5c5SAndroid Build Coastguard Worker device.KillAll('simpleperf', signum=device_signal.SIGINT, blocking=True, 215*8975f5c5SAndroid Build Coastguard Worker quiet=True) 216*8975f5c5SAndroid Build Coastguard Worker if completed: 217*8975f5c5SAndroid Build Coastguard Worker adb_shell_simpleperf_process.wait() 218*8975f5c5SAndroid Build Coastguard Worker ret = adb_shell_simpleperf_process.returncode 219*8975f5c5SAndroid Build Coastguard Worker if ret == 0: 220*8975f5c5SAndroid Build Coastguard Worker # Successfully gathered a profile 221*8975f5c5SAndroid Build Coastguard Worker device.PullFile(device_out_path, host_out_path) 222*8975f5c5SAndroid Build Coastguard Worker else: 223*8975f5c5SAndroid Build Coastguard Worker logging.warning( 224*8975f5c5SAndroid Build Coastguard Worker 'simpleperf exited unusually, expected exit 0, got %d', ret 225*8975f5c5SAndroid Build Coastguard Worker ) 226*8975f5c5SAndroid Build Coastguard Worker stdout, stderr = adb_shell_simpleperf_process.communicate() 227*8975f5c5SAndroid Build Coastguard Worker logging.info('stdout: \'%s\', stderr: \'%s\'', stdout, stderr) 228*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('simpleperf exited with unexpected code {} ' 229*8975f5c5SAndroid Build Coastguard Worker '(run with -vv for full stdout/stderr)'.format(ret)) 230*8975f5c5SAndroid Build Coastguard Worker 231*8975f5c5SAndroid Build Coastguard Worker 232*8975f5c5SAndroid Build Coastguard Workerdef ConvertSimpleperfToPprof(simpleperf_out_path, build_directory, 233*8975f5c5SAndroid Build Coastguard Worker pprof_out_path): 234*8975f5c5SAndroid Build Coastguard Worker # The simpleperf scripts require the unstripped libs to be installed in the 235*8975f5c5SAndroid Build Coastguard Worker # same directory structure as the libs on the device. Much of the logic here 236*8975f5c5SAndroid Build Coastguard Worker # is just figuring out and creating the necessary directory structure, and 237*8975f5c5SAndroid Build Coastguard Worker # symlinking the unstripped shared libs. 238*8975f5c5SAndroid Build Coastguard Worker 239*8975f5c5SAndroid Build Coastguard Worker # Get the set of libs that we can symbolize 240*8975f5c5SAndroid Build Coastguard Worker unstripped_lib_dir = os.path.join(build_directory, 'lib.unstripped') 241*8975f5c5SAndroid Build Coastguard Worker unstripped_libs = set( 242*8975f5c5SAndroid Build Coastguard Worker f for f in os.listdir(unstripped_lib_dir) if f.endswith('.so')) 243*8975f5c5SAndroid Build Coastguard Worker 244*8975f5c5SAndroid Build Coastguard Worker # report.py will show the directory structure above the shared libs; 245*8975f5c5SAndroid Build Coastguard Worker # that is the directory structure we need to recreate on the host. 246*8975f5c5SAndroid Build Coastguard Worker script_dir = devil_env.config.LocalPath('simpleperf_scripts') 247*8975f5c5SAndroid Build Coastguard Worker report_path = os.path.join(script_dir, 'report.py') 248*8975f5c5SAndroid Build Coastguard Worker report_cmd = [sys.executable, report_path, '-i', simpleperf_out_path] 249*8975f5c5SAndroid Build Coastguard Worker device_lib_path = None 250*8975f5c5SAndroid Build Coastguard Worker output = subprocess.check_output(report_cmd, stderr=subprocess.STDOUT) 251*8975f5c5SAndroid Build Coastguard Worker if isinstance(output, bytes): 252*8975f5c5SAndroid Build Coastguard Worker output = output.decode() 253*8975f5c5SAndroid Build Coastguard Worker for line in output.splitlines(): 254*8975f5c5SAndroid Build Coastguard Worker fields = line.split() 255*8975f5c5SAndroid Build Coastguard Worker if len(fields) < 5: 256*8975f5c5SAndroid Build Coastguard Worker continue 257*8975f5c5SAndroid Build Coastguard Worker shlib_path = fields[4] 258*8975f5c5SAndroid Build Coastguard Worker shlib_dirname, shlib_basename = shlib_path.rpartition('/')[::2] 259*8975f5c5SAndroid Build Coastguard Worker if shlib_basename in unstripped_libs: 260*8975f5c5SAndroid Build Coastguard Worker device_lib_path = shlib_dirname 261*8975f5c5SAndroid Build Coastguard Worker break 262*8975f5c5SAndroid Build Coastguard Worker if not device_lib_path: 263*8975f5c5SAndroid Build Coastguard Worker raise RuntimeError('No chrome-related symbols in profiling data in %s. ' 264*8975f5c5SAndroid Build Coastguard Worker 'Either the process was idle for the entire profiling ' 265*8975f5c5SAndroid Build Coastguard Worker 'period, or something went very wrong (and you should ' 266*8975f5c5SAndroid Build Coastguard Worker 'file a bug at crbug.com/new with component ' 267*8975f5c5SAndroid Build Coastguard Worker 'Speed>Tracing, and assign it to [email protected]).' 268*8975f5c5SAndroid Build Coastguard Worker % simpleperf_out_path) 269*8975f5c5SAndroid Build Coastguard Worker 270*8975f5c5SAndroid Build Coastguard Worker # Recreate the directory structure locally, and symlink unstripped libs. 271*8975f5c5SAndroid Build Coastguard Worker processing_dir = tempfile.mkdtemp() 272*8975f5c5SAndroid Build Coastguard Worker try: 273*8975f5c5SAndroid Build Coastguard Worker processing_lib_dir = os.path.join( 274*8975f5c5SAndroid Build Coastguard Worker processing_dir, 'binary_cache', device_lib_path.lstrip('/')) 275*8975f5c5SAndroid Build Coastguard Worker os.makedirs(processing_lib_dir) 276*8975f5c5SAndroid Build Coastguard Worker for lib in unstripped_libs: 277*8975f5c5SAndroid Build Coastguard Worker unstripped_lib_path = os.path.join(unstripped_lib_dir, lib) 278*8975f5c5SAndroid Build Coastguard Worker processing_lib_path = os.path.join(processing_lib_dir, lib) 279*8975f5c5SAndroid Build Coastguard Worker os.symlink(unstripped_lib_path, processing_lib_path) 280*8975f5c5SAndroid Build Coastguard Worker 281*8975f5c5SAndroid Build Coastguard Worker # Run the script to annotate symbols and convert from simpleperf format to 282*8975f5c5SAndroid Build Coastguard Worker # pprof format. 283*8975f5c5SAndroid Build Coastguard Worker pprof_converter_script = os.path.join( 284*8975f5c5SAndroid Build Coastguard Worker script_dir, 'pprof_proto_generator.py') 285*8975f5c5SAndroid Build Coastguard Worker pprof_converter_cmd = [ 286*8975f5c5SAndroid Build Coastguard Worker sys.executable, pprof_converter_script, '-i', simpleperf_out_path, '-o', 287*8975f5c5SAndroid Build Coastguard Worker os.path.abspath(pprof_out_path), '--ndk_path', 288*8975f5c5SAndroid Build Coastguard Worker constants.ANDROID_NDK_ROOT 289*8975f5c5SAndroid Build Coastguard Worker ] 290*8975f5c5SAndroid Build Coastguard Worker subprocess.check_output(pprof_converter_cmd, stderr=subprocess.STDOUT, 291*8975f5c5SAndroid Build Coastguard Worker cwd=processing_dir) 292*8975f5c5SAndroid Build Coastguard Worker finally: 293*8975f5c5SAndroid Build Coastguard Worker shutil.rmtree(processing_dir, ignore_errors=True) 294