blob: e3f4bb869451c6315ea55a0ba866eea3a8c6596b [file] [log] [blame]
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.car.watchdog;
18
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070019import android.annotation.Nullable;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070020import android.automotive.watchdog.internal.ApplicationCategoryType;
21import android.automotive.watchdog.internal.ComponentType;
22import android.automotive.watchdog.internal.PackageIdentifier;
23import android.automotive.watchdog.internal.PackageInfo;
24import android.automotive.watchdog.internal.UidType;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
27import android.os.Process;
28import android.os.UserHandle;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070029import android.util.ArrayMap;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070030import android.util.IntArray;
31import android.util.SparseArray;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070032import android.util.SparseBooleanArray;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070033
34import com.android.car.CarLog;
35import com.android.internal.annotations.GuardedBy;
36import com.android.server.utils.Slogf;
37
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.List;
41
42/** Handles package info resolving */
43public final class PackageInfoHandler {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070044 public static final String SHARED_PACKAGE_PREFIX = "shared:";
45
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070046 private static final String TAG = CarLog.tagFor(PackageInfoHandler.class);
47
48 private final PackageManager mPackageManager;
49 private final Object mLock = new Object();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070050 @GuardedBy("mLock")
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070051 private final SparseArray<String> mGenericPackageNameByUid = new SparseArray<>();
52 @GuardedBy("mLock")
53 private final SparseArray<List<String>> mPackagesBySharedUid = new SparseArray<>();
54 @GuardedBy("mLock")
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -070055 private final ArrayMap<String, String> mGenericPackageNameByPackage = new ArrayMap<>();
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -070056 @GuardedBy("mLock")
57 private List<String> mVendorPackagePrefixes = new ArrayList<>();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070058
59 public PackageInfoHandler(PackageManager packageManager) {
60 mPackageManager = packageManager;
61 }
62
63 /**
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070064 * Returns the generic package names for the given UIDs.
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070065 *
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070066 * Some UIDs may not have names. This may occur when a UID is being removed and the
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070067 * internal data structures are not up-to-date. The caller should handle it.
68 */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070069 public SparseArray<String> getNamesForUids(int[] uids) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070070 IntArray unmappedUids = new IntArray(uids.length);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070071 SparseArray<String> genericPackageNameByUid = new SparseArray<>();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070072 synchronized (mLock) {
73 for (int uid : uids) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070074 String genericPackageName = mGenericPackageNameByUid.get(uid, null);
75 if (genericPackageName != null) {
76 genericPackageNameByUid.append(uid, genericPackageName);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070077 } else {
78 unmappedUids.add(uid);
79 }
80 }
81 }
82 if (unmappedUids.size() == 0) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070083 return genericPackageNameByUid;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070084 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070085 String[] genericPackageNames = mPackageManager.getNamesForUids(unmappedUids.toArray());
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070086 synchronized (mLock) {
87 for (int i = 0; i < unmappedUids.size(); ++i) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070088 if (genericPackageNames[i] == null || genericPackageNames[i].isEmpty()) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070089 continue;
90 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070091 int uid = unmappedUids.get(i);
92 String genericPackageName = genericPackageNames[i];
93 mGenericPackageNameByUid.append(uid, genericPackageName);
94 genericPackageNameByUid.append(uid, genericPackageName);
95 mGenericPackageNameByPackage.put(genericPackageName, genericPackageName);
96 if (!genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
97 continue;
98 }
99 populateSharedPackagesLocked(uid, genericPackageName);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700100 }
101 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700102 return genericPackageNameByUid;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700103 }
104
105 /**
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700106 * Returns the generic package name for the user package.
107 *
108 * Returns null when no generic package name is found.
109 */
110 @Nullable
111 public String getNameForUserPackage(String packageName, int userId) {
112 synchronized (mLock) {
113 String genericPackageName = mGenericPackageNameByPackage.get(packageName);
114 if (genericPackageName != null) {
115 return genericPackageName;
116 }
117 }
118 try {
119 return getNameForPackage(
120 mPackageManager.getPackageInfoAsUser(packageName, /* flags= */ 0, userId));
121 } catch (PackageManager.NameNotFoundException e) {
122 Slogf.e(TAG, "Package '%s' not found for user %d: %s", packageName, userId, e);
123 }
124 return null;
125 }
126
127 /** Returns the packages owned by the shared UID */
128 public List<String> getPackagesForUid(int uid, String genericPackageName) {
129 synchronized (mLock) {
130 /* When fetching the packages under a shared UID update the internal DS. This will help
131 * capture any recently installed packages.
132 */
133 populateSharedPackagesLocked(uid, genericPackageName);
134 return mPackagesBySharedUid.get(uid);
135 }
136 }
137
138 /** Returns the generic package name for the given package info. */
139 public String getNameForPackage(android.content.pm.PackageInfo packageInfo) {
140 synchronized (mLock) {
141 String genericPackageName = mGenericPackageNameByPackage.get(packageInfo.packageName);
142 if (genericPackageName != null) {
143 return genericPackageName;
144 }
145 if (packageInfo.sharedUserId != null) {
146 populateSharedPackagesLocked(packageInfo.applicationInfo.uid,
147 SHARED_PACKAGE_PREFIX + packageInfo.sharedUserId);
148 return SHARED_PACKAGE_PREFIX + packageInfo.sharedUserId;
149 }
150 mGenericPackageNameByPackage.put(packageInfo.packageName, packageInfo.packageName);
151 return packageInfo.packageName;
152 }
153 }
154
155 /**
156 * Returns the internal package infos for the given UIDs.
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700157 *
158 * Some UIDs may not have package infos. This may occur when a UID is being removed and the
159 * internal data structures are not up-to-date. The caller should handle it.
160 */
161 public List<PackageInfo> getPackageInfosForUids(int[] uids,
162 List<String> vendorPackagePrefixes) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700163 synchronized (mLock) {
164 /*
165 * Vendor package prefixes don't change frequently because it changes only when the
166 * vendor configuration is updated. Thus caching this locally during this call should
167 * keep the cache up-to-date because the daemon issues this call frequently.
168 */
169 mVendorPackagePrefixes = vendorPackagePrefixes;
170 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700171 SparseArray<String> genericPackageNameByUid = getNamesForUids(uids);
172 ArrayList<PackageInfo> packageInfos = new ArrayList<>(genericPackageNameByUid.size());
173 for (int i = 0; i < genericPackageNameByUid.size(); ++i) {
174 packageInfos.add(getPackageInfo(genericPackageNameByUid.keyAt(i),
175 genericPackageNameByUid.valueAt(i)));
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700176 }
177 return packageInfos;
178 }
179
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700180 @GuardedBy("mLock")
181 private void populateSharedPackagesLocked(int uid, String genericPackageName) {
182 String[] packages = mPackageManager.getPackagesForUid(uid);
183 for (String pkg : packages) {
184 mGenericPackageNameByPackage.put(pkg, genericPackageName);
185 }
186 mPackagesBySharedUid.put(uid, Arrays.asList(packages));
187 }
188
189 private PackageInfo getPackageInfo(int uid, String genericPackageName) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700190 PackageInfo packageInfo = new PackageInfo();
191 packageInfo.packageIdentifier = new PackageIdentifier();
192 packageInfo.packageIdentifier.uid = uid;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700193 packageInfo.packageIdentifier.name = genericPackageName;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700194 packageInfo.sharedUidPackages = new ArrayList<>();
195 packageInfo.componentType = ComponentType.UNKNOWN;
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700196 /* Application category type mapping is handled on the daemon side. */
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700197 packageInfo.appCategoryType = ApplicationCategoryType.OTHERS;
198 int userId = UserHandle.getUserId(uid);
199 int appId = UserHandle.getAppId(uid);
200 packageInfo.uidType = appId >= Process.FIRST_APPLICATION_UID ? UidType.APPLICATION :
201 UidType.NATIVE;
202
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700203 if (genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
204 List<String> packages = null;
205 synchronized (mLock) {
206 packages = mPackagesBySharedUid.get(uid);
207 if (packages == null) {
208 return packageInfo;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700209 }
210 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700211 List<ApplicationInfo> applicationInfos = new ArrayList<>();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700212 for (int i = 0; i < packages.size(); ++i) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700213 try {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700214 applicationInfos.add(mPackageManager.getApplicationInfoAsUser(packages.get(i),
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700215 /* flags= */ 0, userId));
216 } catch (PackageManager.NameNotFoundException e) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700217 Slogf.e(TAG, "Package '%s' not found for user %d: %s", packages.get(i), userId,
218 e);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700219 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700220 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700221 packageInfo.componentType = getSharedComponentType(
222 applicationInfos, genericPackageName);
223 packageInfo.sharedUidPackages = new ArrayList<>(packages);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700224 } else {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700225 packageInfo.componentType = getUserPackageComponentType(
226 userId, genericPackageName);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700227 }
228 return packageInfo;
229 }
230
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700231 /**
232 * Returns the most restrictive component type shared by the given application infos.
233 *
234 * A shared UID has multiple packages associated with it and these packages may be
235 * mapped to different component types. Thus map the shared UID to the most restrictive
236 * component type.
237 */
238 public int getSharedComponentType(List<ApplicationInfo> applicationInfos,
239 String genericPackageName) {
240 SparseBooleanArray seenComponents = new SparseBooleanArray();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700241 for (int i = 0; i < applicationInfos.size(); ++i) {
242 int type = getComponentType(applicationInfos.get(i));
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700243 seenComponents.put(type, true);
244 }
245 if (seenComponents.get(ComponentType.VENDOR)) {
246 return ComponentType.VENDOR;
247 } else if (seenComponents.get(ComponentType.SYSTEM)) {
248 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700249 for (int i = 0; i < mVendorPackagePrefixes.size(); ++i) {
250 if (genericPackageName.startsWith(mVendorPackagePrefixes.get(i))) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700251 return ComponentType.VENDOR;
252 }
253 }
254 }
255 return ComponentType.SYSTEM;
256 } else if (seenComponents.get(ComponentType.THIRD_PARTY)) {
257 return ComponentType.THIRD_PARTY;
258 }
259 return ComponentType.UNKNOWN;
260 }
261
262 private int getUserPackageComponentType(int userId, String packageName) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700263 try {
264 ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(packageName,
265 /* flags= */ 0, userId);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700266 return getComponentType(info);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700267 } catch (PackageManager.NameNotFoundException e) {
268 Slogf.e(TAG, "Package '%s' not found for user %d: %s", packageName, userId, e);
269 }
270 return ComponentType.UNKNOWN;
271 }
272
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700273 /** Returns the component type for the given application info. */
274 public int getComponentType(ApplicationInfo applicationInfo) {
275 if ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0
276 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0
277 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700278 return ComponentType.VENDOR;
279 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700280 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
281 || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
282 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0
283 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700284 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700285 for (int i = 0; i < mVendorPackagePrefixes.size(); ++i) {
286 if (applicationInfo.packageName.startsWith(mVendorPackagePrefixes.get(i))) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700287 return ComponentType.VENDOR;
288 }
289 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700290 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700291 return ComponentType.SYSTEM;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700292 }
293 return ComponentType.THIRD_PARTY;
294 }
Jahdiel Alvarez5528c712021-08-10 21:07:40 +0000295
296 void setVendorPackagePrefixes(List<String> vendorPackagePrefixes) {
297 synchronized (mLock) {
298 mVendorPackagePrefixes = vendorPackagePrefixes;
299 }
300 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700301}