1#!/usr/bin/env python 2# Copyright (C) 2017 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 16from __future__ import print_function 17import argparse 18import datetime 19import os 20import subprocess 21import sys 22 23"""Pulls all format files from an Android device. 24 25Usage: ./tools/pull_ftrace_format_files.py [-s serial] [-p directory_prefix] 26""" 27 28ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 29ADB_PATH = os.path.join(ROOT_DIR, 'buildtools/android_sdk/platform-tools/adb') 30 31def adb(*cmd, **kwargs): 32 serial = kwargs.get('serial', None) 33 prefix = [ADB_PATH] 34 if serial: 35 prefix += ['-s', serial] 36 cmd = prefix + list(cmd) 37 output = subprocess.check_output(cmd).replace('\r', '') 38 return output 39 40 41def get_devices(): 42 # adb devices output looks like: 43 # List of devices attached 44 # 557dccd8\tdevice 45 # With a trailing newline. 46 serials = [s.split('\t')[0] for s in adb('devices').split('\n')[1:] if s] 47 return serials 48 49 50def ensure_output_directory_empty(path): 51 if os.path.isfile(path): 52 print('The output directory {} exists as a file.'.format(path)) 53 sys.exit(1) 54 55 if os.path.isdir(path) and os.listdir(path): 56 print('The output directory {} exists but is not empty.'.format(path)) 57 sys.exit(1) 58 59 if not os.path.isdir(path): 60 os.makedirs(path) 61 62 63def ensure_dir(path): 64 try: 65 os.makedirs(path) 66 except OSError: 67 if not os.path.isdir(path): 68 raise 69 70 71def ensure_single_device(serial): 72 serials = get_devices() 73 if serial is None and len(serials) == 1: 74 return serials[0] 75 76 if serial in serials: 77 return serial 78 79 if not serials: 80 print('No devices connected.') 81 elif serial is None: 82 print('More than one device connected, use -s.') 83 else: 84 print('No device with serial {} found.'.format(serial)) 85 sys.exit(1) 86 87 88def pull_format_files(serial, output_directory): 89 # Pulling each file individually is 100x slower so we pipe all together then 90 # split them on the host. 91 cmd = "find /sys/kernel/debug/tracing/ " \ 92 "-name available_events -o " \ 93 "-name format -o " \ 94 "-name header_event -o " \ 95 "-name header_page | " \ 96 "grep -v '/instances/' | " \ 97 "while read f; do echo 'path:' $f; cat $f; done" 98 99 output = adb('shell', cmd, serial=serial) 100 sections = output.split('path: /sys/kernel/debug/tracing/') 101 for section in sections: 102 if not section: 103 continue 104 path, rest = section.split('\n', 1) 105 path = os.path.join(output_directory, path) 106 ensure_dir(os.path.dirname(path)) 107 with open(path, 'wb') as f: 108 f.write(rest) 109 110 111# Produces output of the form: prefix_android_seed_N2F62_3.10.49 112def get_output_directory(prefix=None, serial=None): 113 build_id = adb('shell', 'getprop', 'ro.build.id', serial=serial).strip() 114 product = adb('shell', 'getprop', 'ro.build.product', serial=serial).strip() 115 kernel = adb('shell', 'uname', '-r', serial=serial).split('-')[0].strip() 116 parts = ['android', product, build_id, kernel] 117 if prefix: 118 parts = [prefix] + parts 119 return '_'.join(parts) 120 121 122def main(): 123 parser = argparse.ArgumentParser(description='Pull format files.') 124 parser.add_argument('-p', dest='prefix', default=None, 125 help='the output directory prefix') 126 parser.add_argument('-s', dest='serial', default=None, 127 help='use device with the given serial') 128 args = parser.parse_args() 129 130 prefix = args.prefix 131 serial = args.serial 132 133 serial = ensure_single_device(serial) 134 output_directory = get_output_directory(prefix, serial) 135 136 ensure_output_directory_empty(output_directory) 137 pull_format_files(serial, output_directory) 138 139 return 0 140 141 142if __name__ == '__main__': 143 sys.exit(main()) 144 145