Lakshman Annadorai | 3c8f88e | 2022-02-16 16:24:51 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright (C) 2022 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 | """Package <-> UID <-> Process mapper.""" |
| 18 | |
| 19 | import re |
| 20 | |
| 21 | # ex) Name: init |
| 22 | PROC_STATUS_NAME_LINE = r"Name:\s+(\S+)" |
| 23 | |
| 24 | # ex) Pid: 1 |
| 25 | PROC_STATUS_PID_LINE = r"Pid:\s+([0-9]+)" |
| 26 | |
| 27 | # ex) Uid: 0 0 0 0 |
| 28 | PROC_STATUS_UID_LINE = r"Uid:\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)" |
| 29 | |
| 30 | # ex) package:com.google.android.car.uxr.sample uid:1000 |
| 31 | PACKAGE_UID_LINE = r"package:(\S+)\suid:([0-9]+)" |
| 32 | |
| 33 | USER_ID_OFFSET = 100000 |
| 34 | AID_APP_START = 10000 |
| 35 | UNKNOWN_UID = -1 |
| 36 | |
| 37 | |
| 38 | class UidInfo: |
| 39 | |
| 40 | def __init__(self, uid, packageName=None): |
| 41 | self.uid = uid |
| 42 | self.packageName = packageName |
| 43 | |
| 44 | def to_string(self): |
| 45 | appId = int(self.uid % USER_ID_OFFSET) |
| 46 | if self.uid == UNKNOWN_UID: |
| 47 | return "UID: UNKNOWN" |
| 48 | elif self.packageName is None and appId < AID_APP_START: |
| 49 | return "User ID: {}, Native service AID: {}".format( |
| 50 | int(self.uid / USER_ID_OFFSET), appId) |
| 51 | elif self.packageName is None: |
| 52 | return "User ID: {}, App ID: {}".format( |
| 53 | int(self.uid / USER_ID_OFFSET), appId) |
| 54 | else: |
| 55 | return "User ID: {}, Package name: {}".format( |
| 56 | int(self.uid / USER_ID_OFFSET), self.packageName) |
| 57 | |
| 58 | |
| 59 | class UidProcessMapper: |
| 60 | |
| 61 | def __init__(self): |
| 62 | self.nameReMatcher = re.compile(PROC_STATUS_NAME_LINE) |
| 63 | self.pidReMatcher = re.compile(PROC_STATUS_PID_LINE) |
| 64 | self.uidReMatcher = re.compile(PROC_STATUS_UID_LINE) |
| 65 | self.packageUidMatcher = re.compile(PACKAGE_UID_LINE) |
| 66 | self.uidByProcessDict = {} # Key: Process Name, Value: {PID: UID} |
| 67 | self.packageNameByAppId = {} # Key: App ID, Value: Package name |
| 68 | |
| 69 | def parse_proc_status_dump(self, dump): |
| 70 | name, pid, uid = "", "", "" |
| 71 | |
| 72 | for line in dump.split("\n"): |
| 73 | if line.startswith("Name:"): |
| 74 | name = self.match_re(self.nameReMatcher, line) |
| 75 | pid, uid = "", "" |
| 76 | elif line.startswith("Pid:"): |
| 77 | pid = self.match_re(self.pidReMatcher, line) |
| 78 | uid = "" |
| 79 | elif line.startswith("Uid:"): |
| 80 | uid = self.match_re(self.uidReMatcher, line) |
| 81 | if name != "" and pid != "" and uid != "": |
| 82 | self.add_mapping(name, int(pid), int(uid)) |
| 83 | name, pid, uid = "", "", "" |
| 84 | |
| 85 | def parse_uid_package_dump(self, dump): |
| 86 | for line in dump.split("\n"): |
| 87 | if line == "": |
| 88 | continue |
| 89 | |
| 90 | match = self.packageUidMatcher.match(line) |
| 91 | if (match): |
| 92 | packageName = match.group(1) |
| 93 | appId = int(match.group(2)) |
| 94 | if appId in self.packageNameByAppId: |
| 95 | self.packageNameByAppId[appId].add(packageName) |
| 96 | else: |
| 97 | self.packageNameByAppId[appId] = {packageName} |
| 98 | else: |
| 99 | print("'{}' line doesn't match '{}' regex".format( |
| 100 | line, self.packageUidMatcher)) |
| 101 | |
| 102 | def match_re(self, reMatcher, line): |
| 103 | match = reMatcher.match(line) |
| 104 | if not match: |
| 105 | return "" |
| 106 | return match.group(1) |
| 107 | |
| 108 | def add_mapping(self, name, pid, uid): |
| 109 | if name in self.uidByProcessDict: |
| 110 | self.uidByProcessDict[name][pid] = uid |
| 111 | else: |
| 112 | self.uidByProcessDict[name] = {pid: uid} |
| 113 | |
| 114 | def get_uid(self, name, pid): |
| 115 | if name in self.uidByProcessDict: |
| 116 | if pid in self.uidByProcessDict[name]: |
| 117 | return self.uidByProcessDict[name][pid] |
| 118 | return UNKNOWN_UID |
| 119 | |
| 120 | def get_uid_info(self, uid): |
| 121 | appId = uid % USER_ID_OFFSET |
| 122 | if appId in self.packageNameByAppId: |
| 123 | return UidInfo(uid, " | ".join(self.packageNameByAppId[appId])) |
| 124 | else: |
| 125 | return UidInfo(uid) |