blob: 359b515fdce825d1da14330ac618ba4bbfa29a84 [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 Annadorai678feda2021-10-25 16:23:46 -070030import android.util.ArraySet;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070031import android.util.IntArray;
32import android.util.SparseArray;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070033import android.util.SparseBooleanArray;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070034
35import com.android.car.CarLog;
36import com.android.internal.annotations.GuardedBy;
37import com.android.server.utils.Slogf;
38
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.List;
42
43/** Handles package info resolving */
44public final class PackageInfoHandler {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070045 public static final String SHARED_PACKAGE_PREFIX = "shared:";
46
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070047 private static final String TAG = CarLog.tagFor(PackageInfoHandler.class);
48
49 private final PackageManager mPackageManager;
50 private final Object mLock = new Object();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070051 @GuardedBy("mLock")
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070052 private final SparseArray<String> mGenericPackageNameByUid = new SparseArray<>();
53 @GuardedBy("mLock")
54 private final SparseArray<List<String>> mPackagesBySharedUid = new SparseArray<>();
55 @GuardedBy("mLock")
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -070056 private final ArrayMap<String, String> mGenericPackageNameByPackage = new ArrayMap<>();
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -070057 @GuardedBy("mLock")
Lakshman Annadorai678feda2021-10-25 16:23:46 -070058 private final SparseArray<ArraySet<String>> mGenericPackageNamesByComponentType =
59 new SparseArray<>();
60 @GuardedBy("mLock")
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -070061 private List<String> mVendorPackagePrefixes = new ArrayList<>();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070062
63 public PackageInfoHandler(PackageManager packageManager) {
64 mPackageManager = packageManager;
65 }
66
67 /**
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070068 * Returns the generic package names for the given UIDs.
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070069 *
Lakshman Annadorai678feda2021-10-25 16:23:46 -070070 * <p>Some UIDs may not have names. This may occur when a UID is being removed and the
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070071 * internal data structures are not up-to-date. The caller should handle it.
72 */
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070073 public SparseArray<String> getNamesForUids(int[] uids) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070074 IntArray unmappedUids = new IntArray(uids.length);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070075 SparseArray<String> genericPackageNameByUid = new SparseArray<>();
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070076 synchronized (mLock) {
77 for (int uid : uids) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070078 String genericPackageName = mGenericPackageNameByUid.get(uid, null);
79 if (genericPackageName != null) {
80 genericPackageNameByUid.append(uid, genericPackageName);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070081 } else {
82 unmappedUids.add(uid);
83 }
84 }
85 }
86 if (unmappedUids.size() == 0) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070087 return genericPackageNameByUid;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070088 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070089 String[] genericPackageNames = mPackageManager.getNamesForUids(unmappedUids.toArray());
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070090 synchronized (mLock) {
91 for (int i = 0; i < unmappedUids.size(); ++i) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070092 if (genericPackageNames[i] == null || genericPackageNames[i].isEmpty()) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -070093 continue;
94 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -070095 int uid = unmappedUids.get(i);
96 String genericPackageName = genericPackageNames[i];
97 mGenericPackageNameByUid.append(uid, genericPackageName);
98 genericPackageNameByUid.append(uid, genericPackageName);
99 mGenericPackageNameByPackage.put(genericPackageName, genericPackageName);
100 if (!genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
101 continue;
102 }
103 populateSharedPackagesLocked(uid, genericPackageName);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700104 }
105 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700106 return genericPackageNameByUid;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700107 }
108
109 /**
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700110 * Returns the generic package name for the user package.
111 *
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700112 * <p>Returns null when no generic package name is found.
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700113 */
114 @Nullable
115 public String getNameForUserPackage(String packageName, int userId) {
116 synchronized (mLock) {
117 String genericPackageName = mGenericPackageNameByPackage.get(packageName);
118 if (genericPackageName != null) {
119 return genericPackageName;
120 }
121 }
122 try {
123 return getNameForPackage(
124 mPackageManager.getPackageInfoAsUser(packageName, /* flags= */ 0, userId));
125 } catch (PackageManager.NameNotFoundException e) {
126 Slogf.e(TAG, "Package '%s' not found for user %d: %s", packageName, userId, e);
127 }
128 return null;
129 }
130
131 /** Returns the packages owned by the shared UID */
132 public List<String> getPackagesForUid(int uid, String genericPackageName) {
133 synchronized (mLock) {
134 /* When fetching the packages under a shared UID update the internal DS. This will help
135 * capture any recently installed packages.
136 */
137 populateSharedPackagesLocked(uid, genericPackageName);
138 return mPackagesBySharedUid.get(uid);
139 }
140 }
141
142 /** Returns the generic package name for the given package info. */
143 public String getNameForPackage(android.content.pm.PackageInfo packageInfo) {
144 synchronized (mLock) {
145 String genericPackageName = mGenericPackageNameByPackage.get(packageInfo.packageName);
146 if (genericPackageName != null) {
147 return genericPackageName;
148 }
149 if (packageInfo.sharedUserId != null) {
150 populateSharedPackagesLocked(packageInfo.applicationInfo.uid,
151 SHARED_PACKAGE_PREFIX + packageInfo.sharedUserId);
152 return SHARED_PACKAGE_PREFIX + packageInfo.sharedUserId;
153 }
154 mGenericPackageNameByPackage.put(packageInfo.packageName, packageInfo.packageName);
155 return packageInfo.packageName;
156 }
157 }
158
159 /**
160 * Returns the internal package infos for the given UIDs.
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700161 *
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700162 * <p>Some UIDs may not have package infos. This may occur when a UID is being removed and the
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700163 * internal data structures are not up-to-date. The caller should handle it.
164 */
165 public List<PackageInfo> getPackageInfosForUids(int[] uids,
166 List<String> vendorPackagePrefixes) {
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700167 setVendorPackagePrefixes(vendorPackagePrefixes);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700168 SparseArray<String> genericPackageNameByUid = getNamesForUids(uids);
169 ArrayList<PackageInfo> packageInfos = new ArrayList<>(genericPackageNameByUid.size());
170 for (int i = 0; i < genericPackageNameByUid.size(); ++i) {
171 packageInfos.add(getPackageInfo(genericPackageNameByUid.keyAt(i),
172 genericPackageNameByUid.valueAt(i)));
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700173 }
174 return packageInfos;
175 }
176
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700177 /** Returns component type for the given uid and package name. */
178 public @ComponentType int getComponentType(int uid, String genericPackageName) {
179 synchronized (mLock) {
180 for (int i = 0; i < mGenericPackageNamesByComponentType.size(); ++i) {
181 if (mGenericPackageNamesByComponentType.valueAt(i).contains(genericPackageName)) {
182 return mGenericPackageNamesByComponentType.keyAt(i);
183 }
184 }
185 }
186 int componentType = ComponentType.UNKNOWN;
187 if (genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
188 synchronized (mLock) {
189 if (!mPackagesBySharedUid.contains(uid)) {
190 populateSharedPackagesLocked(uid, genericPackageName);
191 }
192 List<String> packages = mPackagesBySharedUid.get(uid);
193 if (packages != null) {
194 componentType = getSharedComponentTypeInternal(
195 UserHandle.getUserHandleForUid(uid), packages, genericPackageName);
196 }
197 }
198 } else {
199 componentType = getUserPackageComponentType(
200 UserHandle.getUserHandleForUid(uid), genericPackageName);
201 }
202 if (componentType != ComponentType.UNKNOWN) {
203 cachePackageComponentType(genericPackageName, componentType);
204 }
205 return componentType;
206 }
207
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700208 @GuardedBy("mLock")
209 private void populateSharedPackagesLocked(int uid, String genericPackageName) {
210 String[] packages = mPackageManager.getPackagesForUid(uid);
211 for (String pkg : packages) {
212 mGenericPackageNameByPackage.put(pkg, genericPackageName);
213 }
214 mPackagesBySharedUid.put(uid, Arrays.asList(packages));
215 }
216
217 private PackageInfo getPackageInfo(int uid, String genericPackageName) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700218 PackageInfo packageInfo = new PackageInfo();
219 packageInfo.packageIdentifier = new PackageIdentifier();
220 packageInfo.packageIdentifier.uid = uid;
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700221 packageInfo.packageIdentifier.name = genericPackageName;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700222 packageInfo.sharedUidPackages = new ArrayList<>();
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700223 packageInfo.componentType = getComponentType(uid, genericPackageName);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700224 /* Application category type mapping is handled on the daemon side. */
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700225 packageInfo.appCategoryType = ApplicationCategoryType.OTHERS;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700226 int appId = UserHandle.getAppId(uid);
227 packageInfo.uidType = appId >= Process.FIRST_APPLICATION_UID ? UidType.APPLICATION :
228 UidType.NATIVE;
229
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700230 if (genericPackageName.startsWith(SHARED_PACKAGE_PREFIX)) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700231 synchronized (mLock) {
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700232 List<String> packages = mPackagesBySharedUid.get(uid);
233 if (packages != null) {
234 packageInfo.sharedUidPackages = new ArrayList<>(packages);
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700235 }
236 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700237 }
238 return packageInfo;
239 }
240
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700241 /**
242 * Returns the most restrictive component type shared by the given application infos.
243 *
244 * A shared UID has multiple packages associated with it and these packages may be
245 * mapped to different component types. Thus map the shared UID to the most restrictive
246 * component type.
247 */
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700248 public @ComponentType int getSharedComponentType(
249 List<ApplicationInfo> applicationInfos, String genericPackageName) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700250 SparseBooleanArray seenComponents = new SparseBooleanArray();
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700251 for (int i = 0; i < applicationInfos.size(); ++i) {
252 int type = getComponentType(applicationInfos.get(i));
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700253 seenComponents.put(type, true);
254 }
255 if (seenComponents.get(ComponentType.VENDOR)) {
256 return ComponentType.VENDOR;
257 } else if (seenComponents.get(ComponentType.SYSTEM)) {
258 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700259 for (int i = 0; i < mVendorPackagePrefixes.size(); ++i) {
260 if (genericPackageName.startsWith(mVendorPackagePrefixes.get(i))) {
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700261 return ComponentType.VENDOR;
262 }
263 }
264 }
265 return ComponentType.SYSTEM;
266 } else if (seenComponents.get(ComponentType.THIRD_PARTY)) {
267 return ComponentType.THIRD_PARTY;
268 }
269 return ComponentType.UNKNOWN;
270 }
271
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700272 private @ComponentType int getUserPackageComponentType(
273 UserHandle userHandle, String packageName) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700274 try {
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700275 ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(
276 packageName, /* flags= */ 0, userHandle);
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700277 return getComponentType(info);
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700278 } catch (PackageManager.NameNotFoundException e) {
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700279 Slogf.e(TAG, e, "Package '%s' not found for user %d", packageName,
280 userHandle.getIdentifier());
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700281 }
282 return ComponentType.UNKNOWN;
283 }
284
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700285 private @ComponentType int getSharedComponentTypeInternal(
286 UserHandle userHandle, List<String> packages, String genericPackageName) {
287 List<ApplicationInfo> applicationInfos = new ArrayList<>();
288 for (int i = 0; i < packages.size(); ++i) {
289 try {
290 applicationInfos.add(mPackageManager.getApplicationInfoAsUser(
291 packages.get(i), /* flags= */ 0, userHandle));
292 } catch (PackageManager.NameNotFoundException e) {
293 Slogf.w(TAG, "Package '%s' not found for user %d", packages.get(i),
294 userHandle.getIdentifier());
295 }
296 }
297 return getSharedComponentType(applicationInfos, genericPackageName);
298 }
299
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700300 /** Returns the component type for the given application info. */
301 public int getComponentType(ApplicationInfo applicationInfo) {
302 if ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0
303 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0
304 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700305 return ComponentType.VENDOR;
306 }
Lakshman Annadorai7ecdace2021-07-08 17:05:31 -0700307 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
308 || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
309 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0
310 || (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) {
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700311 synchronized (mLock) {
Lakshman Annadorai36ec22b2021-07-14 16:51:40 -0700312 for (int i = 0; i < mVendorPackagePrefixes.size(); ++i) {
313 if (applicationInfo.packageName.startsWith(mVendorPackagePrefixes.get(i))) {
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700314 return ComponentType.VENDOR;
315 }
316 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700317 }
Lakshman Annadorai5cdf80c2021-04-14 13:07:55 -0700318 return ComponentType.SYSTEM;
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700319 }
320 return ComponentType.THIRD_PARTY;
321 }
Jahdiel Alvarez5528c712021-08-10 21:07:40 +0000322
323 void setVendorPackagePrefixes(List<String> vendorPackagePrefixes) {
324 synchronized (mLock) {
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700325 if (mVendorPackagePrefixes.equals(vendorPackagePrefixes)) {
326 return;
327 }
Jahdiel Alvarez5528c712021-08-10 21:07:40 +0000328 mVendorPackagePrefixes = vendorPackagePrefixes;
Lakshman Annadorai678feda2021-10-25 16:23:46 -0700329 // When the vendor package prefixes change due to config update, the component types
330 // for these packages also change. Ergo, clear the component type cache, so the
331 // component types can be inferred again.
332 mGenericPackageNamesByComponentType.clear();
333 }
334 }
335
336 private void cachePackageComponentType(String genericPackageName,
337 @ComponentType int componentType) {
338 synchronized (mLock) {
339 ArraySet<String> packages = mGenericPackageNamesByComponentType.get(componentType);
340 if (packages == null) {
341 packages = new ArraySet<>();
342 }
343 packages.add(genericPackageName);
344 mGenericPackageNamesByComponentType.append(componentType, packages);
Jahdiel Alvarez5528c712021-08-10 21:07:40 +0000345 }
346 }
Lakshman Annadorai5f1181b2021-04-01 16:03:07 -0700347}