/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.tare; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; import android.content.Context; import android.content.Intent; import android.content.PermissionChecker; import android.content.pm.ApplicationInfo; import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.RemoteException; import com.android.internal.util.ArrayUtils; /** POJO to cache only the information about installed packages that TARE cares about. */ class InstalledPackageInfo { static final int NO_UID = -1; /** * Flags to use when querying for front door activities. Disabled components are included * are included for completeness since the app can enable them at any time. */ private static final int HEADLESS_APP_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DISABLED_COMPONENTS; public final int uid; public final String packageName; public final boolean hasCode; /** * Whether the app is a system app that is "headless." Headless in this context means that * the app doesn't have any "front door" activities --- activities that would show in the * launcher. */ public final boolean isHeadlessSystemApp; public final boolean isSystemInstaller; @Nullable public final String installerPackageName; InstalledPackageInfo(@NonNull Context context, @UserIdInt int userId, @NonNull PackageInfo packageInfo) { final ApplicationInfo applicationInfo = packageInfo.applicationInfo; uid = applicationInfo == null ? NO_UID : applicationInfo.uid; packageName = packageInfo.packageName; hasCode = applicationInfo != null && applicationInfo.hasCode(); final PackageManager packageManager = context.getPackageManager(); final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(packageName); isHeadlessSystemApp = applicationInfo != null && (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) && ArrayUtils.isEmpty( packageManager.queryIntentActivitiesAsUser( frontDoorActivityIntent, HEADLESS_APP_QUERY_FLAGS, userId)); isSystemInstaller = applicationInfo != null && ArrayUtils.indexOf( packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0 && PackageManager.PERMISSION_GRANTED == PermissionChecker.checkPermissionForPreflight(context, Manifest.permission.INSTALL_PACKAGES, PermissionChecker.PID_UNKNOWN, applicationInfo.uid, packageName); InstallSourceInfo installSourceInfo = null; try { installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName, userId); } catch (RemoteException e) { // Shouldn't happen. } installerPackageName = installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName(); } @Override public String toString() { return "IPO{" + "uid=" + uid + ", pkgName=" + packageName + (hasCode ? " HAS_CODE" : "") + (isHeadlessSystemApp ? " HEADLESS_SYSTEM" : "") + (isSystemInstaller ? " SYSTEM_INSTALLER" : "") + ", installer=" + installerPackageName + '}'; } }