1 /*
2  * Copyright (C) 2022 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.tare;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.app.AppGlobals;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.PermissionChecker;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.InstallSourceInfo;
29 import android.content.pm.PackageInfo;
30 import android.content.pm.PackageManager;
31 import android.os.RemoteException;
32 
33 import com.android.internal.util.ArrayUtils;
34 
35 /** POJO to cache only the information about installed packages that TARE cares about. */
36 class InstalledPackageInfo {
37     static final int NO_UID = -1;
38 
39     /**
40      * Flags to use when querying for front door activities. Disabled components are included
41      * are included for completeness since the app can enable them at any time.
42      */
43     private static final int HEADLESS_APP_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE
44             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
45             | PackageManager.MATCH_DISABLED_COMPONENTS;
46 
47     public final int uid;
48     public final String packageName;
49     public final boolean hasCode;
50     /**
51      * Whether the app is a system app that is "headless." Headless in this context means that
52      * the app doesn't have any "front door" activities --- activities that would show in the
53      * launcher.
54      */
55     public final boolean isHeadlessSystemApp;
56     public final boolean isSystemInstaller;
57     @Nullable
58     public final String installerPackageName;
59 
InstalledPackageInfo(@onNull Context context, @UserIdInt int userId, @NonNull PackageInfo packageInfo)60     InstalledPackageInfo(@NonNull Context context, @UserIdInt int userId,
61             @NonNull PackageInfo packageInfo) {
62         final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
63         uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
64         packageName = packageInfo.packageName;
65         hasCode = applicationInfo != null && applicationInfo.hasCode();
66 
67         final PackageManager packageManager = context.getPackageManager();
68         final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
69                 .addCategory(Intent.CATEGORY_LAUNCHER)
70                 .setPackage(packageName);
71         isHeadlessSystemApp = applicationInfo != null
72                 && (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp())
73                 && ArrayUtils.isEmpty(
74                         packageManager.queryIntentActivitiesAsUser(
75                                 frontDoorActivityIntent, HEADLESS_APP_QUERY_FLAGS, userId));
76 
77         isSystemInstaller = applicationInfo != null
78                 && ArrayUtils.indexOf(
79                 packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0
80                 && PackageManager.PERMISSION_GRANTED
81                 == PermissionChecker.checkPermissionForPreflight(context,
82                 Manifest.permission.INSTALL_PACKAGES, PermissionChecker.PID_UNKNOWN,
83                 applicationInfo.uid, packageName);
84         InstallSourceInfo installSourceInfo = null;
85         try {
86             installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName,
87                     userId);
88         } catch (RemoteException e) {
89             // Shouldn't happen.
90         }
91         installerPackageName =
92                 installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
93     }
94 
95     @Override
toString()96     public String toString() {
97         return "IPO{"
98                 + "uid=" + uid
99                 + ", pkgName=" + packageName
100                 + (hasCode ? " HAS_CODE" : "")
101                 + (isHeadlessSystemApp ? " HEADLESS_SYSTEM" : "")
102                 + (isSystemInstaller ? " SYSTEM_INSTALLER" : "")
103                 + ", installer=" + installerPackageName
104                 + '}';
105     }
106 }
107