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