1 #!/usr/bin/env python 2 # 3 # Copyright 2017 - 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 import itertools 18 from metrics.metric import Metric 19 20 21 class ProcessTimeMetric(Metric): 22 TIME_COMMAND = 'ps -p %s -o etimes,command | sed 1d' 23 # Number of seconds in 24 hours 24 MIN_TIME = 86400 25 # Fields for response dictionary 26 ADB_PROCESSES = 'adb_processes' 27 NUM_ADB_PROCESSES = 'num_adb_processes' 28 FASTBOOT_PROCESSES = 'fastboot_processes' 29 NUM_FASTBOOT_PROCESSES = 'num_fastboot_processes' 30 31 def gather_metric(self): 32 """Returns ADB and Fastboot processes and their time elapsed 33 34 Returns: 35 A dictionary with adb/fastboot_processes as a list of serial nums or 36 NONE if number wasn't in command. num_adb/fastboot_processes as 37 the number of serials in list. 38 """ 39 # Get the process ids 40 pids = self.get_adb_fastboot_pids() 41 42 # Get elapsed time for selected pids 43 adb_processes, fastboot_processes = [], [] 44 for pid in pids: 45 # Sample output: 46 # 232893 fastboot -s FA6BM0305019 -w 47 48 output = self._shell.run(self.TIME_COMMAND % pid).stdout 49 spl_ln = output.split() 50 51 # There is a potential race condition between getting pids, and the 52 # pid then dying, so we must check that there is output. 53 if spl_ln: 54 # pull out time in seconds 55 time = int(spl_ln[0]) 56 else: 57 continue 58 59 # We only care about processes older than the min time 60 if time > self.MIN_TIME: 61 # ignore fork-server command, because it's not a problematic process 62 if 'fork-server' not in output: 63 # get serial number, which defaults to none 64 serial_number = None 65 if '-s' in spl_ln: 66 sn_index = spl_ln.index('-s') 67 # avoid indexing out of range 68 if sn_index + 1 < len(spl_ln): 69 serial_number = spl_ln[sn_index + 1] 70 # append to proper list 71 if 'fastboot' in output: 72 fastboot_processes.append(serial_number) 73 elif 'adb' in output: 74 adb_processes.append(serial_number) 75 76 # Create response dictionary 77 response = { 78 self.ADB_PROCESSES: adb_processes, 79 self.NUM_ADB_PROCESSES: len(adb_processes), 80 self.FASTBOOT_PROCESSES: fastboot_processes, 81 self.NUM_FASTBOOT_PROCESSES: len(fastboot_processes) 82 } 83 return response 84 85 def get_adb_fastboot_pids(self): 86 """Finds a list of ADB and Fastboot process ids. 87 88 Returns: 89 A list of PID strings 90 """ 91 # Get ids of processes with 'adb' or 'fastboot' in name 92 adb_result = self._shell.get_command_pids('adb') 93 fastboot_result = self._shell.get_command_pids('fastboot') 94 # concatenate two generator objects, return as list 95 return list(itertools.chain(adb_result, fastboot_result)) 96