1*90c8c64dSAndroid Build Coastguard Workerimport csv 2*90c8c64dSAndroid Build Coastguard Workerimport re 3*90c8c64dSAndroid Build Coastguard Workerimport subprocess 4*90c8c64dSAndroid Build Coastguard Worker 5*90c8c64dSAndroid Build Coastguard WorkerHEADER_RE = re.compile("USER\\s*PID\\s*PPID\\s*VSIZE\\s*RSS\\s*WCHAN\\s*PC\\s*NAME") 6*90c8c64dSAndroid Build Coastguard WorkerPROCESS_RE = re.compile("(\\S+)\\s+(\\d+)\\s+(\\d+)\\s+\\d+\\s+\\d+\\s+\\S+\\s+.\\S+\\s+\\S+\\s+(.*)") 7*90c8c64dSAndroid Build Coastguard Worker 8*90c8c64dSAndroid Build Coastguard WorkerANDROID_UID_RE = re.compile("u(\\d)+_([0-9a-fA-F]+)") 9*90c8c64dSAndroid Build Coastguard WorkerUID_RE = re.compile("(\\d)+") 10*90c8c64dSAndroid Build Coastguard Worker 11*90c8c64dSAndroid Build Coastguard Workerclass Process(object): 12*90c8c64dSAndroid Build Coastguard Worker def __init__(self, uid, pid, ppid, name): 13*90c8c64dSAndroid Build Coastguard Worker self.uid = uid 14*90c8c64dSAndroid Build Coastguard Worker self.pid = pid 15*90c8c64dSAndroid Build Coastguard Worker self.ppid = ppid 16*90c8c64dSAndroid Build Coastguard Worker self.name = name 17*90c8c64dSAndroid Build Coastguard Worker 18*90c8c64dSAndroid Build Coastguard Worker def DisplayName(self): 19*90c8c64dSAndroid Build Coastguard Worker if self.name: 20*90c8c64dSAndroid Build Coastguard Worker return self.name 21*90c8c64dSAndroid Build Coastguard Worker if self.uid: 22*90c8c64dSAndroid Build Coastguard Worker return self.uid.name 23*90c8c64dSAndroid Build Coastguard Worker return self.pid 24*90c8c64dSAndroid Build Coastguard Worker 25*90c8c64dSAndroid Build Coastguard Worker def __str__(self): 26*90c8c64dSAndroid Build Coastguard Worker return "Process(uid=%s, pid=%s, name=%s)" % (self.uid, self.pid, self.name) 27*90c8c64dSAndroid Build Coastguard Worker 28*90c8c64dSAndroid Build Coastguard Workerclass Uid(object): 29*90c8c64dSAndroid Build Coastguard Worker def __init__(self, uid, name): 30*90c8c64dSAndroid Build Coastguard Worker self.uid = uid 31*90c8c64dSAndroid Build Coastguard Worker self.name = name 32*90c8c64dSAndroid Build Coastguard Worker 33*90c8c64dSAndroid Build Coastguard Worker def __str__(self): 34*90c8c64dSAndroid Build Coastguard Worker return "Uid(id=%s, name=%s)" % (self.uid, self.name) 35*90c8c64dSAndroid Build Coastguard Worker 36*90c8c64dSAndroid Build Coastguard Workerclass ProcessSet(object): 37*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 38*90c8c64dSAndroid Build Coastguard Worker self._processes = dict() 39*90c8c64dSAndroid Build Coastguard Worker self._uids = dict() 40*90c8c64dSAndroid Build Coastguard Worker self._pidUpdateCount = 0 41*90c8c64dSAndroid Build Coastguard Worker self._uidUpdateCount = 0 42*90c8c64dSAndroid Build Coastguard Worker self.doUpdates = False 43*90c8c64dSAndroid Build Coastguard Worker 44*90c8c64dSAndroid Build Coastguard Worker def Update(self, force=False): 45*90c8c64dSAndroid Build Coastguard Worker self.UpdateUids(force) 46*90c8c64dSAndroid Build Coastguard Worker self.UpdateProcesses(force) 47*90c8c64dSAndroid Build Coastguard Worker 48*90c8c64dSAndroid Build Coastguard Worker def UpdateProcesses(self, force=False): 49*90c8c64dSAndroid Build Coastguard Worker if not (self.doUpdates or force): 50*90c8c64dSAndroid Build Coastguard Worker return 51*90c8c64dSAndroid Build Coastguard Worker self._pidUpdateCount += 1 52*90c8c64dSAndroid Build Coastguard Worker try: 53*90c8c64dSAndroid Build Coastguard Worker text = subprocess.check_output(["adb", "shell", "ps"]) 54*90c8c64dSAndroid Build Coastguard Worker except subprocess.CalledProcessError: 55*90c8c64dSAndroid Build Coastguard Worker return # oh well. we won't get the pid 56*90c8c64dSAndroid Build Coastguard Worker lines = ParsePs(text) 57*90c8c64dSAndroid Build Coastguard Worker for line in lines: 58*90c8c64dSAndroid Build Coastguard Worker if not self._processes.has_key(line[1]): 59*90c8c64dSAndroid Build Coastguard Worker uid = self.FindUid(ParseUid(line[0])) 60*90c8c64dSAndroid Build Coastguard Worker self._processes[line[1]] = Process(uid, line[1], line[2], line[3]) 61*90c8c64dSAndroid Build Coastguard Worker 62*90c8c64dSAndroid Build Coastguard Worker def UpdateUids(self, force=False): 63*90c8c64dSAndroid Build Coastguard Worker if not (self.doUpdates or force): 64*90c8c64dSAndroid Build Coastguard Worker return 65*90c8c64dSAndroid Build Coastguard Worker self._uidUpdateCount += 1 66*90c8c64dSAndroid Build Coastguard Worker try: 67*90c8c64dSAndroid Build Coastguard Worker text = subprocess.check_output(["adb", "shell", "dumpsys", "package", "--checkin"]) 68*90c8c64dSAndroid Build Coastguard Worker except subprocess.CalledProcessError: 69*90c8c64dSAndroid Build Coastguard Worker return # oh well. we won't get the pid 70*90c8c64dSAndroid Build Coastguard Worker lines = ParseUids(text) 71*90c8c64dSAndroid Build Coastguard Worker for line in lines: 72*90c8c64dSAndroid Build Coastguard Worker if not self._uids.has_key(line[0]): 73*90c8c64dSAndroid Build Coastguard Worker self._uids[line[1]] = Uid(*line) 74*90c8c64dSAndroid Build Coastguard Worker 75*90c8c64dSAndroid Build Coastguard Worker def FindPid(self, pid, uid=None): 76*90c8c64dSAndroid Build Coastguard Worker """Try to find the Process object for the given pid. 77*90c8c64dSAndroid Build Coastguard Worker If it can't be found, do an update. If it still can't be found after that, 78*90c8c64dSAndroid Build Coastguard Worker create a syntheitc Process object, add that to the list, and return that. 79*90c8c64dSAndroid Build Coastguard Worker That can only happen after the process has died, and we just missed our 80*90c8c64dSAndroid Build Coastguard Worker chance to find it. The pid won't come back. 81*90c8c64dSAndroid Build Coastguard Worker """ 82*90c8c64dSAndroid Build Coastguard Worker result = self._processes.get(pid) 83*90c8c64dSAndroid Build Coastguard Worker if not result: 84*90c8c64dSAndroid Build Coastguard Worker self.UpdateProcesses() 85*90c8c64dSAndroid Build Coastguard Worker result = self._processes.get(pid) 86*90c8c64dSAndroid Build Coastguard Worker if not result: 87*90c8c64dSAndroid Build Coastguard Worker if uid: 88*90c8c64dSAndroid Build Coastguard Worker uid = self._uids.get(uid) 89*90c8c64dSAndroid Build Coastguard Worker result = Process(uid, pid, None, None) 90*90c8c64dSAndroid Build Coastguard Worker self._processes[pid] = result 91*90c8c64dSAndroid Build Coastguard Worker return result 92*90c8c64dSAndroid Build Coastguard Worker 93*90c8c64dSAndroid Build Coastguard Worker def FindUid(self, uid): 94*90c8c64dSAndroid Build Coastguard Worker result = self._uids.get(uid) 95*90c8c64dSAndroid Build Coastguard Worker if not result: 96*90c8c64dSAndroid Build Coastguard Worker self.UpdateUids() 97*90c8c64dSAndroid Build Coastguard Worker result = self._uids.get(uid) 98*90c8c64dSAndroid Build Coastguard Worker if not result: 99*90c8c64dSAndroid Build Coastguard Worker result = Uid(uid, uid) 100*90c8c64dSAndroid Build Coastguard Worker self._uids[uid] = result 101*90c8c64dSAndroid Build Coastguard Worker return result 102*90c8c64dSAndroid Build Coastguard Worker 103*90c8c64dSAndroid Build Coastguard Worker def UpdateCount(self): 104*90c8c64dSAndroid Build Coastguard Worker return (self._pidUpdateCount, self._uidUpdateCount) 105*90c8c64dSAndroid Build Coastguard Worker 106*90c8c64dSAndroid Build Coastguard Worker def Print(self): 107*90c8c64dSAndroid Build Coastguard Worker for process in self._processes: 108*90c8c64dSAndroid Build Coastguard Worker print process 109*90c8c64dSAndroid Build Coastguard Worker for uid in self._uids: 110*90c8c64dSAndroid Build Coastguard Worker print uid 111*90c8c64dSAndroid Build Coastguard Worker 112*90c8c64dSAndroid Build Coastguard Workerdef ParsePs(text): 113*90c8c64dSAndroid Build Coastguard Worker """Parses the output of ps, and returns it as a list of tuples of (user, pid, ppid, name)""" 114*90c8c64dSAndroid Build Coastguard Worker result = [] 115*90c8c64dSAndroid Build Coastguard Worker for line in text.splitlines(): 116*90c8c64dSAndroid Build Coastguard Worker m = HEADER_RE.match(line) 117*90c8c64dSAndroid Build Coastguard Worker if m: 118*90c8c64dSAndroid Build Coastguard Worker continue 119*90c8c64dSAndroid Build Coastguard Worker m = PROCESS_RE.match(line) 120*90c8c64dSAndroid Build Coastguard Worker if m: 121*90c8c64dSAndroid Build Coastguard Worker result.append((m.group(1), m.group(2), m.group(3), m.group(4))) 122*90c8c64dSAndroid Build Coastguard Worker continue 123*90c8c64dSAndroid Build Coastguard Worker return result 124*90c8c64dSAndroid Build Coastguard Worker 125*90c8c64dSAndroid Build Coastguard Worker 126*90c8c64dSAndroid Build Coastguard Workerdef ParseUids(text): 127*90c8c64dSAndroid Build Coastguard Worker """Parses the output of dumpsys package --checkin and returns the uids as a list of 128*90c8c64dSAndroid Build Coastguard Worker tuples of (uid, name)""" 129*90c8c64dSAndroid Build Coastguard Worker return [(x[2], x[1]) for x in csv.reader(text.split("\n")) if len(x) and x[0] == "pkg"] 130*90c8c64dSAndroid Build Coastguard Worker 131*90c8c64dSAndroid Build Coastguard Worker 132*90c8c64dSAndroid Build Coastguard Workerdef ParseUid(text): 133*90c8c64dSAndroid Build Coastguard Worker m = ANDROID_UID_RE.match(text) 134*90c8c64dSAndroid Build Coastguard Worker if m: 135*90c8c64dSAndroid Build Coastguard Worker result = int("0x" + m.group(2), 16) 136*90c8c64dSAndroid Build Coastguard Worker return "(%s/%s/%s)" % (m.group(1), m.group(2), result) 137*90c8c64dSAndroid Build Coastguard Worker m = UID_RE.match(text) 138*90c8c64dSAndroid Build Coastguard Worker if m: 139*90c8c64dSAndroid Build Coastguard Worker return "[%s]" % m.group(1) 140*90c8c64dSAndroid Build Coastguard Worker return text 141*90c8c64dSAndroid Build Coastguard Worker 142*90c8c64dSAndroid Build Coastguard Worker# vim: set ts=2 sw=2 sts=2 tw=100 nocindent autoindent smartindent expandtab: 143