• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.pm.parsing;
18 
19 import android.annotation.CheckResult;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.apex.ApexInfo;
24 import android.content.pm.ActivityInfo;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.ComponentInfo;
27 import android.content.pm.InstrumentationInfo;
28 import android.content.pm.PackageInfo;
29 import android.content.pm.PackageItemInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.PermissionGroupInfo;
32 import android.content.pm.PermissionInfo;
33 import android.content.pm.ProcessInfo;
34 import android.content.pm.ProviderInfo;
35 import android.content.pm.ServiceInfo;
36 import android.content.pm.SharedLibraryInfo;
37 import android.os.UserHandle;
38 import android.util.ArrayMap;
39 import android.util.ArraySet;
40 import android.util.Pair;
41 import android.util.Slog;
42 
43 import com.android.internal.util.ArrayUtils;
44 import com.android.server.pm.parsing.pkg.AndroidPackage;
45 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
46 import com.android.server.pm.parsing.pkg.PackageImpl;
47 import com.android.server.pm.pkg.PackageStateInternal;
48 import com.android.server.pm.pkg.PackageStateUnserialized;
49 import com.android.server.pm.pkg.PackageUserStateInternal;
50 import com.android.server.pm.pkg.PackageUserStateUtils;
51 import com.android.server.pm.pkg.component.ComponentParseUtils;
52 import com.android.server.pm.pkg.component.ParsedActivity;
53 import com.android.server.pm.pkg.component.ParsedComponent;
54 import com.android.server.pm.pkg.component.ParsedInstrumentation;
55 import com.android.server.pm.pkg.component.ParsedMainComponent;
56 import com.android.server.pm.pkg.component.ParsedPermission;
57 import com.android.server.pm.pkg.component.ParsedPermissionGroup;
58 import com.android.server.pm.pkg.component.ParsedProcess;
59 import com.android.server.pm.pkg.component.ParsedProvider;
60 import com.android.server.pm.pkg.component.ParsedService;
61 import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
62 import com.android.server.pm.pkg.parsing.ParsingUtils;
63 
64 import libcore.util.EmptyArray;
65 
66 import java.util.Collections;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Set;
70 
71 
72 /**
73  * Methods that use a {@link PackageStateInternal} use it to override information provided from the
74  * raw package, or to provide information that would otherwise be missing. Null can be passed if
75  * none of the state values should be applied.
76  *
77  * @hide
78  **/
79 public class PackageInfoUtils {
80     private static final String TAG = ParsingUtils.TAG;
81 
82     /**
83      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
84      */
85     @Nullable
generate(AndroidPackage pkg, int[] gids, @PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserStateInternal state, @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting)86     public static PackageInfo generate(AndroidPackage pkg, int[] gids,
87             @PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
88             long lastUpdateTime, Set<String> grantedPermissions, PackageUserStateInternal state,
89             @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting) {
90         return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
91                 grantedPermissions, state, userId, null, pkgSetting);
92     }
93 
94     /**
95      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
96      */
97     @Nullable
generate(AndroidPackage pkg, ApexInfo apexInfo, int flags, @Nullable PackageStateInternal pkgSetting)98     public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
99             @Nullable PackageStateInternal pkgSetting) {
100         return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
101                 PackageUserStateInternal.DEFAULT, UserHandle.getCallingUserId(), apexInfo, pkgSetting);
102     }
103 
104     /**
105      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
106      */
generateWithComponents(AndroidPackage pkg, int[] gids, @PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserStateInternal state, @UserIdInt int userId, @Nullable ApexInfo apexInfo, @Nullable PackageStateInternal pkgSetting)107     private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
108             @PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
109             long lastUpdateTime, Set<String> grantedPermissions, PackageUserStateInternal state,
110             @UserIdInt int userId, @Nullable ApexInfo apexInfo,
111             @Nullable PackageStateInternal pkgSetting) {
112         ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId,
113                 pkgSetting);
114         if (applicationInfo == null) {
115             return null;
116         }
117 
118         PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponentsUnchecked(pkg,
119                 gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, state, userId,
120                 apexInfo, applicationInfo);
121 
122         info.isStub = pkg.isStub();
123         info.coreApp = pkg.isCoreApp();
124 
125         if (pkgSetting != null && !pkgSetting.hasSharedUser()) {
126             // It is possible that this shared UID app has left
127             info.sharedUserId = null;
128             info.sharedUserLabel = 0;
129         }
130 
131         if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
132             final int N = pkg.getActivities().size();
133             if (N > 0) {
134                 int num = 0;
135                 final ActivityInfo[] res = new ActivityInfo[N];
136                 for (int i = 0; i < N; i++) {
137                     final ParsedActivity a = pkg.getActivities().get(i);
138                     if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a,
139                             flags)) {
140                         if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
141                                 a.getName())) {
142                             continue;
143                         }
144                         res[num++] = generateActivityInfo(pkg, a, flags, state,
145                                 applicationInfo, userId, pkgSetting);
146                     }
147                 }
148                 info.activities = ArrayUtils.trimToSize(res, num);
149             }
150         }
151         if ((flags & PackageManager.GET_RECEIVERS) != 0) {
152             final int size = pkg.getReceivers().size();
153             if (size > 0) {
154                 int num = 0;
155                 final ActivityInfo[] res = new ActivityInfo[size];
156                 for (int i = 0; i < size; i++) {
157                     final ParsedActivity a = pkg.getReceivers().get(i);
158                     if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a,
159                             flags)) {
160                         res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
161                                 userId, pkgSetting);
162                     }
163                 }
164                 info.receivers = ArrayUtils.trimToSize(res, num);
165             }
166         }
167         if ((flags & PackageManager.GET_SERVICES) != 0) {
168             final int size = pkg.getServices().size();
169             if (size > 0) {
170                 int num = 0;
171                 final ServiceInfo[] res = new ServiceInfo[size];
172                 for (int i = 0; i < size; i++) {
173                     final ParsedService s = pkg.getServices().get(i);
174                     if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), s,
175                             flags)) {
176                         res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
177                                 userId, pkgSetting);
178                     }
179                 }
180                 info.services = ArrayUtils.trimToSize(res, num);
181             }
182         }
183         if ((flags & PackageManager.GET_PROVIDERS) != 0) {
184             final int size = pkg.getProviders().size();
185             if (size > 0) {
186                 int num = 0;
187                 final ProviderInfo[] res = new ProviderInfo[size];
188                 for (int i = 0; i < size; i++) {
189                     final ParsedProvider pr = pkg.getProviders()
190                             .get(i);
191                     if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), pr,
192                             flags)) {
193                         res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
194                                 userId, pkgSetting);
195                     }
196                 }
197                 info.providers = ArrayUtils.trimToSize(res, num);
198             }
199         }
200         if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
201             int N = pkg.getInstrumentations().size();
202             if (N > 0) {
203                 info.instrumentation = new InstrumentationInfo[N];
204                 for (int i = 0; i < N; i++) {
205                     info.instrumentation[i] = generateInstrumentationInfo(
206                             pkg.getInstrumentations().get(i), pkg, flags, userId, pkgSetting);
207                 }
208             }
209         }
210 
211         return info;
212     }
213 
214     /**
215      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
216      */
217     @Nullable
generateApplicationInfo(AndroidPackage pkg, @PackageManager.ApplicationInfoFlagsBits long flags, @NonNull PackageUserStateInternal state, @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting)218     public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
219             @PackageManager.ApplicationInfoFlagsBits long flags,
220             @NonNull PackageUserStateInternal state, @UserIdInt int userId,
221             @Nullable PackageStateInternal pkgSetting) {
222         if (pkg == null) {
223             return null;
224         }
225 
226         if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)
227                 || !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) {
228             return null;
229         }
230 
231         ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(pkg,
232                 flags, state, userId, false /* assignUserFields */);
233 
234         initForUser(info, pkg, userId);
235 
236         if (pkgSetting != null) {
237             // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up
238             PackageStateUnserialized pkgState = pkgSetting.getTransientState();
239             info.hiddenUntilInstalled = pkgState.isHiddenUntilInstalled();
240             List<String> usesLibraryFiles = pkgState.getUsesLibraryFiles();
241             List<SharedLibraryInfo> usesLibraryInfos = pkgState.getUsesLibraryInfos();
242             info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
243                     ? null : usesLibraryFiles.toArray(new String[0]);
244             info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
245             if (info.category == ApplicationInfo.CATEGORY_UNDEFINED) {
246                 info.category = pkgSetting.getCategoryOverride();
247             }
248         }
249 
250         info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
251         info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
252         info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting);
253 
254         info.flags |= appInfoFlags(info.flags, pkgSetting);
255         info.privateFlags |= appInfoPrivateFlags(info.privateFlags, pkgSetting);
256         info.privateFlagsExt |= appInfoPrivateFlagsExt(info.privateFlagsExt, pkgSetting);
257 
258         return info;
259     }
260 
261     /**
262      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
263      */
264     @Nullable
generateActivityInfo(AndroidPackage pkg, ParsedActivity a, @PackageManager.ComponentInfoFlagsBits long flags, @NonNull PackageUserStateInternal state, @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting)265     public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
266             @PackageManager.ComponentInfoFlagsBits long flags,
267             @NonNull PackageUserStateInternal state, @UserIdInt int userId,
268             @Nullable PackageStateInternal pkgSetting) {
269         return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
270     }
271 
272     /**
273      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
274      */
275     @Nullable
generateActivityInfo(AndroidPackage pkg, ParsedActivity a, @PackageManager.ComponentInfoFlagsBits long flags, @NonNull PackageUserStateInternal state, @Nullable ApplicationInfo applicationInfo, @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting)276     private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
277             @PackageManager.ComponentInfoFlagsBits long flags,
278             @NonNull PackageUserStateInternal state, @Nullable ApplicationInfo applicationInfo,
279             @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting) {
280         if (a == null) return null;
281         if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
282             return null;
283         }
284         if (applicationInfo == null) {
285             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
286         }
287 
288         if (applicationInfo == null) {
289             return null;
290         }
291 
292         final ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(
293                 a, flags, applicationInfo);
294         assignSharedFieldsForComponentInfo(info, a, pkgSetting, userId);
295         return info;
296     }
297 
298     /**
299      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
300      */
301     @Nullable
generateServiceInfo(AndroidPackage pkg, ParsedService s, @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state, @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting)302     public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
303             @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state,
304             @UserIdInt int userId, @Nullable PackageStateInternal pkgSetting) {
305         return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
306     }
307 
308     /**
309      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
310      */
311     @Nullable
generateServiceInfo(AndroidPackage pkg, ParsedService s, @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state, @Nullable ApplicationInfo applicationInfo, int userId, @Nullable PackageStateInternal pkgSetting)312     private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
313             @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state,
314             @Nullable ApplicationInfo applicationInfo, int userId,
315             @Nullable PackageStateInternal pkgSetting) {
316         if (s == null) return null;
317         if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
318             return null;
319         }
320         if (applicationInfo == null) {
321             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
322         }
323         if (applicationInfo == null) {
324             return null;
325         }
326 
327         final ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(
328                 s, flags, applicationInfo);
329         assignSharedFieldsForComponentInfo(info, s, pkgSetting, userId);
330         return info;
331     }
332 
333     /**
334      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
335      */
336     @Nullable
generateProviderInfo(AndroidPackage pkg, ParsedProvider p, @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state, @NonNull ApplicationInfo applicationInfo, int userId, @Nullable PackageStateInternal pkgSetting)337     public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
338             @PackageManager.ComponentInfoFlagsBits long flags, PackageUserStateInternal state,
339             @NonNull ApplicationInfo applicationInfo, int userId,
340             @Nullable PackageStateInternal pkgSetting) {
341         if (p == null) return null;
342         if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
343             return null;
344         }
345         if (applicationInfo == null || !pkg.getPackageName().equals(applicationInfo.packageName)) {
346             Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName()
347                     + " actual=" + (applicationInfo == null ? "(null AppInfo)"
348                     : applicationInfo.packageName));
349             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
350         }
351         if (applicationInfo == null) {
352             return null;
353         }
354         ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfoUnchecked(p, flags,
355                 applicationInfo);
356         assignSharedFieldsForComponentInfo(info, p, pkgSetting, userId);
357         return info;
358     }
359 
360     /**
361      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
362      */
363     @Nullable
generateInstrumentationInfo(ParsedInstrumentation i, AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId, @Nullable PackageStateInternal pkgSetting)364     public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
365             AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId,
366             @Nullable PackageStateInternal pkgSetting) {
367         if (i == null) return null;
368 
369         InstrumentationInfo info =
370                 PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId,
371                         false /* assignUserFields */);
372 
373         initForUser(info, pkg, userId);
374 
375         if (info == null) {
376             return null;
377         }
378 
379         info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
380         info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting);
381         info.nativeLibraryDir = pkg.getNativeLibraryDir();
382         info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
383 
384         assignStateFieldsForPackageItemInfo(info, i, pkgSetting, userId);
385 
386         return info;
387     }
388 
389     // TODO(b/135203078): Determine if permission methods need to pass in a non-null
390     //  PackageStateInternal os that checkUseInstalledOrHidden filter can apply
391     @Nullable
generatePermissionInfo(ParsedPermission p, @PackageManager.ComponentInfoFlagsBits long flags)392     public static PermissionInfo generatePermissionInfo(ParsedPermission p,
393             @PackageManager.ComponentInfoFlagsBits long flags) {
394         // TODO(b/135203078): Remove null checks and make all usages @NonNull
395         if (p == null) return null;
396 
397         // For now, permissions don't have state-adjustable fields; return directly
398         return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags);
399     }
400 
401     @Nullable
generatePermissionGroupInfo(ParsedPermissionGroup pg, @PackageManager.ComponentInfoFlagsBits long flags)402     public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
403             @PackageManager.ComponentInfoFlagsBits long flags) {
404         if (pg == null) return null;
405 
406         // For now, permissions don't have state-adjustable fields; return directly
407         return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags);
408     }
409 
410     @Nullable
generateProcessInfo( Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlagsBits long flags)411     public static ArrayMap<String, ProcessInfo> generateProcessInfo(
412             Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlagsBits long flags) {
413         if (procs == null) {
414             return null;
415         }
416 
417         final int numProcs = procs.size();
418         ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
419         for (String key : procs.keySet()) {
420             ParsedProcess proc = procs.get(key);
421             retProcs.put(proc.getName(),
422                     new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()),
423                             proc.getGwpAsanMode(), proc.getMemtagMode(),
424                             proc.getNativeHeapZeroInitialized()));
425         }
426         return retProcs;
427     }
428 
429     /**
430      * Returns true if the package is installed and not hidden, or if the caller explicitly wanted
431      * all uninstalled and hidden packages as well.
432      */
checkUseInstalledOrHidden(AndroidPackage pkg, PackageStateInternal pkgSetting, PackageUserStateInternal state, @PackageManager.PackageInfoFlagsBits long flags)433     public static boolean checkUseInstalledOrHidden(AndroidPackage pkg,
434             PackageStateInternal pkgSetting, PackageUserStateInternal state,
435             @PackageManager.PackageInfoFlagsBits long flags) {
436         // Returns false if the package is hidden system app until installed.
437         if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
438                 && !state.isInstalled()
439                 && pkgSetting != null
440                 && pkgSetting.getTransientState().isHiddenUntilInstalled()) {
441             return false;
442         }
443 
444         // If available for the target user, or trying to match uninstalled packages and it's
445         // a system app.
446         return PackageUserStateUtils.isAvailable(state, flags)
447                 || (pkg.isSystem()
448                 && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
449                 || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
450     }
451 
assignSharedFieldsForComponentInfo(@onNull ComponentInfo componentInfo, @NonNull ParsedMainComponent mainComponent, @Nullable PackageStateInternal pkgSetting, int userId)452     private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
453             @NonNull ParsedMainComponent mainComponent, @Nullable PackageStateInternal pkgSetting,
454             int userId) {
455         assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting, userId);
456         componentInfo.descriptionRes = mainComponent.getDescriptionRes();
457         componentInfo.directBootAware = mainComponent.isDirectBootAware();
458         componentInfo.enabled = mainComponent.isEnabled();
459         componentInfo.splitName = mainComponent.getSplitName();
460         componentInfo.attributionTags = mainComponent.getAttributionTags();
461     }
462 
assignStateFieldsForPackageItemInfo( @onNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component, @Nullable PackageStateInternal pkgSetting, int userId)463     private static void assignStateFieldsForPackageItemInfo(
464             @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
465             @Nullable PackageStateInternal pkgSetting, int userId) {
466         Pair<CharSequence, Integer> labelAndIcon =
467                 ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting,
468                         userId);
469         packageItemInfo.nonLocalizedLabel = labelAndIcon.first;
470         packageItemInfo.icon = labelAndIcon.second;
471     }
472 
473     @CheckResult
flag(boolean hasFlag, int flag)474     private static int flag(boolean hasFlag, int flag) {
475         return hasFlag ? flag : 0;
476     }
477 
478     /**
479      * @see ApplicationInfo#flags
480      */
appInfoFlags(AndroidPackage pkg, @Nullable PackageStateInternal pkgSetting)481     public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageStateInternal pkgSetting) {
482         // @formatter:off
483         int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoFlags(pkg)
484                 | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
485                 | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
486 
487         return appInfoFlags(pkgWithoutStateFlags, pkgSetting);
488         // @formatter:on
489     }
490 
491     /** @see ApplicationInfo#flags */
appInfoFlags(int pkgWithoutStateFlags, @NonNull PackageStateInternal pkgSetting)492     public static int appInfoFlags(int pkgWithoutStateFlags,
493             @NonNull PackageStateInternal pkgSetting) {
494         // @formatter:off
495         int flags = pkgWithoutStateFlags;
496         if (pkgSetting != null) {
497             flags |= flag(pkgSetting.getTransientState().isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
498         }
499         return flags;
500         // @formatter:on
501     }
502 
503     /** @see ApplicationInfo#privateFlags */
appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageStateInternal pkgSetting)504     public static int appInfoPrivateFlags(AndroidPackage pkg,
505             @Nullable PackageStateInternal pkgSetting) {
506         // @formatter:off
507         int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg)
508                 | flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
509                 | flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
510                 | flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM)
511                 | flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR)
512                 | flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
513                 | flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM)
514                 | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
515         return appInfoPrivateFlags(pkgWithoutStateFlags, pkgSetting);
516         // @formatter:on
517     }
518 
519     /** @see ApplicationInfo#privateFlags */
appInfoPrivateFlags(int pkgWithoutStateFlags, @Nullable PackageStateInternal pkgSetting)520     public static int appInfoPrivateFlags(int pkgWithoutStateFlags,
521             @Nullable PackageStateInternal pkgSetting) {
522         // @formatter:off
523         // TODO: Add state specific flags
524         return pkgWithoutStateFlags;
525         // @formatter:on
526     }
527 
528     /** @see ApplicationInfo#privateFlagsExt */
appInfoPrivateFlagsExt(AndroidPackage pkg, @Nullable PackageStateInternal pkgSetting)529     public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
530                                              @Nullable PackageStateInternal pkgSetting) {
531         // @formatter:off
532         int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlagsExt(pkg);
533         return appInfoPrivateFlagsExt(pkgWithoutStateFlags, pkgSetting);
534         // @formatter:on
535     }
536 
537     /** @see ApplicationInfo#privateFlagsExt */
appInfoPrivateFlagsExt(int pkgWithoutStateFlags, @Nullable PackageStateInternal pkgSetting)538     public static int appInfoPrivateFlagsExt(int pkgWithoutStateFlags,
539                                              @Nullable PackageStateInternal pkgSetting) {
540         // @formatter:off
541         // TODO: Add state specific flags
542         return pkgWithoutStateFlags;
543         // @formatter:on
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         if ("android".equals(packageName)) {
553             output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH;
554             return;
555         }
556 
557         // For performance reasons, all these paths are built as strings
558         if (userId == UserHandle.USER_SYSTEM) {
559             output.credentialProtectedDataDir =
560                     pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName;
561             output.deviceProtectedDataDir =
562                     pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName;
563         } else {
564             // Convert /data/user/0/ -> /data/user/1/com.example.app
565             String userIdString = String.valueOf(userId);
566             int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length();
567             output.credentialProtectedDataDir =
568                     new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser())
569                             .replace(credentialLength - 2, credentialLength - 1, userIdString)
570                             .append(packageName)
571                             .toString();
572             int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length();
573             output.deviceProtectedDataDir =
574                     new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser())
575                             .replace(deviceLength - 2, deviceLength - 1, userIdString)
576                             .append(packageName)
577                             .toString();
578         }
579 
580         if (input.isDefaultToDeviceProtectedStorage()
581                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
582             output.dataDir = output.deviceProtectedDataDir;
583         } else {
584             output.dataDir = output.credentialProtectedDataDir;
585         }
586     }
587 
588     // This duplicates the ApplicationInfo variant because it uses field assignment and the classes
589     // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead.
initForUser(InstrumentationInfo output, AndroidPackage input, @UserIdInt int userId)590     private static void initForUser(InstrumentationInfo output, AndroidPackage input,
591             @UserIdInt int userId) {
592         PackageImpl pkg = ((PackageImpl) input);
593         String packageName = input.getPackageName();
594         if ("android".equals(packageName)) {
595             output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH;
596             return;
597         }
598 
599         // For performance reasons, all these paths are built as strings
600         if (userId == UserHandle.USER_SYSTEM) {
601             output.credentialProtectedDataDir =
602                     pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName;
603             output.deviceProtectedDataDir =
604                     pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName;
605         } else {
606             // Convert /data/user/0/ -> /data/user/1/com.example.app
607             String userIdString = String.valueOf(userId);
608             int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length();
609             output.credentialProtectedDataDir =
610                     new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser())
611                             .replace(credentialLength - 2, credentialLength - 1, userIdString)
612                             .append(packageName)
613                             .toString();
614             int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length();
615             output.deviceProtectedDataDir =
616                     new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser())
617                             .replace(deviceLength - 2, deviceLength - 1, userIdString)
618                             .append(packageName)
619                             .toString();
620         }
621 
622         if (input.isDefaultToDeviceProtectedStorage()
623                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
624             output.dataDir = output.deviceProtectedDataDir;
625         } else {
626             output.dataDir = output.credentialProtectedDataDir;
627         }
628     }
629 
630     /**
631      * Wraps {@link PackageInfoUtils#generateApplicationInfo} with a cache.
632      */
633     public static class CachedApplicationInfoGenerator {
634         // Map from a package name to the corresponding app info.
635         private ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>();
636 
637         /**
638          * {@link PackageInfoUtils#generateApplicationInfo} with a cache.
639          */
640         @Nullable
generate(AndroidPackage pkg, @PackageManager.ApplicationInfoFlagsBits long flags, PackageUserStateInternal state, int userId, @Nullable PackageStateInternal pkgSetting)641         public ApplicationInfo generate(AndroidPackage pkg,
642                 @PackageManager.ApplicationInfoFlagsBits long flags, PackageUserStateInternal state,
643                 int userId, @Nullable PackageStateInternal pkgSetting) {
644             ApplicationInfo appInfo = mCache.get(pkg.getPackageName());
645             if (appInfo != null) {
646                 return appInfo;
647             }
648             appInfo = PackageInfoUtils.generateApplicationInfo(
649                     pkg, flags, state, userId, pkgSetting);
650             mCache.put(pkg.getPackageName(), appInfo);
651             return appInfo;
652         }
653     }
654 }
655