xref: /aosp_15_r20/development/tools/logblame/ps.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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