xref: /aosp_15_r20/system/extras/ioblame/uidProcessMapper.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker#!/usr/bin/env python
2*288bf522SAndroid Build Coastguard Worker#
3*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project
4*288bf522SAndroid Build Coastguard Worker#
5*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*288bf522SAndroid Build Coastguard Worker#
9*288bf522SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*288bf522SAndroid Build Coastguard Worker#
11*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*288bf522SAndroid Build Coastguard Worker# limitations under the License.
16*288bf522SAndroid Build Coastguard Worker#
17*288bf522SAndroid Build Coastguard Worker"""Package <-> UID <-> Process mapper."""
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Workerimport re
20*288bf522SAndroid Build Coastguard Worker
21*288bf522SAndroid Build Coastguard Worker# ex) Name:   init
22*288bf522SAndroid Build Coastguard WorkerPROC_STATUS_NAME_LINE = r"Name:\s+(\S+)"
23*288bf522SAndroid Build Coastguard Worker
24*288bf522SAndroid Build Coastguard Worker# ex) Pid:    1
25*288bf522SAndroid Build Coastguard WorkerPROC_STATUS_PID_LINE = r"Pid:\s+([0-9]+)"
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Worker# ex) Uid:    0       0       0       0
28*288bf522SAndroid Build Coastguard WorkerPROC_STATUS_UID_LINE = r"Uid:\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)"
29*288bf522SAndroid Build Coastguard Worker
30*288bf522SAndroid Build Coastguard Worker# ex) package:com.google.android.car.uxr.sample uid:1000
31*288bf522SAndroid Build Coastguard WorkerPACKAGE_UID_LINE = r"package:(\S+)\suid:([0-9]+)"
32*288bf522SAndroid Build Coastguard Worker
33*288bf522SAndroid Build Coastguard WorkerUSER_ID_OFFSET = 100000
34*288bf522SAndroid Build Coastguard WorkerAID_APP_START = 10000
35*288bf522SAndroid Build Coastguard WorkerUNKNOWN_UID = -1
36*288bf522SAndroid Build Coastguard Worker
37*288bf522SAndroid Build Coastguard Worker
38*288bf522SAndroid Build Coastguard Workerclass UidInfo:
39*288bf522SAndroid Build Coastguard Worker
40*288bf522SAndroid Build Coastguard Worker  def __init__(self, uid, packageName=None):
41*288bf522SAndroid Build Coastguard Worker    self.uid = uid
42*288bf522SAndroid Build Coastguard Worker    self.packageName = packageName
43*288bf522SAndroid Build Coastguard Worker
44*288bf522SAndroid Build Coastguard Worker  def to_string(self):
45*288bf522SAndroid Build Coastguard Worker    appId = int(self.uid % USER_ID_OFFSET)
46*288bf522SAndroid Build Coastguard Worker    if self.uid == UNKNOWN_UID:
47*288bf522SAndroid Build Coastguard Worker      return "UID: UNKNOWN"
48*288bf522SAndroid Build Coastguard Worker    elif self.packageName is None and appId < AID_APP_START:
49*288bf522SAndroid Build Coastguard Worker      return "User ID: {}, Native service AID: {}".format(
50*288bf522SAndroid Build Coastguard Worker          int(self.uid / USER_ID_OFFSET), appId)
51*288bf522SAndroid Build Coastguard Worker    elif self.packageName is None:
52*288bf522SAndroid Build Coastguard Worker      return "User ID: {}, App ID: {}".format(
53*288bf522SAndroid Build Coastguard Worker          int(self.uid / USER_ID_OFFSET), appId)
54*288bf522SAndroid Build Coastguard Worker    else:
55*288bf522SAndroid Build Coastguard Worker      return "User ID: {}, Package name: {}".format(
56*288bf522SAndroid Build Coastguard Worker          int(self.uid / USER_ID_OFFSET), self.packageName)
57*288bf522SAndroid Build Coastguard Worker
58*288bf522SAndroid Build Coastguard Worker
59*288bf522SAndroid Build Coastguard Workerclass UidProcessMapper:
60*288bf522SAndroid Build Coastguard Worker
61*288bf522SAndroid Build Coastguard Worker  def __init__(self):
62*288bf522SAndroid Build Coastguard Worker    self.nameReMatcher = re.compile(PROC_STATUS_NAME_LINE)
63*288bf522SAndroid Build Coastguard Worker    self.pidReMatcher = re.compile(PROC_STATUS_PID_LINE)
64*288bf522SAndroid Build Coastguard Worker    self.uidReMatcher = re.compile(PROC_STATUS_UID_LINE)
65*288bf522SAndroid Build Coastguard Worker    self.packageUidMatcher = re.compile(PACKAGE_UID_LINE)
66*288bf522SAndroid Build Coastguard Worker    self.uidByProcessDict = {}  # Key: Process Name, Value: {PID: UID}
67*288bf522SAndroid Build Coastguard Worker    self.packageNameByAppId = {}  # Key: App ID, Value: Package name
68*288bf522SAndroid Build Coastguard Worker
69*288bf522SAndroid Build Coastguard Worker  def parse_proc_status_dump(self, dump):
70*288bf522SAndroid Build Coastguard Worker    name, pid, uid = "", "", ""
71*288bf522SAndroid Build Coastguard Worker
72*288bf522SAndroid Build Coastguard Worker    for line in dump.split("\n"):
73*288bf522SAndroid Build Coastguard Worker      if line.startswith("Name:"):
74*288bf522SAndroid Build Coastguard Worker        name = self.match_re(self.nameReMatcher, line)
75*288bf522SAndroid Build Coastguard Worker        pid, uid = "", ""
76*288bf522SAndroid Build Coastguard Worker      elif line.startswith("Pid:"):
77*288bf522SAndroid Build Coastguard Worker        pid = self.match_re(self.pidReMatcher, line)
78*288bf522SAndroid Build Coastguard Worker        uid = ""
79*288bf522SAndroid Build Coastguard Worker      elif line.startswith("Uid:"):
80*288bf522SAndroid Build Coastguard Worker        uid = self.match_re(self.uidReMatcher, line)
81*288bf522SAndroid Build Coastguard Worker        if name != "" and pid != "" and uid != "":
82*288bf522SAndroid Build Coastguard Worker          self.add_mapping(name, int(pid), int(uid))
83*288bf522SAndroid Build Coastguard Worker        name, pid, uid = "", "", ""
84*288bf522SAndroid Build Coastguard Worker
85*288bf522SAndroid Build Coastguard Worker  def parse_uid_package_dump(self, dump):
86*288bf522SAndroid Build Coastguard Worker    for line in dump.split("\n"):
87*288bf522SAndroid Build Coastguard Worker      if line == "":
88*288bf522SAndroid Build Coastguard Worker        continue
89*288bf522SAndroid Build Coastguard Worker
90*288bf522SAndroid Build Coastguard Worker      match = self.packageUidMatcher.match(line)
91*288bf522SAndroid Build Coastguard Worker      if (match):
92*288bf522SAndroid Build Coastguard Worker        packageName = match.group(1)
93*288bf522SAndroid Build Coastguard Worker        appId = int(match.group(2))
94*288bf522SAndroid Build Coastguard Worker        if appId in self.packageNameByAppId:
95*288bf522SAndroid Build Coastguard Worker          self.packageNameByAppId[appId].add(packageName)
96*288bf522SAndroid Build Coastguard Worker        else:
97*288bf522SAndroid Build Coastguard Worker          self.packageNameByAppId[appId] = {packageName}
98*288bf522SAndroid Build Coastguard Worker      else:
99*288bf522SAndroid Build Coastguard Worker        print("'{}' line doesn't match '{}' regex".format(
100*288bf522SAndroid Build Coastguard Worker            line, self.packageUidMatcher))
101*288bf522SAndroid Build Coastguard Worker
102*288bf522SAndroid Build Coastguard Worker  def match_re(self, reMatcher, line):
103*288bf522SAndroid Build Coastguard Worker    match = reMatcher.match(line)
104*288bf522SAndroid Build Coastguard Worker    if not match:
105*288bf522SAndroid Build Coastguard Worker      return ""
106*288bf522SAndroid Build Coastguard Worker    return match.group(1)
107*288bf522SAndroid Build Coastguard Worker
108*288bf522SAndroid Build Coastguard Worker  def add_mapping(self, name, pid, uid):
109*288bf522SAndroid Build Coastguard Worker    if name in self.uidByProcessDict:
110*288bf522SAndroid Build Coastguard Worker      self.uidByProcessDict[name][pid] = uid
111*288bf522SAndroid Build Coastguard Worker    else:
112*288bf522SAndroid Build Coastguard Worker      self.uidByProcessDict[name] = {pid: uid}
113*288bf522SAndroid Build Coastguard Worker
114*288bf522SAndroid Build Coastguard Worker  def get_uid(self, name, pid):
115*288bf522SAndroid Build Coastguard Worker    if name in self.uidByProcessDict:
116*288bf522SAndroid Build Coastguard Worker      if pid in self.uidByProcessDict[name]:
117*288bf522SAndroid Build Coastguard Worker        return self.uidByProcessDict[name][pid]
118*288bf522SAndroid Build Coastguard Worker    return UNKNOWN_UID
119*288bf522SAndroid Build Coastguard Worker
120*288bf522SAndroid Build Coastguard Worker  def get_uid_info(self, uid):
121*288bf522SAndroid Build Coastguard Worker    appId = uid % USER_ID_OFFSET
122*288bf522SAndroid Build Coastguard Worker    if appId in self.packageNameByAppId:
123*288bf522SAndroid Build Coastguard Worker      return UidInfo(uid, " | ".join(self.packageNameByAppId[appId]))
124*288bf522SAndroid Build Coastguard Worker    else:
125*288bf522SAndroid Build Coastguard Worker      return UidInfo(uid)
126