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