1#!/usr/bin/env python3 2# Copyright (C) 2020 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import os 17import subprocess 18import sys 19import tempfile 20import time 21from typing import List, Optional 22from urllib import request, error 23 24from perfetto.common.exceptions import PerfettoException 25from perfetto.trace_processor.platform import PlatformDelegate 26 27# Default port that trace_processor_shell runs on 28TP_PORT = 9001 29 30 31def load_shell(bin_path: str, 32 unique_port: bool, 33 verbose: bool, 34 ingest_ftrace_in_raw: bool, 35 enable_dev_features: bool, 36 platform_delegate: PlatformDelegate, 37 load_timeout: int = 2, 38 extra_flags: Optional[List[str]] = None): 39 addr, port = platform_delegate.get_bind_addr( 40 port=0 if unique_port else TP_PORT) 41 url = f'{addr}:{str(port)}' 42 43 shell_path = platform_delegate.get_shell_path(bin_path=bin_path) 44 if os.name == 'nt' and not shell_path.endswith('.exe'): 45 tp_exec = [sys.executable, shell_path] 46 else: 47 tp_exec = [shell_path] 48 49 args = ['-D', '--http-port', str(port)] 50 if not ingest_ftrace_in_raw: 51 args.append('--no-ftrace-raw') 52 53 if enable_dev_features: 54 args.append('--dev') 55 56 if extra_flags: 57 args.extend(extra_flags) 58 59 temp_stdout = tempfile.TemporaryFile() 60 temp_stderr = tempfile.TemporaryFile() 61 p = subprocess.Popen( 62 tp_exec + args, 63 stdin=subprocess.DEVNULL, 64 stdout=temp_stdout, 65 stderr=None if verbose else temp_stderr) 66 67 success = False 68 for _ in range(load_timeout + 1): 69 try: 70 if p.poll() is None: 71 _ = request.urlretrieve(f'http://{url}/status') 72 success = True 73 break 74 except (error.URLError, ConnectionError): 75 time.sleep(1) 76 77 if not success: 78 p.kill() 79 temp_stdout.seek(0) 80 stdout = temp_stdout.read().decode("utf-8") 81 temp_stderr.seek(0) 82 stderr = temp_stderr.read().decode("utf-8") 83 raise PerfettoException("Trace processor failed to start.\n" 84 f"stdout: {stdout}\nstderr: {stderr}\n") 85 86 return url, p 87