1 /*
2  * Copyright (C) 2023 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 package com.android.internal.pm.parsing;
17 
18 import static com.android.internal.pm.pkg.SEInfoUtil.COMPLETE_STR;
19 
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.Attribution;
26 import android.content.pm.ComponentInfo;
27 import android.content.pm.ConfigurationInfo;
28 import android.content.pm.FallbackCategoryProvider;
29 import android.content.pm.FeatureGroupInfo;
30 import android.content.pm.FeatureInfo;
31 import android.content.pm.InstrumentationInfo;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.PackageItemInfo;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PathPermission;
36 import android.content.pm.PermissionInfo;
37 import android.content.pm.ProviderInfo;
38 import android.content.pm.ServiceInfo;
39 import android.content.pm.Signature;
40 import android.content.pm.SigningDetails;
41 import android.content.pm.SigningInfo;
42 import android.os.Debug;
43 import android.os.PatternMatcher;
44 import android.os.UserHandle;
45 import android.util.DebugUtils;
46 import android.util.Slog;
47 
48 import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
49 import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
50 import com.android.internal.pm.parsing.pkg.PackageImpl;
51 import com.android.internal.pm.pkg.component.ComponentParseUtils;
52 import com.android.internal.pm.pkg.component.ParsedActivity;
53 import com.android.internal.pm.pkg.component.ParsedAttribution;
54 import com.android.internal.pm.pkg.component.ParsedComponent;
55 import com.android.internal.pm.pkg.component.ParsedInstrumentation;
56 import com.android.internal.pm.pkg.component.ParsedMainComponent;
57 import com.android.internal.pm.pkg.component.ParsedPermission;
58 import com.android.internal.pm.pkg.component.ParsedProvider;
59 import com.android.internal.pm.pkg.component.ParsedService;
60 import com.android.internal.pm.pkg.component.ParsedUsesPermission;
61 import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
62 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
63 import com.android.internal.pm.pkg.parsing.ParsingUtils;
64 import com.android.internal.util.ArrayUtils;
65 import com.android.server.pm.pkg.AndroidPackage;
66 
67 import java.util.List;
68 
69 /**
70  * Method that use a {@link AndroidPackage} to generate a {@link PackageInfo} though
71  * the given {@link PackageManager.PackageInfoFlags}
72  * @hide
73  **/
74 // TODO(b/317215254): refactor coped code from PackageInfoUtils
75 public class PackageInfoCommonUtils {
76 
77     private static final String TAG = ParsingUtils.TAG;
78     private static final boolean DEBUG = false;
79 
80     /**
81      * Generates a {@link PackageInfo} from the given {@link AndroidPackage}
82      */
83     @Nullable
generate(@ullable AndroidPackage pkg, @PackageManager.PackageInfoFlagsBits long flags, int userId)84     public static PackageInfo generate(@Nullable AndroidPackage pkg,
85             @PackageManager.PackageInfoFlagsBits long flags, int userId) {
86         if (pkg == null) {
87             return null;
88         }
89         ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, userId);
90 
91         PackageInfo info = new PackageInfo();
92         info.packageName = pkg.getPackageName();
93         info.splitNames = pkg.getSplitNames();
94         info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
95         info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
96         info.baseRevisionCode = pkg.getBaseRevisionCode();
97         info.splitRevisionCodes = pkg.getSplitRevisionCodes();
98         info.versionName = pkg.getVersionName();
99         if (!pkg.isLeavingSharedUser()) {
100             info.sharedUserId = pkg.getSharedUserId();
101             info.sharedUserLabel = pkg.getSharedUserLabelResourceId();
102         }
103         info.applicationInfo = applicationInfo;
104         info.installLocation = pkg.getInstallLocation();
105         if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
106                 || (info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
107             info.requiredForAllUsers = pkg.isRequiredForAllUsers();
108         }
109         info.restrictedAccountType = pkg.getRestrictedAccountType();
110         info.requiredAccountType = pkg.getRequiredAccountType();
111         info.overlayTarget = pkg.getOverlayTarget();
112         info.targetOverlayableName = pkg.getOverlayTargetOverlayableName();
113         info.overlayCategory = pkg.getOverlayCategory();
114         info.overlayPriority = pkg.getOverlayPriority();
115         info.mOverlayIsStatic = pkg.isOverlayIsStatic();
116         info.compileSdkVersion = pkg.getCompileSdkVersion();
117         info.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
118         info.isStub = pkg.isStub();
119         info.coreApp = pkg.isCoreApp();
120         info.isApex = pkg.isApex();
121 
122         if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
123             int size = pkg.getConfigPreferences().size();
124             if (size > 0) {
125                 info.configPreferences = new ConfigurationInfo[size];
126                 pkg.getConfigPreferences().toArray(info.configPreferences);
127             }
128             size = pkg.getRequestedFeatures().size();
129             if (size > 0) {
130                 info.reqFeatures = new FeatureInfo[size];
131                 pkg.getRequestedFeatures().toArray(info.reqFeatures);
132             }
133             size = pkg.getFeatureGroups().size();
134             if (size > 0) {
135                 info.featureGroups = new FeatureGroupInfo[size];
136                 pkg.getFeatureGroups().toArray(info.featureGroups);
137             }
138         }
139         if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
140             int size = ArrayUtils.size(pkg.getPermissions());
141             if (size > 0) {
142                 info.permissions = new PermissionInfo[size];
143                 for (int i = 0; i < size; i++) {
144                     final var permission = pkg.getPermissions().get(i);
145                     final var permissionInfo = generatePermissionInfo(permission, flags);
146                     info.permissions[i] = permissionInfo;
147                 }
148             }
149             final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
150             size = usesPermissions.size();
151             if (size > 0) {
152                 info.requestedPermissions = new String[size];
153                 info.requestedPermissionsFlags = new int[size];
154                 for (int i = 0; i < size; i++) {
155                     final ParsedUsesPermission usesPermission = usesPermissions.get(i);
156                     info.requestedPermissions[i] = usesPermission.getName();
157                     // The notion of required permissions is deprecated but for compatibility.
158                     info.requestedPermissionsFlags[i] |=
159                             PackageInfo.REQUESTED_PERMISSION_REQUIRED;
160                     if ((usesPermission.getUsesPermissionFlags()
161                             & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0) {
162                         info.requestedPermissionsFlags[i] |=
163                                 PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
164                     }
165                     if (pkg.getImplicitPermissions().contains(info.requestedPermissions[i])) {
166                         info.requestedPermissionsFlags[i] |=
167                                 PackageInfo.REQUESTED_PERMISSION_IMPLICIT;
168                     }
169                 }
170             }
171         }
172         if ((flags & PackageManager.GET_ATTRIBUTIONS_LONG) != 0) {
173             int size = ArrayUtils.size(pkg.getAttributions());
174             if (size > 0) {
175                 info.attributions = new Attribution[size];
176                 for (int i = 0; i < size; i++) {
177                     ParsedAttribution parsedAttribution = pkg.getAttributions().get(i);
178                     if (parsedAttribution != null) {
179                         info.attributions[i] = new Attribution(parsedAttribution.getTag(),
180                                 parsedAttribution.getLabel());
181                     }
182                 }
183             }
184             if (pkg.isAttributionsUserVisible()) {
185                 info.applicationInfo.privateFlagsExt
186                         |= ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
187             } else {
188                 info.applicationInfo.privateFlagsExt
189                         &= ~ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
190             }
191         } else {
192             info.applicationInfo.privateFlagsExt
193                     &= ~ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
194         }
195 
196         final SigningDetails signingDetails = pkg.getSigningDetails();
197         // deprecated method of getting signing certificates
198         if ((flags & PackageManager.GET_SIGNATURES) != 0) {
199             if (signingDetails.hasPastSigningCertificates()) {
200                 // Package has included signing certificate rotation information.  Return the oldest
201                 // cert so that programmatic checks keep working even if unaware of key rotation.
202                 info.signatures = new Signature[1];
203                 info.signatures[0] = signingDetails.getPastSigningCertificates()[0];
204             } else if (signingDetails.hasSignatures()) {
205                 // otherwise keep old behavior
206                 int numberOfSigs = signingDetails.getSignatures().length;
207                 info.signatures = new Signature[numberOfSigs];
208                 System.arraycopy(signingDetails.getSignatures(), 0, info.signatures, 0,
209                         numberOfSigs);
210             }
211         }
212 
213         // replacement for GET_SIGNATURES
214         if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
215             if (signingDetails != SigningDetails.UNKNOWN) {
216                 // only return a valid SigningInfo if there is signing information to report
217                 info.signingInfo = new SigningInfo(signingDetails);
218             } else {
219                 info.signingInfo = null;
220             }
221         }
222 
223         if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
224             final int size = pkg.getActivities().size();
225             if (size > 0) {
226                 int num = 0;
227                 final ActivityInfo[] res = new ActivityInfo[size];
228                 for (int i = 0; i < size; i++) {
229                     final ParsedActivity a = pkg.getActivities().get(i);
230                     if (isMatch(pkg, a.isDirectBootAware(), flags)) {
231                         if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
232                                 a.getName())) {
233                             continue;
234                         }
235                         res[num++] = generateActivityInfo(a, flags, applicationInfo);
236                     }
237                 }
238                 info.activities = ArrayUtils.trimToSize(res, num);
239             }
240         }
241         if ((flags & PackageManager.GET_RECEIVERS) != 0) {
242             final int size = pkg.getReceivers().size();
243             if (size > 0) {
244                 int num = 0;
245                 final ActivityInfo[] res = new ActivityInfo[size];
246                 for (int i = 0; i < size; i++) {
247                     final ParsedActivity a = pkg.getReceivers().get(i);
248                     if (isMatch(pkg, a.isDirectBootAware(), flags)) {
249                         res[num++] = generateActivityInfo(a, flags, applicationInfo);
250                     }
251                 }
252                 info.receivers = ArrayUtils.trimToSize(res, num);
253             }
254         }
255         if ((flags & PackageManager.GET_SERVICES) != 0) {
256             final int size = pkg.getServices().size();
257             if (size > 0) {
258                 int num = 0;
259                 final ServiceInfo[] res = new ServiceInfo[size];
260                 for (int i = 0; i < size; i++) {
261                     final ParsedService s = pkg.getServices().get(i);
262                     if (isMatch(pkg, s.isDirectBootAware(), flags)) {
263                         res[num++] = generateServiceInfo(s, flags, applicationInfo);
264                     }
265                 }
266                 info.services = ArrayUtils.trimToSize(res, num);
267             }
268         }
269         if ((flags & PackageManager.GET_PROVIDERS) != 0) {
270             final int size = pkg.getProviders().size();
271             if (size > 0) {
272                 int num = 0;
273                 final ProviderInfo[] res = new ProviderInfo[size];
274                 for (int i = 0; i < size; i++) {
275                     final ParsedProvider pr = pkg.getProviders().get(i);
276                     if (isMatch(pkg, pr.isDirectBootAware(), flags)) {
277                         res[num++] = generateProviderInfo(pkg, pr, flags, applicationInfo, userId);
278                     }
279                 }
280                 info.providers = ArrayUtils.trimToSize(res, num);
281             }
282         }
283         if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
284             final int size = pkg.getInstrumentations().size();
285             if (size > 0) {
286                 info.instrumentation = new InstrumentationInfo[size];
287                 for (int i = 0; i < size; i++) {
288                     info.instrumentation[i] = generateInstrumentationInfo(
289                             pkg.getInstrumentations().get(i), pkg, flags, userId);
290                 }
291             }
292         }
293 
294         return info;
295     }
296 
updateApplicationInfo(ApplicationInfo ai, long flags)297     private static void updateApplicationInfo(ApplicationInfo ai, long flags) {
298         if ((flags & PackageManager.GET_META_DATA) == 0) {
299             ai.metaData = null;
300         }
301         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
302             ai.sharedLibraryFiles = null;
303             ai.sharedLibraryInfos = null;
304         }
305 
306         // CompatibilityMode is global state.
307         if (!ParsingPackageUtils.sCompatibilityModeEnabled) {
308             ai.disableCompatibilityMode();
309         }
310 
311         if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
312             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
313         }
314         ai.seInfoUser = COMPLETE_STR;
315     }
316 
317     @Nullable
generateApplicationInfo(@onNull AndroidPackage pkg, @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId)318     private static ApplicationInfo generateApplicationInfo(@NonNull AndroidPackage pkg,
319             @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId) {
320 
321         // Make shallow copy so we can store the metadata/libraries safely
322         ApplicationInfo info = ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
323 
324         updateApplicationInfo(info, flags);
325 
326         initForUser(info, pkg, userId);
327 
328         info.primaryCpuAbi = AndroidPackageLegacyUtils.getRawPrimaryCpuAbi(pkg);
329         info.secondaryCpuAbi = AndroidPackageLegacyUtils.getRawSecondaryCpuAbi(pkg);
330 
331         if ((flags & PackageManager.GET_META_DATA) != 0) {
332             info.metaData = pkg.getMetaData();
333         }
334         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
335             List<String> usesLibraryFiles = pkg.getUsesLibraries();
336 
337             info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
338                     ? null : usesLibraryFiles.toArray(new String[0]);
339         }
340 
341         return info;
342     }
343 
344     @Nullable
generateActivityInfo(ParsedActivity a, @PackageManager.ComponentInfoFlagsBits long flags, @NonNull ApplicationInfo applicationInfo)345     private static ActivityInfo generateActivityInfo(ParsedActivity a,
346             @PackageManager.ComponentInfoFlagsBits long flags,
347             @NonNull ApplicationInfo applicationInfo) {
348         if (a == null) return null;
349 
350         // Make shallow copies so we can store the metadata safely
351         ActivityInfo ai = new ActivityInfo();
352         ai.targetActivity = a.getTargetActivity();
353         ai.processName = a.getProcessName();
354         ai.exported = a.isExported();
355         ai.theme = a.getTheme();
356         ai.uiOptions = a.getUiOptions();
357         ai.parentActivityName = a.getParentActivityName();
358         ai.permission = a.getPermission();
359         ai.taskAffinity = a.getTaskAffinity();
360         ai.flags = a.getFlags();
361         ai.privateFlags = a.getPrivateFlags();
362         ai.launchMode = a.getLaunchMode();
363         ai.documentLaunchMode = a.getDocumentLaunchMode();
364         ai.maxRecents = a.getMaxRecents();
365         ai.configChanges = a.getConfigChanges();
366         ai.softInputMode = a.getSoftInputMode();
367         ai.persistableMode = a.getPersistableMode();
368         ai.lockTaskLaunchMode = a.getLockTaskLaunchMode();
369         ai.screenOrientation = a.getScreenOrientation();
370         ai.resizeMode = a.getResizeMode();
371         ai.setMaxAspectRatio(a.getMaxAspectRatio());
372         ai.setMinAspectRatio(a.getMinAspectRatio());
373         ai.supportsSizeChanges = a.isSupportsSizeChanges();
374         ai.requestedVrComponent = a.getRequestedVrComponent();
375         ai.rotationAnimation = a.getRotationAnimation();
376         ai.colorMode = a.getColorMode();
377         ai.windowLayout = a.getWindowLayout();
378         ai.attributionTags = a.getAttributionTags();
379         if ((flags & PackageManager.GET_META_DATA) != 0) {
380             var metaData = a.getMetaData();
381             // Backwards compatibility, coerce to null if empty
382             ai.metaData = metaData.isEmpty() ? null : metaData;
383         } else {
384             ai.metaData = null;
385         }
386         ai.applicationInfo = applicationInfo;
387         ai.requiredDisplayCategory = a.getRequiredDisplayCategory();
388         ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
389         assignFieldsComponentInfoParsedMainComponent(ai, a);
390         return ai;
391     }
392 
393     @Nullable
generateServiceInfo(ParsedService s, @PackageManager.ComponentInfoFlagsBits long flags, @NonNull ApplicationInfo applicationInfo)394     private static ServiceInfo generateServiceInfo(ParsedService s,
395             @PackageManager.ComponentInfoFlagsBits long flags,
396             @NonNull ApplicationInfo applicationInfo) {
397         if (s == null) return null;
398 
399         // Make shallow copies so we can store the metadata safely
400         ServiceInfo si = new ServiceInfo();
401         si.exported = s.isExported();
402         si.flags = s.getFlags();
403         si.permission = s.getPermission();
404         si.processName = s.getProcessName();
405         si.mForegroundServiceType = s.getForegroundServiceType();
406         si.applicationInfo = applicationInfo;
407         if ((flags & PackageManager.GET_META_DATA) != 0) {
408             var metaData = s.getMetaData();
409             // Backwards compatibility, coerce to null if empty
410             si.metaData = metaData.isEmpty() ? null : metaData;
411         }
412         assignFieldsComponentInfoParsedMainComponent(si, s);
413         return si;
414     }
415 
416     @Nullable
generateProviderInfo(AndroidPackage pkg, ParsedProvider p, @PackageManager.ComponentInfoFlagsBits long flags, @NonNull ApplicationInfo applicationInfo, int userId)417     private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
418             @PackageManager.ComponentInfoFlagsBits long flags,
419             @NonNull ApplicationInfo applicationInfo, int userId) {
420         if (p == null) return null;
421 
422         if (!pkg.getPackageName().equals(applicationInfo.packageName)) {
423             Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName()
424                     + " actual=" + applicationInfo.packageName);
425             applicationInfo = generateApplicationInfo(pkg, flags, userId);
426         }
427 
428         // Make shallow copies so we can store the metadata safely
429         ProviderInfo pi = new ProviderInfo();
430         pi.exported = p.isExported();
431         pi.flags = p.getFlags();
432         pi.processName = p.getProcessName();
433         pi.authority = p.getAuthority();
434         pi.isSyncable = p.isSyncable();
435         pi.readPermission = p.getReadPermission();
436         pi.writePermission = p.getWritePermission();
437         pi.grantUriPermissions = p.isGrantUriPermissions();
438         pi.forceUriPermissions = p.isForceUriPermissions();
439         pi.multiprocess = p.isMultiProcess();
440         pi.initOrder = p.getInitOrder();
441         pi.uriPermissionPatterns = p.getUriPermissionPatterns().toArray(new PatternMatcher[0]);
442         pi.pathPermissions = p.getPathPermissions().toArray(new PathPermission[0]);
443         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
444             pi.uriPermissionPatterns = null;
445         }
446         if ((flags & PackageManager.GET_META_DATA) != 0) {
447             var metaData = p.getMetaData();
448             // Backwards compatibility, coerce to null if empty
449             pi.metaData = metaData.isEmpty() ? null : metaData;
450         }
451         pi.applicationInfo = applicationInfo;
452         assignFieldsComponentInfoParsedMainComponent(pi, p);
453         return pi;
454     }
455 
456     @Nullable
generateInstrumentationInfo(ParsedInstrumentation i, AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId)457     private static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
458             AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
459         if (i == null) return null;
460 
461         InstrumentationInfo info = new InstrumentationInfo();
462         info.targetPackage = i.getTargetPackage();
463         info.targetProcesses = i.getTargetProcesses();
464         info.handleProfiling = i.isHandleProfiling();
465         info.functionalTest = i.isFunctionalTest();
466 
467         info.sourceDir = pkg.getBaseApkPath();
468         info.publicSourceDir = pkg.getBaseApkPath();
469         info.splitNames = pkg.getSplitNames();
470         info.splitSourceDirs = pkg.getSplitCodePaths().length == 0 ? null : pkg.getSplitCodePaths();
471         info.splitPublicSourceDirs = pkg.getSplitCodePaths().length == 0
472                 ? null : pkg.getSplitCodePaths();
473         info.splitDependencies = pkg.getSplitDependencies().size() == 0
474                 ? null : pkg.getSplitDependencies();
475 
476         initForUser(info, pkg, userId);
477 
478         info.primaryCpuAbi = AndroidPackageLegacyUtils.getRawPrimaryCpuAbi(pkg);
479         info.secondaryCpuAbi = AndroidPackageLegacyUtils.getRawSecondaryCpuAbi(pkg);
480         info.nativeLibraryDir = pkg.getNativeLibraryDir();
481         info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
482 
483         assignFieldsPackageItemInfoParsedComponent(info, i);
484 
485         if ((flags & PackageManager.GET_META_DATA) == 0) {
486             info.metaData = null;
487         } else {
488             var metaData = i.getMetaData();
489             // Backwards compatibility, coerce to null if empty
490             info.metaData = metaData.isEmpty() ? null : metaData;
491         }
492 
493         return info;
494     }
495 
496     @Nullable
generatePermissionInfo(ParsedPermission p, @PackageManager.ComponentInfoFlagsBits long flags)497     private static PermissionInfo generatePermissionInfo(ParsedPermission p,
498             @PackageManager.ComponentInfoFlagsBits long flags) {
499         // TODO(b/135203078): Remove null checks and make all usages @NonNull
500         if (p == null) return null;
501 
502         PermissionInfo pi = new PermissionInfo(p.getBackgroundPermission());
503 
504         assignFieldsPackageItemInfoParsedComponent(pi, p);
505 
506         pi.group = p.getGroup();
507         pi.requestRes = p.getRequestRes();
508         pi.protectionLevel = p.getProtectionLevel();
509         pi.descriptionRes = p.getDescriptionRes();
510         pi.flags = p.getFlags();
511         pi.knownCerts = p.getKnownCerts();
512 
513         if ((flags & PackageManager.GET_META_DATA) == 0) {
514             pi.metaData = null;
515         } else {
516             var metaData = p.getMetaData();
517             // Backwards compatibility, coerce to null if empty
518             pi.metaData = metaData.isEmpty() ? null : metaData;
519         }
520         return pi;
521     }
522 
assignFieldsComponentInfoParsedMainComponent( @onNull ComponentInfo info, @NonNull ParsedMainComponent component)523     private static void assignFieldsComponentInfoParsedMainComponent(
524             @NonNull ComponentInfo info, @NonNull ParsedMainComponent component) {
525         assignFieldsPackageItemInfoParsedComponent(info, component);
526         info.descriptionRes = component.getDescriptionRes();
527         info.directBootAware = component.isDirectBootAware();
528         info.enabled = component.isEnabled();
529         info.splitName = component.getSplitName();
530         info.attributionTags = component.getAttributionTags();
531         info.nonLocalizedLabel = component.getNonLocalizedLabel();
532         info.icon = component.getIcon();
533     }
534 
assignFieldsPackageItemInfoParsedComponent( @onNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component)535     private static void assignFieldsPackageItemInfoParsedComponent(
536             @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
537         packageItemInfo.nonLocalizedLabel = ComponentParseUtils.getNonLocalizedLabel(component);
538         packageItemInfo.icon = ComponentParseUtils.getIcon(component);
539         packageItemInfo.banner = component.getBanner();
540         packageItemInfo.labelRes = component.getLabelRes();
541         packageItemInfo.logo = component.getLogo();
542         packageItemInfo.name = component.getName();
543         packageItemInfo.packageName = component.getPackageName();
544     }
545 
initForUser(ApplicationInfo output, AndroidPackage input, @UserIdInt int userId)546     private static void initForUser(ApplicationInfo output, AndroidPackage input,
547             @UserIdInt int userId) {
548         PackageImpl pkg = ((PackageImpl) input);
549         String packageName = input.getPackageName();
550         output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid()));
551 
552         // For performance reasons, all these paths are built as strings
553         final String credentialDir = pkg.getBaseAppDataCredentialProtectedDirForSystemUser();
554         final String deviceDir = pkg.getBaseAppDataDeviceProtectedDirForSystemUser();
555         if (credentialDir !=  null && deviceDir != null) {
556             if (userId == UserHandle.USER_SYSTEM) {
557                 output.credentialProtectedDataDir = credentialDir + packageName;
558                 output.deviceProtectedDataDir = deviceDir + packageName;
559             } else {
560                 // Convert /data/user/0/ -> /data/user/1/com.example.app
561                 String userIdString = String.valueOf(userId);
562                 int credentialLength = credentialDir.length();
563                 output.credentialProtectedDataDir = new StringBuilder(credentialDir)
564                         .replace(credentialLength - 2, credentialLength - 1, userIdString)
565                         .append(packageName)
566                         .toString();
567                 int deviceLength = deviceDir.length();
568                 output.deviceProtectedDataDir = new StringBuilder(deviceDir)
569                         .replace(deviceLength - 2, deviceLength - 1, userIdString)
570                         .append(packageName)
571                         .toString();
572             }
573         }
574 
575         if (input.isDefaultToDeviceProtectedStorage()
576                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
577             output.dataDir = output.deviceProtectedDataDir;
578         } else {
579             output.dataDir = output.credentialProtectedDataDir;
580         }
581     }
582 
583     // This duplicates the ApplicationInfo variant because it uses field assignment and the classes
584     // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead.
initForUser(InstrumentationInfo output, AndroidPackage input, @UserIdInt int userId)585     private static void initForUser(InstrumentationInfo output, AndroidPackage input,
586             @UserIdInt int userId) {
587         PackageImpl pkg = ((PackageImpl) input);
588         String packageName = input.getPackageName();
589 
590         // For performance reasons, all these paths are built as strings
591         final String credentialDir = pkg.getBaseAppDataCredentialProtectedDirForSystemUser();
592         final String deviceDir = pkg.getBaseAppDataDeviceProtectedDirForSystemUser();
593         if (credentialDir !=  null && deviceDir != null) {
594             if (userId == UserHandle.USER_SYSTEM) {
595                 output.credentialProtectedDataDir = credentialDir + packageName;
596                 output.deviceProtectedDataDir = deviceDir + packageName;
597             } else {
598                 // Convert /data/user/0/ -> /data/user/1/com.example.app
599                 String userIdString = String.valueOf(userId);
600                 int credentialLength = credentialDir.length();
601                 output.credentialProtectedDataDir = new StringBuilder(credentialDir)
602                         .replace(credentialLength - 2, credentialLength - 1, userIdString)
603                         .append(packageName)
604                         .toString();
605                 int deviceLength = deviceDir.length();
606                 output.deviceProtectedDataDir = new StringBuilder(deviceDir)
607                         .replace(deviceLength - 2, deviceLength - 1, userIdString)
608                         .append(packageName)
609                         .toString();
610             }
611         }
612 
613         if (input.isDefaultToDeviceProtectedStorage()
614                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
615             output.dataDir = output.deviceProtectedDataDir;
616         } else {
617             output.dataDir = output.credentialProtectedDataDir;
618         }
619     }
620 
621     /**
622      * Test if the given component is considered system, enabled and a match for the given
623      * flags.
624      *
625      * <p>
626      * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link
627      * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
628      * </p>
629      */
isMatch(AndroidPackage pkg, boolean isComponentDirectBootAware, long flags)630     private static boolean isMatch(AndroidPackage pkg,
631             boolean isComponentDirectBootAware, long flags) {
632         final boolean isSystem = ((AndroidPackageHidden) pkg).isSystem();
633         if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
634             if (!isSystem) {
635                 return reportIfDebug(false, flags);
636             }
637         }
638 
639         final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0)
640                 && !isComponentDirectBootAware;
641         final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0)
642                 && isComponentDirectBootAware;
643         return reportIfDebug(matchesUnaware || matchesAware, flags);
644     }
645 
reportIfDebug(boolean result, long flags)646     private static boolean reportIfDebug(boolean result, long flags) {
647         if (DEBUG && !result) {
648             Slog.i(TAG, "No match!; flags: "
649                     + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
650                     + Debug.getCaller());
651         }
652         return result;
653     }
654 }
655