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 socket 18import subprocess 19import tempfile 20from urllib import request 21 22 23# This class contains all functions that first try to use a vendor to fulfil 24# their function 25class LoaderStandalone: 26 # Limit parsing file to 32MB to maintain parity with the UI 27 MAX_BYTES_LOADED = 32 * 1024 * 1024 28 29 # URL to download script to run trace_processor 30 SHELL_URL = 'http://get.perfetto.dev/trace_processor' 31 32 # Default port that trace_processor_shell runs on 33 TP_PORT = '9001' 34 35 def read_tp_descriptor(): 36 ws = os.path.dirname(__file__) 37 with open(os.path.join(ws, 'trace_processor.descriptor'), 'rb') as x: 38 return x.read() 39 40 def read_metrics_descriptor(): 41 ws = os.path.dirname(__file__) 42 with open(os.path.join(ws, 'metrics.descriptor'), 'rb') as x: 43 return x.read() 44 45 def parse_file(tp_http, file_path): 46 with open(file_path, 'rb') as f: 47 f_size = os.path.getsize(file_path) 48 bytes_read = 0 49 while (bytes_read < f_size): 50 chunk = f.read(LoaderStandalone.MAX_BYTES_LOADED) 51 tp_http.parse(chunk) 52 bytes_read += len(chunk) 53 tp_http.notify_eof() 54 return tp_http 55 56 def get_shell_path(bin_path=None): 57 # Try to use preexisting binary before attempting to download 58 # trace_processor 59 if bin_path is None: 60 with tempfile.NamedTemporaryFile(delete=False) as file: 61 req = request.Request(LoaderStandalone.SHELL_URL) 62 with request.urlopen(req) as req: 63 file.write(req.read()) 64 subprocess.check_output(['chmod', '+x', file.name]) 65 return file.name 66 else: 67 if not os.path.isfile(bin_path): 68 raise Exception('Path to binary is not valid') 69 return bin_path 70 71 def get_free_port(unique_port=False): 72 if not unique_port: 73 return LoaderStandalone.TP_PORT, f'localhost:{LoaderStandalone.TP_PORT}' 74 free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 75 free_socket.bind(('', 0)) 76 free_socket.listen(5) 77 port = free_socket.getsockname()[1] 78 free_socket.close() 79 return str(port), f"localhost:{str(port)}" 80 81 82# Return vendor class if it exists before falling back on LoaderStandalone 83def get_loader(): 84 try: 85 from .loader_vendor import LoaderVendor 86 return LoaderVendor 87 except ModuleNotFoundError: 88 return LoaderStandalone 89