Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
src.com.android.server.pm.PackageManagerService Maven / Gradle / Ivy
Go to download
A library jar that provides APIs for Applications written for the Google Android Platform.
/*
* Copyright (C) 2006 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.pm;
import static android.Manifest.permission.DELETE_PACKAGES;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_VERSION_CODE;
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_APEX;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageManager.TYPE_ACTIVITY;
import static android.content.pm.PackageManager.TYPE_PROVIDER;
import static android.content.pm.PackageManager.TYPE_RECEIVER;
import static android.content.pm.PackageManager.TYPE_SERVICE;
import static android.content.pm.PackageManager.TYPE_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import android.Manifest;
import android.annotation.AppIdInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.PermissionChecker;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.ChangedPackages;
import android.content.pm.Checksum;
import android.content.pm.ComponentInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ComponentType;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.ModuleInfoFlags;
import android.content.pm.PackageManager.Property;
import android.content.pm.PackageManager.PropertyLocation;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.PackagePartitions;
import android.content.pm.PackagePartitions.SystemPartition;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingPackageUtils.ParseFlags;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SELinux;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
import android.os.incremental.PerUidReadTimeouts;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.permission.PermissionManager;
import android.provider.ContactsContract;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
import android.stats.storage.StorageEnums;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.LogPrinter;
import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.PackageUtils;
import android.util.Pair;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimingsTraceLog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.apk.ApkSignatureVerifier;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.AttributeCache;
import com.android.internal.security.VerityUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.DomainVerificationUtils;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedLongSparseArray;
import com.android.server.utils.WatchedSparseBooleanArray;
import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
import com.android.server.wm.ActivityTaskManagerInternal;
import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
import libcore.util.HexEncoding;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
*
* Internally there are three important locks:
*
* {@link #mLock} is used to guard all in-memory parsed package details
* and other related state. It is a fine-grained lock that should only be held
* momentarily, as it's one of the most contended locks in the system.
* {@link #mInstallLock} is used to guard all {@code installd} access, whose
* operations typically involve heavy lifting of application data on disk. Since
* {@code installd} is single-threaded, and it's operations can often be slow,
* this lock should never be acquired while already holding {@link #mLock}.
* Conversely, it's safe to acquire {@link #mLock} momentarily while already
* holding {@link #mInstallLock}.
* {@link #mSnapshotLock} is used to guard access to two snapshot fields: the snapshot
* itself and the snapshot invalidation flag. This lock should never be acquired while
* already holding {@link #mLock}. Conversely, it's safe to acquire {@link #mLock}
* momentarily while already holding {@link #mSnapshotLock}.
*
* Many internal methods rely on the caller to hold the appropriate locks, and
* this contract is expressed through method name suffixes:
*
* fooLI(): the caller must hold {@link #mInstallLock}
* fooLIF(): the caller must hold {@link #mInstallLock} and the package
* being modified must be frozen
* fooLPr(): the caller must hold {@link #mLock} for reading
* fooLPw(): the caller must hold {@link #mLock} for writing
*
* {@link #mSnapshotLock} is taken in exactly one place - {@code snapshotComputer()}. It
* should not be taken anywhere else or used for any other purpose.
*
* Because this class is very central to the platform's security; please run all
* CTS and unit tests whenever making modifications:
*
*
* $ runtest -c android.content.pm.PackageManagerTests frameworks-core
* $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
*
*/
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender, TestUtilityService {
static final String TAG = "PackageManager";
public static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
private static final boolean DEBUG_BACKUP = false;
public static final boolean DEBUG_INSTALL = false;
public static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_BROADCASTS = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
public static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
public static final boolean TRACE_SNAPSHOTS = false;
private static final boolean DEBUG_PER_UID_READ_TIMEOUTS = false;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
// user, but by default initialize to this.
public static final boolean DEBUG_DEXOPT = false;
static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
private static final boolean HIDE_EPHEMERAL_APIS = false;
private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
private static final int SE_UID = Process.SE_UID;
private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID;
private static final int UWB_UID = Process.UWB_UID;
static final int SCAN_NO_DEX = 1 << 0;
static final int SCAN_UPDATE_SIGNATURE = 1 << 1;
static final int SCAN_NEW_INSTALL = 1 << 2;
static final int SCAN_UPDATE_TIME = 1 << 3;
static final int SCAN_BOOTING = 1 << 4;
static final int SCAN_REQUIRE_KNOWN = 1 << 7;
static final int SCAN_MOVE = 1 << 8;
static final int SCAN_INITIAL = 1 << 9;
static final int SCAN_DONT_KILL_APP = 1 << 10;
static final int SCAN_IGNORE_FROZEN = 1 << 11;
static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
static final int SCAN_AS_INSTANT_APP = 1 << 13;
static final int SCAN_AS_FULL_APP = 1 << 14;
static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
static final int SCAN_AS_SYSTEM = 1 << 16;
static final int SCAN_AS_PRIVILEGED = 1 << 17;
static final int SCAN_AS_OEM = 1 << 18;
static final int SCAN_AS_VENDOR = 1 << 19;
static final int SCAN_AS_PRODUCT = 1 << 20;
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
SCAN_UPDATE_SIGNATURE,
SCAN_NEW_INSTALL,
SCAN_UPDATE_TIME,
SCAN_BOOTING,
SCAN_REQUIRE_KNOWN,
SCAN_MOVE,
SCAN_INITIAL,
SCAN_DONT_KILL_APP,
SCAN_IGNORE_FROZEN,
SCAN_FIRST_BOOT_OR_UPGRADE,
SCAN_AS_INSTANT_APP,
SCAN_AS_FULL_APP,
SCAN_AS_VIRTUAL_PRELOAD,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScanFlags {}
/**
* Used as the result code of the {@link #getPackageStartability}.
*/
@IntDef(value = {
PACKAGE_STARTABILITY_OK,
PACKAGE_STARTABILITY_NOT_FOUND,
PACKAGE_STARTABILITY_NOT_SYSTEM,
PACKAGE_STARTABILITY_FROZEN,
PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageStartability {}
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is allowed to start.
*/
static final int PACKAGE_STARTABILITY_OK = 0;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is not allowed to start because it's not found
* (could be due to that package is invisible to the given user).
*/
static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is not allowed to start because it's not a system app
* and the system is running in safe mode.
*/
static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is not allowed to start because it's currently frozen.
*/
static final int PACKAGE_STARTABILITY_FROZEN = 3;
/**
* Used as the result code of the {@link #getPackageStartability} to indicate
* the given package is not allowed to start because it doesn't support
* direct boot.
*/
static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
public final static String STUB_SUFFIX = "-Stub";
private static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* Timeout (in milliseconds) after which the watchdog should declare that
* our handler thread is wedged. The usual default for such things is one
* minute but we sometimes do very lengthy I/O operations on this thread,
* such as installing multi-gigabyte applications, so ours needs to be longer.
*/
static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes
/**
* Wall-clock timeout (in milliseconds) after which we *require* that an fstrim
* be run on this device. We use the value in the Settings.Global.MANDATORY_FSTRIM_INTERVAL
* settings entry if available, otherwise we use the hardcoded default. If it's been
* more than this long since the last fstrim, we force one during the boot sequence.
*
* This backstops other fstrim scheduling: if the device is alive at midnight+idle,
* one gets run at the next available charging+idle time. This final mandatory
* no-fstrim check kicks in only of the other scheduling criteria is never met.
*/
private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS;
/**
* Whether verification is enabled by default.
*/
private static final boolean DEFAULT_VERIFY_ENABLE = true;
/**
* Whether integrity verification is enabled by default.
*/
private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
/**
* The default maximum time to wait for the verification agent to return in
* milliseconds.
*/
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
* The default maximum time to wait for the integrity verification to return in
* milliseconds.
*/
private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
/**
* Timeout duration in milliseconds for enabling package rollback. If we fail to enable
* rollback within that period, the install will proceed without rollback enabled.
*
* If flag value is negative, the default value will be assigned.
*
* Flag type: {@code long}
* Namespace: NAMESPACE_ROLLBACK
*/
private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
/**
* The default duration to wait for rollback to be enabled in
* milliseconds.
*/
private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
/**
* Default IncFs timeouts. Maximum values in IncFs is 1hr.
*
*
If flag value is empty, the default value will be assigned.
*
* Flag type: {@code String}
* Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
*/
private static final String PROPERTY_INCFS_DEFAULT_TIMEOUTS = "incfs_default_timeouts";
/**
* Known digesters with optional timeouts.
*
* Flag type: {@code String}
* Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
*/
private static final String PROPERTY_KNOWN_DIGESTERS_LIST = "known_digesters_list";
/**
* The default response for package verification timeout.
*
* This can be either PackageManager.VERIFICATION_ALLOW or
* PackageManager.VERIFICATION_REJECT.
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
/**
* Adding an installer package name to a package that does not have one set requires the
* INSTALL_PACKAGES permission.
*
* If the caller targets R, this will throw a SecurityException. Otherwise the request will
* fail silently. In both cases, and regardless of whether this change is enabled, the
* installer package will remain unchanged.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
150857253;
/**
* Apps targeting Android S and above need to declare dependencies to the public native
* shared libraries that are defined by the device maker using {@code uses-native-library} tag
* in its {@code AndroidManifest.xml}.
*
* If any of the dependencies cannot be satisfied, i.e. one of the dependency doesn't exist,
* the package manager rejects to install the app. The dependency can be specified as optional
* using {@code android:required} attribute in the tag, in which case failing to satisfy the
* dependency doesn't stop the installation.
*
Once installed, an app is provided with only the native shared libraries that are
* specified in the app manifest. {@code dlopen}ing a native shared library that doesn't appear
* in the app manifest will fail even if it actually exists on the device.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088;
public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String PACKAGE_SCHEME = "package";
private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager";
// Compilation reasons.
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT_AFTER_OTA = 1;
public static final int REASON_POST_BOOT = 2;
public static final int REASON_INSTALL = 3;
public static final int REASON_INSTALL_FAST = 4;
public static final int REASON_INSTALL_BULK = 5;
public static final int REASON_INSTALL_BULK_SECONDARY = 6;
public static final int REASON_INSTALL_BULK_DOWNGRADED = 7;
public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 8;
public static final int REASON_BACKGROUND_DEXOPT = 9;
public static final int REASON_AB_OTA = 10;
public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11;
public static final int REASON_CMDLINE = 12;
public static final int REASON_SHARED = 13;
public static final int REASON_LAST = REASON_SHARED;
/**
* The initial enabled state of the cache before other checks are done.
*/
private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
/**
* Whether to skip all other checks and force the cache to be enabled.
*
* Setting this to true will cause the cache to be named "debug" to avoid eviction from
* build fingerprint changes.
*/
private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
/**
* Permissions required in order to receive instant application lifecycle broadcasts.
*/
private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS };
private static final String RANDOM_DIR_PREFIX = "~~";
final Handler mHandler;
private final ProcessLoggingHandler mProcessLoggingHandler;
private final boolean mEnableFreeCacheV2;
final int mSdkVersion;
final Context mContext;
final boolean mFactoryTest;
final boolean mOnlyCore;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
final boolean mIsUpgrade;
final boolean mIsPreNUpgrade;
final boolean mIsPreNMR1Upgrade;
final boolean mIsPreQUpgrade;
@GuardedBy("mLock")
private boolean mDexOptDialogShown;
// Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
// LOCK HELD. Can be called with mInstallLock held.
@GuardedBy("mInstallLock")
final Installer mInstaller;
/** Directory where installed applications are stored */
private final File mAppInstallDir;
/** Directory where installed application's 32-bit native libraries are copied. */
@VisibleForTesting
final File mAppLib32InstallDir;
private static File getAppLib32InstallDir() {
return new File(Environment.getDataDirectory(), "app-lib");
}
// ----------------------------------------------------------------
// Lock for state used when installing and doing other long running
// operations. Methods that must be called with this lock held have
// the suffix "LI".
final Object mInstallLock;
// ----------------------------------------------------------------
// Lock for global state used when modifying package state or settings.
// Methods that must be called with this lock held have
// the suffix "Locked". Some methods may use the legacy suffix "LP"
final PackageManagerTracedLock mLock;
// Keys are String (package name), values are Package.
@Watched
@GuardedBy("mLock")
final WatchedArrayMap mPackages = new WatchedArrayMap<>();
private final SnapshotCache> mPackagesSnapshot =
new SnapshotCache.Auto(mPackages, mPackages, "PackageManagerService.mPackages");
// Keys are isolated uids and values are the uid of the application
// that created the isolated process.
@Watched
@GuardedBy("mLock")
final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
private final SnapshotCache mIsolatedOwnersSnapshot =
new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners,
"PackageManagerService.mIsolatedOwners");
/**
* Tracks new system packages [received in an OTA] that we expect to
* find updated user-installed versions. Keys are package name, values
* are package location.
*/
final private ArrayMap mExpectingBetter = new ArrayMap<>();
/**
* Tracks existing packages prior to receiving an OTA. Keys are package name.
* Only non-null during an OTA, and even then it is nulled again once systemReady().
*/
private @Nullable ArraySet mExistingPackages = null;
/**
* List of code paths that need to be released when the system becomes ready.
*
* NOTE: We have to delay releasing cblocks for no other reason than we cannot
* retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. When
* we no longer need to read that setting, cblock release can occur in the
* constructor.
*
* @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL
* @see #systemReady()
*/
private @Nullable List mReleaseOnSystemReady;
/**
* Whether or not system app permissions should be promoted from install to runtime.
*/
boolean mPromoteSystemApps;
private final PackageManagerInternal mPmInternal;
private final TestUtilityService mTestUtilityService;
@Watched
@GuardedBy("mLock")
final Settings mSettings;
/**
* Set of package names that are currently "frozen", which means active
* surgery is being done on the code/data for that package. The platform
* will refuse to launch frozen packages to avoid race conditions.
*
* @see PackageFreezer
*/
@GuardedBy("mLock")
final ArraySet mFrozenPackages = new ArraySet<>();
final ProtectedPackages mProtectedPackages;
@GuardedBy("mLoadedVolumes")
final ArraySet mLoadedVolumes = new ArraySet<>();
boolean mFirstBoot;
private final boolean mIsEngBuild;
private final boolean mIsUserDebugBuild;
private final String mIncrementalVersion;
PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
@GuardedBy("mAvailableFeatures")
final ArrayMap mAvailableFeatures;
@Watched
private final InstantAppRegistry mInstantAppRegistry;
@GuardedBy("mLock")
int mChangedPackagesSequenceNumber;
/**
* List of changed [installed, removed or updated] packages.
* mapping from user id -> sequence number -> package name
*/
@GuardedBy("mLock")
final SparseArray> mChangedPackages = new SparseArray<>();
/**
* The sequence number of the last change to a package.
* mapping from user id -> package name -> sequence number
*/
@GuardedBy("mLock")
final SparseArray> mChangedPackagesSequenceNumbers = new SparseArray<>();
@GuardedBy("mLock")
final private ArraySet mPackageListObservers = new ArraySet<>();
@GuardedBy("mLock")
private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
private final ModuleInfoProvider mModuleInfoProvider;
private final ApexManager mApexManager;
private final Injector mInjector;
private final SystemWrapper mSystemWrapper;
/**
* The list of all system partitions that may contain packages in ascending order of
* specificity (the more generic, the earlier in the list a partition appears).
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static final List SYSTEM_PARTITIONS = Collections.unmodifiableList(
PackagePartitions.getOrderedPartitions(ScanPartition::new));
private final List mDirsToScanAsSystem;
private final OverlayConfig mOverlayConfig;
@GuardedBy("itself")
final private ArrayList mPackageChangeObservers =
new ArrayList<>();
// Cached parsed flag value. Invalidated on each flag change.
private PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {};
/**
* Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
*
* NOTE: All getters should return the same instance for every call.
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Injector {
@VisibleForTesting(visibility = Visibility.PRIVATE)
interface Producer {
/** Produce an instance of type {@link T} */
T produce(Injector injector, PackageManagerService packageManager);
}
interface ProducerWithArgument {
T produce(Injector injector, PackageManagerService packageManager, R argument);
}
interface ServiceProducer {
T produce(Class c);
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
static class Singleton {
private final Producer mProducer;
private volatile T mInstance = null;
Singleton(Producer producer) {
this.mProducer = producer;
}
T get(Injector injector, PackageManagerService packageManagerService) {
if (mInstance == null) {
mInstance = mProducer.produce(injector, packageManagerService);
}
return mInstance;
}
}
private PackageManagerService mPackageManager;
private final PackageAbiHelper mAbiHelper;
private final Context mContext;
private final PackageManagerTracedLock mLock;
private final Installer mInstaller;
private final Object mInstallLock;
private final Handler mBackgroundHandler;
private final Executor mBackgroundExecutor;
private final List mSystemPartitions;
// ----- producers -----
private final Singleton mComponentResolverProducer;
private final Singleton mPermissionManagerServiceProducer;
private final Singleton mUserManagerProducer;
private final Singleton mSettingsProducer;
private final Singleton mAppsFilterProducer;
private final Singleton mPlatformCompatProducer;
private final Singleton mSystemConfigProducer;
private final Singleton mPackageDexOptimizerProducer;
private final Singleton mDexManagerProducer;
private final Singleton mArtManagerServiceProducer;
private final Singleton mApexManagerProducer;
private final Singleton mViewCompilerProducer;
private final Singleton mIncrementalManagerProducer;
private final Singleton mDefaultAppProviderProducer;
private final Singleton mDisplayMetricsProducer;
private final Producer mScanningCachingPackageParserProducer;
private final Producer mScanningPackageParserProducer;
private final Producer mPreparingPackageParserProducer;
private final Singleton mPackageInstallerServiceProducer;
private final ProducerWithArgument
mInstantAppResolverConnectionProducer;
private final Singleton
mLegacyPermissionManagerInternalProducer;
private final SystemWrapper mSystemWrapper;
private final ServiceProducer mGetLocalServiceProducer;
private final ServiceProducer mGetSystemServiceProducer;
private final Singleton mModuleInfoProviderProducer;
private final Singleton
mDomainVerificationManagerInternalProducer;
private final Singleton mHandlerProducer;
Injector(Context context, PackageManagerTracedLock lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
Handler backgroundHandler,
List systemPartitions,
Producer componentResolverProducer,
Producer permissionManagerServiceProducer,
Producer userManagerProducer,
Producer settingsProducer,
Producer appsFilterProducer,
Producer platformCompatProducer,
Producer systemConfigProducer,
Producer packageDexOptimizerProducer,
Producer dexManagerProducer,
Producer artManagerServiceProducer,
Producer apexManagerProducer,
Producer viewCompilerProducer,
Producer incrementalManagerProducer,
Producer defaultAppProviderProducer,
Producer displayMetricsProducer,
Producer scanningCachingPackageParserProducer,
Producer scanningPackageParserProducer,
Producer preparingPackageParserProducer,
Producer packageInstallerServiceProducer,
ProducerWithArgument
instantAppResolverConnectionProducer,
Producer moduleInfoProviderProducer,
Producer legacyPermissionManagerInternalProducer,
Producer
domainVerificationManagerInternalProducer,
Producer handlerProducer,
SystemWrapper systemWrapper,
ServiceProducer getLocalServiceProducer,
ServiceProducer getSystemServiceProducer) {
mContext = context;
mLock = lock;
mInstaller = installer;
mAbiHelper = abiHelper;
mInstallLock = installLock;
mBackgroundHandler = backgroundHandler;
mBackgroundExecutor = new HandlerExecutor(backgroundHandler);
mSystemPartitions = systemPartitions;
mComponentResolverProducer = new Singleton<>(componentResolverProducer);
mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer);
mUserManagerProducer = new Singleton<>(userManagerProducer);
mSettingsProducer = new Singleton<>(settingsProducer);
mAppsFilterProducer = new Singleton<>(appsFilterProducer);
mPlatformCompatProducer = new Singleton<>(platformCompatProducer);
mSystemConfigProducer = new Singleton<>(systemConfigProducer);
mPackageDexOptimizerProducer = new Singleton<>(packageDexOptimizerProducer);
mDexManagerProducer = new Singleton<>(dexManagerProducer);
mArtManagerServiceProducer = new Singleton<>(artManagerServiceProducer);
mApexManagerProducer = new Singleton<>(apexManagerProducer);
mViewCompilerProducer = new Singleton<>(viewCompilerProducer);
mIncrementalManagerProducer = new Singleton<>(incrementalManagerProducer);
mDefaultAppProviderProducer = new Singleton<>(defaultAppProviderProducer);
mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer);
mScanningCachingPackageParserProducer = scanningCachingPackageParserProducer;
mScanningPackageParserProducer = scanningPackageParserProducer;
mPreparingPackageParserProducer = preparingPackageParserProducer;
mPackageInstallerServiceProducer = new Singleton<>(packageInstallerServiceProducer);
mInstantAppResolverConnectionProducer = instantAppResolverConnectionProducer;
mModuleInfoProviderProducer = new Singleton<>(moduleInfoProviderProducer);
mLegacyPermissionManagerInternalProducer = new Singleton<>(
legacyPermissionManagerInternalProducer);
mSystemWrapper = systemWrapper;
mGetLocalServiceProducer = getLocalServiceProducer;
mGetSystemServiceProducer = getSystemServiceProducer;
mDomainVerificationManagerInternalProducer =
new Singleton<>(domainVerificationManagerInternalProducer);
mHandlerProducer = new Singleton<>(handlerProducer);
}
/**
* Bootstraps this injector with the {@link PackageManagerService instance to which it
* belongs.
*/
public void bootstrap(PackageManagerService pm) {
this.mPackageManager = pm;
}
public UserManagerInternal getUserManagerInternal() {
return getUserManagerService().getInternalForInjectorOnly();
}
public PackageAbiHelper getAbiHelper() {
return mAbiHelper;
}
public Object getInstallLock() {
return mInstallLock;
}
public List getSystemPartitions() {
return mSystemPartitions;
}
public UserManagerService getUserManagerService() {
return mUserManagerProducer.get(this, mPackageManager);
}
public PackageManagerTracedLock getLock() {
return mLock;
}
public Installer getInstaller() {
return mInstaller;
}
public ComponentResolver getComponentResolver() {
return mComponentResolverProducer.get(this, mPackageManager);
}
public PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
return mPermissionManagerServiceProducer.get(this, mPackageManager);
}
public Context getContext() {
return mContext;
}
public Settings getSettings() {
return mSettingsProducer.get(this, mPackageManager);
}
public AppsFilter getAppsFilter() {
return mAppsFilterProducer.get(this, mPackageManager);
}
public PlatformCompat getCompatibility() {
return mPlatformCompatProducer.get(this, mPackageManager);
}
public SystemConfig getSystemConfig() {
return mSystemConfigProducer.get(this, mPackageManager);
}
public PackageDexOptimizer getPackageDexOptimizer() {
return mPackageDexOptimizerProducer.get(this, mPackageManager);
}
public DexManager getDexManager() {
return mDexManagerProducer.get(this, mPackageManager);
}
public ArtManagerService getArtManagerService() {
return mArtManagerServiceProducer.get(this, mPackageManager);
}
public ApexManager getApexManager() {
return mApexManagerProducer.get(this, mPackageManager);
}
public ViewCompiler getViewCompiler() {
return mViewCompilerProducer.get(this, mPackageManager);
}
public Handler getBackgroundHandler() {
return mBackgroundHandler;
}
public Executor getBackgroundExecutor() {
return mBackgroundExecutor;
}
public DisplayMetrics getDisplayMetrics() {
return mDisplayMetricsProducer.get(this, mPackageManager);
}
public T getLocalService(Class c) {
return mGetLocalServiceProducer.produce(c);
}
public T getSystemService(Class c) {
return mGetSystemServiceProducer.produce(c);
}
public SystemWrapper getSystemWrapper() {
return mSystemWrapper;
}
public IncrementalManager getIncrementalManager() {
return mIncrementalManagerProducer.get(this, mPackageManager);
}
public DefaultAppProvider getDefaultAppProvider() {
return mDefaultAppProviderProducer.get(this, mPackageManager);
}
public PackageParser2 getScanningCachingPackageParser() {
return mScanningCachingPackageParserProducer.produce(this, mPackageManager);
}
public PackageParser2 getScanningPackageParser() {
return mScanningPackageParserProducer.produce(this, mPackageManager);
}
public PackageParser2 getPreparingPackageParser() {
return mPreparingPackageParserProducer.produce(this, mPackageManager);
}
public PackageInstallerService getPackageInstallerService() {
return mPackageInstallerServiceProducer.get(this, mPackageManager);
}
public InstantAppResolverConnection getInstantAppResolverConnection(
ComponentName instantAppResolverComponent) {
return mInstantAppResolverConnectionProducer.produce(
this, mPackageManager, instantAppResolverComponent);
}
public ModuleInfoProvider getModuleInfoProvider() {
return mModuleInfoProviderProducer.get(this, mPackageManager);
}
public LegacyPermissionManagerInternal getLegacyPermissionManagerInternal() {
return mLegacyPermissionManagerInternalProducer.get(this, mPackageManager);
}
public DomainVerificationManagerInternal getDomainVerificationManagerInternal() {
return mDomainVerificationManagerInternalProducer.get(this, mPackageManager);
}
public Handler getHandler() {
return mHandlerProducer.get(this, mPackageManager);
}
}
/** Provides an abstraction to static access to system state. */
public interface SystemWrapper {
void disablePackageCaches();
void enablePackageCaches();
}
private static class DefaultSystemWrapper implements SystemWrapper {
@Override
public void disablePackageCaches() {
// disable all package caches that shouldn't apply within system server
PackageManager.disableApplicationInfoCache();
PackageManager.disablePackageInfoCache();
ApplicationPackageManager.invalidateGetPackagesForUidCache();
ApplicationPackageManager.disableGetPackagesForUidCache();
ApplicationPackageManager.invalidateHasSystemFeatureCache();
// Avoid invalidation-thrashing by preventing cache invalidations from causing property
// writes if the cache isn't enabled yet. We re-enable writes later when we're
// done initializing.
sSnapshotCorked.incrementAndGet();
PackageManager.corkPackageInfoCache();
}
@Override
public void enablePackageCaches() {
// Uncork cache invalidations and allow clients to cache package information.
int corking = sSnapshotCorked.decrementAndGet();
if (TRACE_SNAPSHOTS && corking == 0) {
Log.i(TAG, "snapshot: corking returns to 0");
}
PackageManager.uncorkPackageInfoCache();
}
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class TestParams {
public ApexManager apexManager;
public @Nullable String appPredictionServicePackage;
public ArtManagerService artManagerService;
public @Nullable String configuratorPackage;
public int defParseFlags;
public DefaultAppProvider defaultAppProvider;
public DexManager dexManager;
public List dirsToScanAsSystem;
public @Nullable String documenterPackage;
public boolean factoryTest;
public ArrayMap availableFeatures;
public Handler handler;
public @Nullable String incidentReportApproverPackage;
public IncrementalManager incrementalManager;
public PackageInstallerService installerService;
public InstantAppRegistry instantAppRegistry;
public InstantAppResolverConnection instantAppResolverConnection;
public ComponentName instantAppResolverSettingsComponent;
public boolean isPreNmr1Upgrade;
public boolean isPreNupgrade;
public boolean isPreQupgrade;
public boolean isUpgrade;
public LegacyPermissionManagerInternal legacyPermissionManagerInternal;
public DisplayMetrics Metrics;
public ModuleInfoProvider moduleInfoProvider;
public MoveCallbacks moveCallbacks;
public boolean onlyCore;
public OverlayConfig overlayConfig;
public PackageDexOptimizer packageDexOptimizer;
public PackageParser2.Callback packageParserCallback;
public PendingPackageBroadcasts pendingPackageBroadcasts;
public PackageManagerInternal pmInternal;
public TestUtilityService testUtilityService;
public ProcessLoggingHandler processLoggingHandler;
public ProtectedPackages protectedPackages;
public @NonNull String requiredInstallerPackage;
public @NonNull String requiredPermissionControllerPackage;
public @NonNull String requiredUninstallerPackage;
public @Nullable String requiredVerifierPackage;
public String[] separateProcesses;
public @NonNull String servicesExtensionPackageName;
public @Nullable String setupWizardPackage;
public @NonNull String sharedSystemSharedLibraryPackageName;
public @Nullable String storageManagerPackage;
public @Nullable String defaultTextClassifierPackage;
public @Nullable String systemTextClassifierPackage;
public @Nullable String overlayConfigSignaturePackage;
public ViewCompiler viewCompiler;
public @Nullable String retailDemoPackage;
public @Nullable String recentsPackage;
public ComponentName resolveComponentName;
public ArrayMap packages;
public boolean enableFreeCacheV2;
public int sdkVersion;
public SystemWrapper systemWrapper;
public File appInstallDir;
public File appLib32InstallDir;
public boolean isEngBuild;
public boolean isUserDebugBuild;
public int sdkInt = Build.VERSION.SDK_INT;
public String incrementalVersion = Build.VERSION.INCREMENTAL;
}
@Watched
private final AppsFilter mAppsFilter;
final PackageParser2.Callback mPackageParserCallback;
// Currently known shared libraries.
@Watched
final WatchedArrayMap>
mSharedLibraries = new WatchedArrayMap<>();
private final SnapshotCache>>
mSharedLibrariesSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
@Watched
final WatchedArrayMap>
mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
private final SnapshotCache>>
mStaticLibsByDeclaringPackageSnapshot =
new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
"PackageManagerService.mStaticLibsByDeclaringPackage");
// Mapping from instrumentation class names to info about them.
@Watched
final WatchedArrayMap mInstrumentation =
new WatchedArrayMap<>();
private final SnapshotCache>
mInstrumentationSnapshot =
new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation,
"PackageManagerService.mInstrumentation");
// Packages whose data we have transfered into another package, thus
// should no longer exist.
final ArraySet mTransferredPackages = new ArraySet<>();
// Broadcast actions that are only available to the system.
@GuardedBy("mProtectedBroadcasts")
final ArraySet mProtectedBroadcasts = new ArraySet<>();
/** List of packages waiting for verification. */
final SparseArray mPendingVerification = new SparseArray<>();
/** List of packages waiting for rollback to be enabled. */
final SparseArray mPendingEnableRollback = new SparseArray<>();
final PackageInstallerService mInstallerService;
final ArtManagerService mArtManagerService;
final PackageDexOptimizer mPackageDexOptimizer;
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
private final DexManager mDexManager;
private final ViewCompiler mViewCompiler;
private AtomicInteger mNextMoveId = new AtomicInteger();
private final MoveCallbacks mMoveCallbacks;
// Cache of users who need badging.
private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
/** Token for keys in mPendingVerification. */
private int mPendingVerificationToken = 0;
/** Token for keys in mPendingEnableRollback. */
private int mPendingEnableRollbackToken = 0;
@Watched(manual = true)
volatile boolean mSystemReady;
@Watched(manual = true)
private volatile boolean mSafeMode;
volatile boolean mHasSystemUidErrors;
@Watched
private final WatchedSparseBooleanArray mWebInstantAppsDisabled =
new WatchedSparseBooleanArray();
@Watched(manual = true)
private ApplicationInfo mAndroidApplication;
@Watched(manual = true)
final ActivityInfo mResolveActivity = new ActivityInfo();
final ResolveInfo mResolveInfo = new ResolveInfo();
@Watched(manual = true)
private ComponentName mResolveComponentName;
AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
boolean mResolverReplaced = false;
@NonNull
private final DomainVerificationManagerInternal mDomainVerificationManager;
/** The service connection to the ephemeral resolver */
final InstantAppResolverConnection mInstantAppResolverConnection;
/** Component used to show resolver settings for Instant Apps */
final ComponentName mInstantAppResolverSettingsComponent;
/** Activity used to install instant applications */
@Watched(manual = true)
private ActivityInfo mInstantAppInstallerActivity;
@Watched(manual = true)
private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
private final Map>
mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
// Internal interface for permission manager
private final PermissionManagerServiceInternal mPermissionManager;
@Watched
private final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
private List mKeepUninstalledPackages;
// Cached reference to IDevicePolicyManager.
private IDevicePolicyManager mDevicePolicyManager = null;
private File mCacheDir;
private Future> mPrepareAppDataFuture;
private final IncrementalManager mIncrementalManager;
private final DefaultAppProvider mDefaultAppProvider;
private final LegacyPermissionManagerInternal mLegacyPermissionManager;
private final PackageProperty mPackageProperty = new PackageProperty();
// Set of pending broadcasts for aggregating enable/disable of components.
@VisibleForTesting(visibility = Visibility.PACKAGE)
public static class PendingPackageBroadcasts {
// for each user id, a map of components within that package>
final SparseArray>> mUidMap;
public PendingPackageBroadcasts() {
mUidMap = new SparseArray<>(2);
}
public ArrayList get(int userId, String packageName) {
ArrayMap> packages = getOrAllocate(userId);
return packages.get(packageName);
}
public void put(int userId, String packageName, ArrayList components) {
ArrayMap> packages = getOrAllocate(userId);
packages.put(packageName, components);
}
public void remove(int userId, String packageName) {
ArrayMap> packages = mUidMap.get(userId);
if (packages != null) {
packages.remove(packageName);
}
}
public void remove(int userId) {
mUidMap.remove(userId);
}
public int userIdCount() {
return mUidMap.size();
}
public int userIdAt(int n) {
return mUidMap.keyAt(n);
}
public ArrayMap> packagesForUserId(int userId) {
return mUidMap.get(userId);
}
public int size() {
// total number of pending broadcast entries across all userIds
int num = 0;
for (int i = 0; i< mUidMap.size(); i++) {
num += mUidMap.valueAt(i).size();
}
return num;
}
public void clear() {
mUidMap.clear();
}
private ArrayMap> getOrAllocate(int userId) {
ArrayMap> map = mUidMap.get(userId);
if (map == null) {
map = new ArrayMap<>();
mUidMap.put(userId, map);
}
return map;
}
}
final PendingPackageBroadcasts mPendingBroadcasts;
static final int SEND_PENDING_BROADCAST = 1;
static final int INIT_COPY = 5;
static final int POST_INSTALL = 9;
static final int WRITE_SETTINGS = 13;
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int CHECK_PENDING_VERIFICATION = 16;
// public static final int UNUSED = 17;
// public static final int UNUSED = 18;
static final int WRITE_PACKAGE_LIST = 19;
static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
static final int ENABLE_ROLLBACK_STATUS = 21;
static final int ENABLE_ROLLBACK_TIMEOUT = 22;
static final int DEFERRED_NO_KILL_POST_DELETE = 23;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26;
static final int DOMAIN_VERIFICATION = 27;
static final int SNAPSHOT_UNCORK = 28;
static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
private static final long BROADCAST_DELAY_DURING_STARTUP = 10 * 1000L; // 10 seconds (in millis)
private static final long BROADCAST_DELAY = 1 * 1000L; // 1 second (in millis)
// When the service constructor finished plus a delay (used for broadcast delay computation)
private long mServiceStartWithDelay;
private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
2 * 60 * 60 * 1000L; /* two hours */
final UserManagerService mUserManager;
// Stores a list of users whose package restrictions file needs to be updated
private ArraySet mDirtyUsers = new ArraySet<>();
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
static class PostInstallData {
@Nullable
public final InstallArgs args;
@NonNull
public final PackageInstalledInfo res;
@Nullable
public final Runnable mPostInstallRunnable;
PostInstallData(@Nullable InstallArgs args, @NonNull PackageInstalledInfo res,
@Nullable Runnable postInstallRunnable) {
this.args = args;
this.res = res;
mPostInstallRunnable = postInstallRunnable;
}
}
final SparseArray mRunningInstalls = new SparseArray<>();
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
// XML tags for backup/restore of various bits of state
private static final String TAG_PREFERRED_BACKUP = "pa";
private static final String TAG_DEFAULT_APPS = "da";
private static final String TAG_INTENT_FILTER_VERIFICATION = "iv";
private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup";
private static final String TAG_ALL_GRANTS = "rt-grants";
private static final String TAG_GRANT = "grant";
private static final String ATTR_PACKAGE_NAME = "pkg";
private static final String TAG_PERMISSION = "perm";
private static final String ATTR_PERMISSION_NAME = "name";
private static final String ATTR_IS_GRANTED = "g";
private static final String ATTR_USER_SET = "set";
private static final String ATTR_USER_FIXED = "fixed";
private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
// System/policy permission grants are not backed up
private static final int SYSTEM_RUNTIME_GRANT_MASK =
FLAG_PERMISSION_POLICY_FIXED
| FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_GRANTED_BY_DEFAULT;
// And we back up these user-adjusted states
private static final int USER_RUNTIME_GRANT_MASK =
FLAG_PERMISSION_USER_SET
| FLAG_PERMISSION_USER_FIXED
| FLAG_PERMISSION_REVOKED_COMPAT;
final @Nullable String mRequiredVerifierPackage;
final @NonNull String mRequiredInstallerPackage;
final @NonNull String mRequiredUninstallerPackage;
final @NonNull String mRequiredPermissionControllerPackage;
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mDefaultTextClassifierPackage;
final @Nullable String mSystemTextClassifierPackageName;
final @Nullable String mDocumenterPackage;
final @Nullable String mConfiguratorPackage;
final @Nullable String mAppPredictionServicePackage;
final @Nullable String mIncidentReportApproverPackage;
final @Nullable String mServicesExtensionPackageName;
final @Nullable String mSharedSystemSharedLibraryPackageName;
final @Nullable String mRetailDemoPackage;
final @Nullable String mOverlayConfigSignaturePackage;
final @Nullable String mRecentsPackage;
@GuardedBy("mLock")
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
private final DomainVerificationConnection mDomainVerificationConnection =
new DomainVerificationConnection();
private class DomainVerificationConnection implements DomainVerificationService.Connection,
DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
@Override
public void scheduleWriteSettings() {
synchronized (mLock) {
PackageManagerService.this.scheduleWriteSettingsLocked();
}
}
@Override
public int getCallingUid() {
return Binder.getCallingUid();
}
@UserIdInt
@Override
public int getCallingUserId() {
return UserHandle.getCallingUserId();
}
@Override
public void schedule(int code, @Nullable Object object) {
Message message = mHandler.obtainMessage(DOMAIN_VERIFICATION);
message.arg1 = code;
message.obj = object;
mHandler.sendMessage(message);
}
@Override
public long getPowerSaveTempWhitelistAppDuration() {
return PackageManagerService.this.getVerificationTimeout();
}
@Override
public DeviceIdleInternal getDeviceIdleInternal() {
return mInjector.getLocalService(DeviceIdleInternal.class);
}
@Override
public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
final int callingUserId = UserHandle.getUserId(callingUid);
return callingUid == getPackageUid(packageName, 0, callingUserId);
}
@Nullable
@Override
public AndroidPackage getPackage(@NonNull String packageName) {
return PackageManagerService.this.getPackage(packageName);
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
return mPmInternal.filterAppAccess(packageName, callingUid, userId);
}
@Override
public int[] getAllUserIds() {
return mUserManager.getUserIds();
}
@Override
public boolean doesUserExist(@UserIdInt int userId) {
return mUserManager.exists(userId);
}
@Override
public void withPackageSettingsSnapshot(
@NonNull Consumer> block) {
mPmInternal.withPackageSettingsSnapshot(block);
}
@Override
public Output withPackageSettingsSnapshotReturning(
@NonNull FunctionalUtils.ThrowingFunction, Output>
block) {
return mPmInternal.withPackageSettingsSnapshotReturning(block);
}
@Override
public void withPackageSettingsSnapshotThrowing(
@NonNull FunctionalUtils.ThrowingCheckedConsumer,
ExceptionType> block) throws ExceptionType {
mPmInternal.withPackageSettingsSnapshotThrowing(block);
}
@Override
public void
withPackageSettingsSnapshotThrowing2(
@NonNull FunctionalUtils.ThrowingChecked2Consumer<
Function, ExceptionOne, ExceptionTwo> block)
throws ExceptionOne, ExceptionTwo {
mPmInternal.withPackageSettingsSnapshotThrowing2(block);
}
@Override
public Output
withPackageSettingsSnapshotReturningThrowing(
@NonNull FunctionalUtils.ThrowingCheckedFunction<
Function, Output, ExceptionType> block)
throws ExceptionType {
return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block);
}
}
/**
* Invalidate the package info cache, which includes updating the cached computer.
* @hide
*/
public static void invalidatePackageInfoCache() {
PackageManager.invalidatePackageInfoCache();
onChanged();
}
private final Watcher mWatcher = new Watcher() {
@Override
public void onChange(@Nullable Watchable what) {
PackageManagerService.this.onChange(what);
}
};
/**
* A Snapshot is a subset of PackageManagerService state. A snapshot is either live
* or snapped. Live snapshots directly reference PackageManagerService attributes.
* Snapped snapshots contain deep copies of the attributes.
*/
private class Snapshot {
public static final int LIVE = 1;
public static final int SNAPPED = 2;
public final Settings settings;
public final WatchedSparseIntArray isolatedOwners;
public final WatchedArrayMap packages;
public final WatchedArrayMap> sharedLibs;
public final WatchedArrayMap> staticLibs;
public final WatchedArrayMap instrumentation;
public final WatchedSparseBooleanArray webInstantAppsDisabled;
public final ComponentName resolveComponentName;
public final ActivityInfo resolveActivity;
public final ActivityInfo instantAppInstallerActivity;
public final ResolveInfo instantAppInstallerInfo;
public final InstantAppRegistry instantAppRegistry;
public final ApplicationInfo androidApplication;
public final String appPredictionServicePackage;
public final AppsFilter appsFilter;
public final ComponentResolver componentResolver;
public final PackageManagerService service;
Snapshot(int type) {
if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot();
isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
packages = mPackagesSnapshot.snapshot();
sharedLibs = mSharedLibrariesSnapshot.snapshot();
staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
instrumentation = mInstrumentationSnapshot.snapshot();
resolveComponentName = mResolveComponentName.clone();
resolveActivity = new ActivityInfo(mResolveActivity);
instantAppInstallerActivity =
(mInstantAppInstallerActivity == null)
? null
: new ActivityInfo(mInstantAppInstallerActivity);
instantAppInstallerInfo = new ResolveInfo(mInstantAppInstallerInfo);
webInstantAppsDisabled = mWebInstantAppsDisabled.snapshot();
instantAppRegistry = mInstantAppRegistry.snapshot();
androidApplication =
(mAndroidApplication == null)
? null
: new ApplicationInfo(mAndroidApplication);
appPredictionServicePackage = mAppPredictionServicePackage;
appsFilter = mAppsFilter.snapshot();
componentResolver = mComponentResolver.snapshot();
} else if (type == Snapshot.LIVE) {
settings = mSettings;
isolatedOwners = mIsolatedOwners;
packages = mPackages;
sharedLibs = mSharedLibraries;
staticLibs = mStaticLibsByDeclaringPackage;
instrumentation = mInstrumentation;
resolveComponentName = mResolveComponentName;
resolveActivity = mResolveActivity;
instantAppInstallerActivity = mInstantAppInstallerActivity;
instantAppInstallerInfo = mInstantAppInstallerInfo;
webInstantAppsDisabled = mWebInstantAppsDisabled;
instantAppRegistry = mInstantAppRegistry;
androidApplication = mAndroidApplication;
appPredictionServicePackage = mAppPredictionServicePackage;
appsFilter = mAppsFilter;
componentResolver = mComponentResolver;
} else {
throw new IllegalArgumentException();
}
service = PackageManagerService.this;
}
}
/**
* A {@link Computer} provides a set of functions that can operate on live data or snapshot
* data. At this time, the {@link Computer} is implemented by the
* {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}.
*
* New functions must be added carefully.
*
* New functions must be true functions with respect to data collected in a
* {@link Snapshot}. Such data may never be modified from inside a {@link Computer}
* function.
*
*
* A new function must be implemented in {@link ComputerEngine}.
*
*
* A new function must be overridden in {@link ComputerLocked} if the function
* cannot safely access live data without holding the PackageManagerService lock. The
* form of the {@link ComputerLocked} function must be a single call to the
* {@link ComputerEngine} implementation, wrapped in a synchronized
* block. Functions in {@link ComputerLocked} should never include any other code.
*
*
* Care must be taken when deciding if a function should be overridden in
* {@link ComputerLocked}. The complex lock relationships of PackageManagerService
* and other managers (like PermissionManager) mean deadlock is possible. On the
* other hand, not overriding in {@link ComputerLocked} may leave a function walking
* unstable data.
*
* To coax developers to consider such issues carefully, all methods in
* {@link Computer} must be annotated with @LiveImplementation(override =
* MANDATORY)
or LiveImplementation(locked = NOT_ALLOWED)
. A unit
* test verifies the annotation and that the annotation corresponds to the code in
* {@link ComputerEngine} and {@link ComputerLocked}.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected interface Computer {
/**
* Every method must be annotated.
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface LiveImplementation {
// A Computer method must be annotated with one of the following values:
// MANDATORY - the method must be overridden in ComputerEngineLive. The
// format of the override is a call to the super method, wrapped in a
// synchronization block.
// NOT_ALLOWED - the method may not appear in the live computer. It must
// be final in the ComputerEngine.
int MANDATORY = 1;
int NOT_ALLOWED = 2;
int override() default MANDATORY;
String rationale() default "";
}
/**
* Administrative statistics: record that the snapshot has been used. Every call
* to use() increments the usage counter.
*/
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
default void use() {
}
/**
* Fetch the snapshot usage counter.
* @return The number of times this snapshot was used.
*/
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
default int getUsed() {
return 0;
}
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType,
int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid,
int userId, boolean resolveForStart, boolean allowDynamicSplits);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType,
int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
@NonNull List queryIntentServicesInternal(Intent intent, String resolvedType,
int flags, int userId, int callingUid, boolean includeInstantApps);
@LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfo(ComponentName component, int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId);
@LiveImplementation(override = LiveImplementation.MANDATORY)
AndroidPackage getPackage(String packageName);
@LiveImplementation(override = LiveImplementation.MANDATORY)
AndroidPackage getPackage(int uid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ComponentName getDefaultHomeActivity(int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
int flags, int sourceUserId, int parentUserId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
Intent getHomeIntent();
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
List getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
List applyPostResolutionFilter(@NonNull List resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfo(String packageName, int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags,
int filterCallingUid, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
PackageSetting getPackageSetting(String packageName);
@LiveImplementation(override = LiveImplementation.MANDATORY)
PackageSetting getPackageSettingInternal(String packageName, int callingUid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ParceledListSlice getInstalledPackages(int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ServiceInfo getServiceInfo(ComponentName component, int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version);
@LiveImplementation(override = LiveImplementation.MANDATORY)
String getInstantAppPackageName(int callingUid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String resolveExternalPackageNameLPr(AndroidPackage pkg);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String resolveInternalPackageNameLPr(String packageName, long versionCode);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
String[] getPackagesForUid(int uid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
UserInfo getProfileParent(int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean canViewInstantApps(int callingUid, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isCallerSameApp(String packageName, int uid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@ComponentType int type);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
String resolvedType, int flags);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isInstantApp(String packageName, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int checkUidPermission(String permName, int uid);
@LiveImplementation(override = LiveImplementation.MANDATORY)
int getPackageUidInternal(String packageName, int flags, int userId, int callingUid);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForApplication(int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForComponent(int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForPackage(int flags, int userId);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
boolean isImplicitImageCaptureIntentAndNotSetByDpc);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
@LiveImplementation(override = LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(@NonNull String packageName);
@LiveImplementation(override = LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(int uid);
@LiveImplementation(override = LiveImplementation.MANDATORY)
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
@LiveImplementation(override = LiveImplementation.MANDATORY)
boolean filterAppAccess(String packageName, int callingUid, int userId);
@LiveImplementation(override = LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
String resolvedType, int flags, List query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
@LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
List query, boolean debug, int userId);
}
/**
* This class contains the implementation of the Computer functions. It
* is entirely self-contained - it has no implicit access to
* PackageManagerService.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected static class ComputerEngine implements Computer {
// The administrative use counter.
private int mUsed = 0;
// Cached attributes. The names in this class are the same as the
// names in PackageManagerService; see that class for documentation.
protected final Settings mSettings;
private final WatchedSparseIntArray mIsolatedOwners;
private final WatchedArrayMap mPackages;
private final WatchedArrayMap
mInstrumentation;
private final WatchedArrayMap>
mStaticLibsByDeclaringPackage;
private final WatchedArrayMap>
mSharedLibraries;
private final ComponentName mLocalResolveComponentName;
private final ActivityInfo mResolveActivity;
private final WatchedSparseBooleanArray mWebInstantAppsDisabled;
private final ActivityInfo mLocalInstantAppInstallerActivity;
private final ResolveInfo mInstantAppInstallerInfo;
private final InstantAppRegistry mInstantAppRegistry;
private final ApplicationInfo mLocalAndroidApplication;
private final AppsFilter mAppsFilter;
// Immutable service attribute
private final String mAppPredictionServicePackage;
// The following are not cloned since changes to these have never
// been guarded by the PMS lock.
private final Context mContext;
private final UserManagerService mUserManager;
private final PermissionManagerServiceInternal mPermissionManager;
private final ApexManager mApexManager;
private final Injector mInjector;
private final ComponentResolver mComponentResolver;
private final InstantAppResolverConnection mInstantAppResolverConnection;
private final DefaultAppProvider mDefaultAppProvider;
private final DomainVerificationManagerInternal mDomainVerificationManager;
private final PackageDexOptimizer mPackageDexOptimizer;
private final DexManager mDexManager;
private final CompilerStats mCompilerStats;
// PackageManagerService attributes that are primitives are referenced through the
// pms object directly. Primitives are the only attributes so referenced.
protected final PackageManagerService mService;
private boolean safeMode() {
return mService.mSafeMode;
}
protected ComponentName resolveComponentName() {
return mLocalResolveComponentName;
}
protected ActivityInfo instantAppInstallerActivity() {
return mLocalInstantAppInstallerActivity;
}
protected ApplicationInfo androidApplication() {
return mLocalAndroidApplication;
}
ComputerEngine(Snapshot args) {
mSettings = args.settings;
mIsolatedOwners = args.isolatedOwners;
mPackages = args.packages;
mSharedLibraries = args.sharedLibs;
mStaticLibsByDeclaringPackage = args.staticLibs;
mInstrumentation = args.instrumentation;
mWebInstantAppsDisabled = args.webInstantAppsDisabled;
mLocalResolveComponentName = args.resolveComponentName;
mResolveActivity = args.resolveActivity;
mLocalInstantAppInstallerActivity = args.instantAppInstallerActivity;
mInstantAppInstallerInfo = args.instantAppInstallerInfo;
mInstantAppRegistry = args.instantAppRegistry;
mLocalAndroidApplication = args.androidApplication;
mAppsFilter = args.appsFilter;
mComponentResolver = args.componentResolver;
mAppPredictionServicePackage = args.appPredictionServicePackage;
// The following are not cached copies. Instead they are
// references to outside services.
mPermissionManager = args.service.mPermissionManager;
mUserManager = args.service.mUserManager;
mContext = args.service.mContext;
mInjector = args.service.mInjector;
mApexManager = args.service.mApexManager;
mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
mDefaultAppProvider = args.service.mDefaultAppProvider;
mDomainVerificationManager = args.service.mDomainVerificationManager;
mPackageDexOptimizer = args.service.mPackageDexOptimizer;
mDexManager = args.service.mDexManager;
mCompilerStats = args.service.mCompilerStats;
// Used to reference PMS attributes that are primitives and which are not
// updated under control of the PMS lock.
mService = args.service;
}
/**
* Record that the snapshot was used.
*/
public final void use() {
mUsed++;
}
/**
* Return the usage counter.
*/
public final int getUsed() {
return mUsed;
}
public final @NonNull List queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart,
boolean allowDynamicSplits) {
if (!mUserManager.exists(userId)) return Collections.emptyList();
final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
final String pkgName = intent.getPackage();
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
flags));
if (comp != null) {
final List list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
// When specifying an explicit component, we prevent the activity from being
// used when either 1) the calling package is normal and the activity is within
// an ephemeral application or 2) the calling package is ephemeral and the
// activity is not visible to ephemeral applications.
final boolean matchInstantApp =
(flags & PackageManager.MATCH_INSTANT) != 0;
final boolean matchVisibleToInstantAppOnly =
(flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
final boolean matchExplicitlyVisibleOnly =
(flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
final boolean isCallerInstantApp =
instantAppPkgName != null;
final boolean isTargetSameInstantApp =
comp.getPackageName().equals(instantAppPkgName);
final boolean isTargetInstantApp =
(ai.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
final boolean isTargetVisibleToInstantApp =
(ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
final boolean isTargetExplicitlyVisibleToInstantApp =
isTargetVisibleToInstantApp
&& (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
== 0;
final boolean isTargetHiddenFromInstantApp =
!isTargetVisibleToInstantApp
|| (matchExplicitlyVisibleOnly
&& !isTargetExplicitlyVisibleToInstantApp);
final boolean blockInstantResolution =
!isTargetSameInstantApp
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
|| (matchVisibleToInstantAppOnly && isCallerInstantApp
&& isTargetHiddenFromInstantApp));
final boolean blockNormalResolution =
!resolveForStart && !isTargetInstantApp && !isCallerInstantApp
&& shouldFilterApplicationLocked(
getPackageSettingInternal(ai.applicationInfo.packageName,
Process.SYSTEM_UID), filterCallingUid, userId);
if (!blockInstantResolution && !blockNormalResolution) {
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
}
List result = applyPostResolutionFilter(
list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
resolveForStart,
userId, intent);
return result;
}
QueryIntentActivitiesResult lockedResult =
queryIntentActivitiesInternalBody(
intent, resolvedType, flags, filterCallingUid, userId, resolveForStart,
allowDynamicSplits, pkgName, instantAppPkgName);
if (lockedResult.answer != null) {
return lockedResult.answer;
}
if (lockedResult.addInstant) {
String callingPkgName = getInstantAppPackageName(filterCallingUid);
boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
lockedResult.result = maybeAddInstantAppInstaller(lockedResult.result, intent,
resolvedType, flags, userId, resolveForStart, isRequesterInstantApp);
}
if (lockedResult.sortResult) {
Collections.sort(lockedResult.result, RESOLVE_PRIORITY_SORTER);
}
return applyPostResolutionFilter(
lockedResult.result, instantAppPkgName, allowDynamicSplits, filterCallingUid,
resolveForStart, userId, intent);
}
public final @NonNull List queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
return queryIntentActivitiesInternal(
intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(),
userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
}
public final @NonNull List queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
if (!mUserManager.exists(userId)) return Collections.emptyList();
enforceCrossUserOrProfilePermission(callingUid,
userId,
false /*requireFullPermission*/,
false /*checkShell*/,
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
if (comp != null) {
final List list = new ArrayList<>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
// When specifying an explicit component, we prevent the service from being
// used when either 1) the service is in an instant application and the
// caller is not the same instant application or 2) the calling package is
// ephemeral and the activity is not visible to ephemeral applications.
final boolean matchInstantApp =
(flags & PackageManager.MATCH_INSTANT) != 0;
final boolean matchVisibleToInstantAppOnly =
(flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
final boolean isCallerInstantApp =
instantAppPkgName != null;
final boolean isTargetSameInstantApp =
comp.getPackageName().equals(instantAppPkgName);
final boolean isTargetInstantApp =
(si.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
final boolean isTargetHiddenFromInstantApp =
(si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0;
final boolean blockInstantResolution =
!isTargetSameInstantApp
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
|| (matchVisibleToInstantAppOnly && isCallerInstantApp
&& isTargetHiddenFromInstantApp));
final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp
&& shouldFilterApplicationLocked(
getPackageSettingInternal(si.applicationInfo.packageName,
Process.SYSTEM_UID), callingUid, userId);
if (!blockInstantResolution && !blockNormalResolution) {
final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
}
}
return list;
}
return queryIntentServicesInternalBody(intent, resolvedType, flags,
userId, callingUid, instantAppPkgName);
}
protected @NonNull List queryIntentServicesInternalBody(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
String instantAppPkgName) {
// reader
String pkgName = intent.getPackage();
if (pkgName == null) {
final List resolveInfos = mComponentResolver.queryServices(intent,
resolvedType, flags, userId);
if (resolveInfos == null) {
return Collections.emptyList();
}
return applyPostServiceResolutionFilter(
resolveInfos, instantAppPkgName, userId, callingUid);
}
final AndroidPackage pkg = mPackages.get(pkgName);
if (pkg != null) {
final List resolveInfos = mComponentResolver.queryServices(intent,
resolvedType, flags, pkg.getServices(),
userId);
if (resolveInfos == null) {
return Collections.emptyList();
}
return applyPostServiceResolutionFilter(
resolveInfos, instantAppPkgName, userId, callingUid);
}
return Collections.emptyList();
}
public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName) {
// reader
boolean sortResult = false;
boolean addInstant = false;
List result = null;
if (pkgName == null) {
List matchingFilters =
getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
// Check for results that need to skip the current profile.
ResolveInfo skipProfileInfo = querySkipCurrentProfileIntents(matchingFilters,
intent, resolvedType, flags, userId);
if (skipProfileInfo != null) {
List xpResult = new ArrayList<>(1);
xpResult.add(skipProfileInfo);
return new QueryIntentActivitiesResult(
applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId,
intent));
}
// Check for results in the current profile.
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
intent, resolvedType, flags, userId), userId);
addInstant = isInstantAppResolutionAllowed(intent, result, userId,
false /*skipPackageCheck*/, flags);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
CrossProfileDomainInfo specificXpInfo = queryCrossProfileIntents(
matchingFilters, intent, resolvedType, flags, userId,
hasNonNegativePriorityResult);
if (intent.hasWebURI()) {
CrossProfileDomainInfo generalXpInfo = null;
final UserInfo parent = getProfileParent(userId);
if (parent != null) {
generalXpInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
flags, userId, parent.id);
}
// Generalized cross profile intents take precedence over specific.
// Note that this is the opposite of the intuitive order.
CrossProfileDomainInfo prioritizedXpInfo =
generalXpInfo != null ? generalXpInfo : specificXpInfo;
if (!addInstant) {
if (result.isEmpty() && prioritizedXpInfo != null) {
// No result in current profile, but found candidate in parent user.
// And we are not going to add ephemeral app, so we can return the
// result straight away.
result.add(prioritizedXpInfo.resolveInfo);
return new QueryIntentActivitiesResult(
applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent));
} else if (result.size() <= 1 && prioritizedXpInfo == null) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add ephemeral app, so we can return the result
// without further processing.
return new QueryIntentActivitiesResult(
applyPostResolutionFilter(result, instantAppPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart,
userId, intent));
}
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
result = filterCandidatesWithDomainPreferredActivitiesLPr(
intent, flags, result, prioritizedXpInfo, userId);
sortResult = true;
} else {
// If not web Intent, just add result to candidate set and let ResolverActivity
// figure it out.
if (specificXpInfo != null) {
result.add(specificXpInfo.resolveInfo);
sortResult = true;
}
}
} else {
final PackageSetting setting =
getPackageSettingInternal(pkgName, Process.SYSTEM_UID);
result = null;
if (setting != null && setting.pkg != null && (resolveForStart
|| !shouldFilterApplicationLocked(setting, filterCallingUid, userId))) {
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
intent, resolvedType, flags, setting.pkg.getActivities(), userId),
userId);
}
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId,
true /*skipPackageCheck*/, flags);
if (result == null) {
result = new ArrayList<>();
}
}
}
return new QueryIntentActivitiesResult(sortResult, addInstant, result);
}
/**
* Returns the activity component that can handle install failures.
* By default, the instant application installer handles failures. However, an
* application may want to handle failures on its own. Applications do this by
* creating an activity with an intent filter that handles the action
* {@link Intent#ACTION_INSTALL_FAILURE}.
*/
private @Nullable ComponentName findInstallFailureActivity(
String packageName, int filterCallingUid, int userId) {
final Intent failureActivityIntent = new Intent(Intent.ACTION_INSTALL_FAILURE);
failureActivityIntent.setPackage(packageName);
// IMPORTANT: disallow dynamic splits to avoid an infinite loop
final List result = queryIntentActivitiesInternal(
failureActivityIntent, null /*resolvedType*/, 0 /*flags*/,
0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/,
false /*allowDynamicSplits*/);
final int NR = result.size();
if (NR > 0) {
for (int i = 0; i < NR; i++) {
final ResolveInfo info = result.get(i);
if (info.activityInfo.splitName != null) {
continue;
}
return new ComponentName(packageName, info.activityInfo.name);
}
}
return null;
}
public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out activities
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId);
if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"get activity info");
}
return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
}
protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
int filterCallingUid, int userId) {
ParsedActivity a = mComponentResolver.getActivity(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
return PackageInfoUtils.generateActivityInfo(pkg,
a, flags, ps.readUserState(userId), userId, ps);
}
if (resolveComponentName().equals(component)) {
return PackageParser.generateActivityInfo(
mResolveActivity, flags, new PackageUserState(), userId);
}
return null;
}
public AndroidPackage getPackage(String packageName) {
packageName = resolveInternalPackageNameLPr(
packageName, PackageManager.VERSION_CODE_HIGHEST);
return mPackages.get(packageName);
}
public AndroidPackage getPackage(int uid) {
final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
AndroidPackage pkg = null;
final int numPackages = packageNames == null ? 0 : packageNames.length;
for (int i = 0; pkg == null && i < numPackages; i++) {
pkg = mPackages.get(packageNames[i]);
}
return pkg;
}
public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
int flags, int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
if (ps.pkg == null) {
final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
if (pInfo != null) {
return pInfo.applicationInfo;
}
return null;
}
ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId, ps);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
return ai;
}
return null;
}
public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out applications
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForApplication(flags, userId);
if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"get application info");
}
return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
}
protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
int filterCallingUid, int userId) {
// writer
// Normalize package name to handle renamed packages and static libs
packageName = resolveInternalPackageNameLPr(packageName,
PackageManager.VERSION_CODE_HIGHEST);
AndroidPackage p = mPackages.get(packageName);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getApplicationInfo " + packageName
+ ": " + p);
if (p != null) {
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) return null;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
// Note: isEnabledLP() does not apply here - always return info
ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId, ps);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(p);
}
return ai;
}
if ((flags & PackageManager.MATCH_APEX) != 0) {
// For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo
// returned from getApplicationInfo, but for APEX packages difference shouldn't be
// very big.
// TODO(b/155328545): generate proper application info for APEXes as well.
int apexFlags = ApexManager.MATCH_ACTIVE_PACKAGE;
if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
}
final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags);
if (pi == null) {
return null;
}
return pi.applicationInfo;
}
if ("android".equals(packageName)||"system".equals(packageName)) {
return androidApplication();
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
// Already generates the external package name
return generateApplicationInfoFromSettingsLPw(packageName,
flags, filterCallingUid, userId);
}
return null;
}
protected ArrayList filterCandidatesWithDomainPreferredActivitiesLPrBody(
Intent intent, int matchFlags, List candidates,
CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
final ArrayList result = new ArrayList<>();
final ArrayList matchAllList = new ArrayList<>();
final ArrayList undefinedList = new ArrayList<>();
// Blocking instant apps is usually done in applyPostResolutionFilter, but since
// domain verification can resolve to a single result, which can be an instant app,
// it will then be filtered to an empty list in that method. Instead, do blocking
// here so that instant apps can be ignored for approval filtering and a lower
// priority result chosen instead.
final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
final int count = candidates.size();
// First, try to use approved apps.
for (int n = 0; n < count; n++) {
ResolveInfo info = candidates.get(n);
if (blockInstant && (info.isInstantAppAvailable
|| isInstantApp(info.activityInfo.packageName, userId))) {
continue;
}
// Add to the special match all list (Browser use case)
if (info.handleAllWebDataURI) {
matchAllList.add(info);
} else {
undefinedList.add(info);
}
}
// We'll want to include browser possibilities in a few cases
boolean includeBrowser = false;
if (!DomainVerificationUtils.isDomainVerificationIntent(intent, matchFlags)) {
result.addAll(undefinedList);
// Maybe add one for the other profile.
if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
> DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
result.add(xpDomainInfo.resolveInfo);
}
includeBrowser = true;
} else {
Pair, Integer> infosAndLevel = mDomainVerificationManager
.filterToApprovedApp(intent, undefinedList, userId,
mSettings::getPackageLPr);
List approvedInfos = infosAndLevel.first;
Integer highestApproval = infosAndLevel.second;
// If no apps are approved for the domain, resolve only to browsers
if (approvedInfos.isEmpty()) {
includeBrowser = true;
if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
> DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
result.add(xpDomainInfo.resolveInfo);
}
} else {
result.addAll(approvedInfos);
// If the other profile has an app that's higher approval, add it
if (xpDomainInfo != null
&& xpDomainInfo.highestApprovalLevel > highestApproval) {
result.add(xpDomainInfo.resolveInfo);
}
}
}
if (includeBrowser) {
// Also add browsers (all of them or only the default one)
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.v(TAG, " ...including browsers in candidate set");
}
if ((matchFlags & MATCH_ALL) != 0) {
result.addAll(matchAllList);
} else {
// Browser/generic handling case. If there's a default browser, go straight
// to that (but only if there is no other higher-priority match).
final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(
userId);
int maxMatchPrio = 0;
ResolveInfo defaultBrowserMatch = null;
final int numCandidates = matchAllList.size();
for (int n = 0; n < numCandidates; n++) {
ResolveInfo info = matchAllList.get(n);
// track the highest overall match priority...
if (info.priority > maxMatchPrio) {
maxMatchPrio = info.priority;
}
// ...and the highest-priority default browser match
if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) {
if (defaultBrowserMatch == null
|| (defaultBrowserMatch.priority < info.priority)) {
if (debug) {
Slog.v(TAG, "Considering default browser match " + info);
}
defaultBrowserMatch = info;
}
}
}
if (defaultBrowserMatch != null
&& defaultBrowserMatch.priority >= maxMatchPrio
&& !TextUtils.isEmpty(defaultBrowserPackageName))
{
if (debug) {
Slog.v(TAG, "Default browser match " + defaultBrowserMatch);
}
result.add(defaultBrowserMatch);
} else {
result.addAll(matchAllList);
}
}
// If there is nothing selected, add all candidates
if (result.size() == 0) {
result.addAll(candidates);
}
}
return result;
}
/**
* Report the 'Home' activity which is currently set as "always use this one". If non is set
* then reports the most likely home activity or null if there are more than one.
*/
public final ComponentName getDefaultHomeActivity(int userId) {
List allHomeCandidates = new ArrayList<>();
ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
if (cn != null) {
return cn;
}
// TODO: This should not happen since there should always be a default package set for
// ROLE_HOME in RoleManager. Continue with a warning log for now.
Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
// Find the launcher with the highest priority and return that component if there are no
// other home activity with the same priority.
int lastPriority = Integer.MIN_VALUE;
ComponentName lastComponent = null;
final int size = allHomeCandidates.size();
for (int i = 0; i < size; i++) {
final ResolveInfo ri = allHomeCandidates.get(i);
if (ri.priority > lastPriority) {
lastComponent = ri.activityInfo.getComponentName();
lastPriority = ri.priority;
} else if (ri.priority == lastPriority) {
// Two components found with same priority.
lastComponent = null;
}
}
return lastComponent;
}
public final ComponentName getHomeActivitiesAsUser(List allHomeCandidates,
int userId) {
Intent intent = getHomeIntent();
List resolveInfos = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, userId);
allHomeCandidates.clear();
if (resolveInfos == null) {
return null;
}
allHomeCandidates.addAll(resolveInfos);
String packageName = mDefaultAppProvider.getDefaultHome(userId);
if (packageName == null) {
// Role changes are not and cannot be atomic because its implementation lives inside
// a system app, so when the home role changes, there is a window when the previous
// role holder is removed and the new role holder is granted the preferred activity,
// but hasn't become the role holder yet. However, this case may be easily hit
// because the preferred activity change triggers a broadcast and receivers may try
// to get the default home activity there. So we need to fix it for this time
// window, and an easy workaround is to fallback to the current preferred activity.
final int appId = UserHandle.getAppId(Binder.getCallingUid());
final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
FindPreferredActivityBodyResult result = findPreferredActivityInternal(
intent, null, 0, resolveInfos, true, false, false, userId, filtered);
ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo;
if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
packageName = preferredResolveInfo.activityInfo.packageName;
}
}
if (packageName == null) {
return null;
}
int resolveInfosSize = resolveInfos.size();
for (int i = 0; i < resolveInfosSize; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
if (resolveInfo.activityInfo != null && TextUtils.equals(
resolveInfo.activityInfo.packageName, packageName)) {
return new ComponentName(resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name);
}
}
return null;
}
public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
String resolvedType, int flags, int sourceUserId, int parentUserId) {
if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
sourceUserId)) {
return null;
}
List resultTargetUser = mComponentResolver.queryActivities(intent,
resolvedType, flags, parentUserId);
if (resultTargetUser == null || resultTargetUser.isEmpty()) {
return null;
}
CrossProfileDomainInfo result = null;
int size = resultTargetUser.size();
for (int i = 0; i < size; i++) {
ResolveInfo riTargetUser = resultTargetUser.get(i);
// Intent filter verification is only for filters that specify a host. So don't
//return
// those that handle all web uris.
if (riTargetUser.handleAllWebDataURI) {
continue;
}
String packageName = riTargetUser.activityInfo.packageName;
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
continue;
}
int approvalLevel = mDomainVerificationManager
.approvalLevelForDomain(ps, intent, flags, parentUserId);
if (result == null) {
result = new CrossProfileDomainInfo(createForwardingResolveInfoUnchecked(
new WatchedIntentFilter(), sourceUserId, parentUserId), approvalLevel);
} else {
result.highestApprovalLevel =
Math.max(approvalLevel, result.highestApprovalLevel);
}
}
if (result != null && result.highestApprovalLevel
<= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
return null;
}
return result;
}
public final Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.addCategory(Intent.CATEGORY_DEFAULT);
return intent;
}
public final List getMatchingCrossProfileIntentFilters(
Intent intent, String resolvedType, int userId) {
CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
if (resolver != null) {
return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
}
return null;
}
/**
* Filters out ephemeral activities.
* When resolving for an ephemeral app, only activities that 1) are defined in the
* ephemeral app or 2) marked with {@code visibleToEphemeral} are returned.
*
* @param resolveInfos The pre-filtered list of resolved activities
* @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
* is performed.
* @param intent
* @return A filtered list of resolved activities.
*/
public final List applyPostResolutionFilter(
@NonNull List resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent) {
final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
final ResolveInfo info = resolveInfos.get(i);
// remove locally resolved instant app web results when disabled
if (info.isInstantAppAvailable && blockInstant) {
resolveInfos.remove(i);
continue;
}
// allow activities that are defined in the provided package
if (allowDynamicSplits
&& info.activityInfo != null
&& info.activityInfo.splitName != null
&& !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
info.activityInfo.splitName)) {
if (instantAppInstallerActivity() == null) {
if (DEBUG_INSTALL) {
Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
}
resolveInfos.remove(i);
continue;
}
if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) {
resolveInfos.remove(i);
continue;
}
// requested activity is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
if (DEBUG_INSTALL) {
Slog.v(TAG, "Adding installer to the ResolveInfo list");
}
final ResolveInfo installerInfo = new ResolveInfo(
mInstantAppInstallerInfo);
final ComponentName installFailureActivity = findInstallFailureActivity(
info.activityInfo.packageName, filterCallingUid, userId);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
installFailureActivity,
info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode,
info.activityInfo.splitName);
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// This resolve info may appear in the chooser UI, so let us make it
// look as the one it replaces as far as the user is concerned which
// requires loading the correct label and icon for the resolve info.
installerInfo.resolvePackageName = info.getComponentInfo().packageName;
installerInfo.labelRes = info.resolveLabelResId();
installerInfo.icon = info.resolveIconResId();
installerInfo.isInstantAppAvailable = true;
resolveInfos.set(i, installerInfo);
continue;
}
if (ephemeralPkgName == null) {
// caller is a full app
SettingBase callingSetting =
mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
PackageSetting resolvedSetting =
getPackageSettingInternal(info.activityInfo.packageName, 0);
if (resolveForStart
|| !mAppsFilter.shouldFilterApplication(
filterCallingUid, callingSetting, resolvedSetting, userId)) {
continue;
}
} else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
// caller is same app; don't need to apply any other filtering
continue;
} else if (resolveForStart
&& (intent.isWebIntent()
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0)
&& intent.getPackage() == null
&& intent.getComponent() == null) {
// ephemeral apps can launch other ephemeral apps indirectly
continue;
} else if (((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP)
!= 0)
&& !info.activityInfo.applicationInfo.isInstantApp()) {
// allow activities that have been explicitly exposed to ephemeral apps
continue;
}
resolveInfos.remove(i);
}
return resolveInfos;
}
private List applyPostServiceResolutionFilter(List resolveInfos,
String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) {
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
final ResolveInfo info = resolveInfos.get(i);
if (instantAppPkgName == null) {
SettingBase callingSetting =
mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid));
PackageSetting resolvedSetting =
getPackageSettingInternal(info.serviceInfo.packageName, 0);
if (!mAppsFilter.shouldFilterApplication(
filterCallingUid, callingSetting, resolvedSetting, userId)) {
continue;
}
}
final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp();
// allow services that are defined in the provided package
if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) {
if (info.serviceInfo.splitName != null
&& !ArrayUtils.contains(info.serviceInfo.applicationInfo.splitNames,
info.serviceInfo.splitName)) {
if (instantAppInstallerActivity() == null) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "No installer - not adding it to the ResolveInfo"
+ "list");
}
resolveInfos.remove(i);
continue;
}
// requested service is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
if (DEBUG_INSTANT) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo installerInfo = new ResolveInfo(
mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
null /* installFailureActivity */,
info.serviceInfo.packageName,
info.serviceInfo.applicationInfo.longVersionCode,
info.serviceInfo.splitName);
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// load resources from the correct package
installerInfo.resolvePackageName = info.getComponentInfo().packageName;
resolveInfos.set(i, installerInfo);
}
continue;
}
// allow services that have been explicitly exposed to ephemeral apps
if (!isEphemeralApp
&& ((info.serviceInfo.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP)
!= 0)) {
continue;
}
resolveInfos.remove(i);
}
return resolveInfos;
}
private List filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
int matchFlags, List candidates, CrossProfileDomainInfo xpDomainInfo,
int userId) {
final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " +
candidates.size());
}
final ArrayList result =
filterCandidatesWithDomainPreferredActivitiesLPrBody(
intent, matchFlags, candidates, xpDomainInfo, userId, debug);
if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
+ result.size());
for (ResolveInfo info : result) {
Slog.v(TAG, " + " + info.activityInfo);
}
}
return result;
}
/**
* Filter out activities with systemUserOnly flag set, when current user is not System.
*
* @return filtered list
*/
private List filterIfNotSystemUser(List resolveInfos,
int userId) {
if (userId == UserHandle.USER_SYSTEM) {
return resolveInfos;
}
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
ResolveInfo info = resolveInfos.get(i);
if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
resolveInfos.remove(i);
}
}
return resolveInfos;
}
private List maybeAddInstantAppInstaller(List result,
Intent intent,
String resolvedType, int flags, int userId, boolean resolveForStart,
boolean isRequesterInstantApp) {
// first, check to see if we've got an instant app already installed
final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
ResolveInfo localInstantApp = null;
boolean blockResolution = false;
if (!alreadyResolvedLocally) {
final List instantApps = mComponentResolver.queryActivities(
intent,
resolvedType,
flags
| PackageManager.GET_RESOLVED_FILTER
| PackageManager.MATCH_INSTANT
| PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
userId);
for (int i = instantApps.size() - 1; i >= 0; --i) {
final ResolveInfo info = instantApps.get(i);
final String packageName = info.activityInfo.packageName;
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps.getInstantApp(userId)) {
if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "Instant app approved for intent; pkg: "
+ packageName);
}
localInstantApp = info;
} else {
if (DEBUG_INSTANT) {
Slog.v(TAG, "Instant app not approved for intent; pkg: "
+ packageName);
}
blockResolution = true;
}
break;
}
}
}
// no app installed, let's see if one's available
AuxiliaryResolveInfo auxiliaryResponse = null;
if (!blockResolution) {
if (localInstantApp == null) {
// we don't have an instant app locally, resolve externally
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
String token = UUID.randomUUID().toString();
InstantAppDigest digest = InstantAppResolver.parseDigest(intent);
final InstantAppRequest requestObject =
new InstantAppRequest(null /*responseObj*/,
intent /*origIntent*/, resolvedType, null /*callingPackage*/,
null /*callingFeatureId*/, isRequesterInstantApp, userId,
null /*verificationBundle*/, resolveForStart,
digest.getDigestPrefixSecure(), token);
auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
mInstantAppResolverConnection, requestObject);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
} else {
// we have an instant application locally, but, we can't admit that since
// callers shouldn't be able to determine prior browsing. create a placeholder
// auxiliary response so the downstream code behaves as if there's an
// instant application available externally. when it comes time to start
// the instant application, we'll do the right thing.
final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */,
ai.packageName, ai.longVersionCode,
null /* splitName */);
}
}
if (intent.isWebIntent() && auxiliaryResponse == null) {
return result;
}
final PackageSetting ps =
mSettings.getPackageLPr(instantAppInstallerActivity().packageName);
if (ps == null
|| !ps.readUserState(userId).isEnabled(instantAppInstallerActivity(), 0)) {
return result;
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
instantAppInstallerActivity(), 0, ps.readUserState(userId), userId);
ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
ephemeralInstaller.filter = new IntentFilter();
if (intent.getAction() != null) {
ephemeralInstaller.filter.addAction(intent.getAction());
}
if (intent.getData() != null && intent.getData().getPath() != null) {
ephemeralInstaller.filter.addDataPath(
intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
}
ephemeralInstaller.isInstantAppAvailable = true;
// make sure this resolver is the default
ephemeralInstaller.isDefault = true;
ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
if (DEBUG_INSTANT) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
result.add(ephemeralInstaller);
return result;
}
public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
if (ps == null) {
return null;
}
final int callingUid = Binder.getCallingUid();
// Filter out ephemeral app metadata:
// * The system/shell/root can see metadata for any app
// * An installed app can see metadata for 1) other installed apps
// and 2) ephemeral apps that have explicitly interacted with it
// * Ephemeral apps can only see their own data and exposed installed apps
// * Holding a signature permission allows seeing instant apps
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
}
if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
&& ps.isSystem()) {
flags |= MATCH_ANY_USER;
}
final PackageUserState state = ps.readUserState(userId);
AndroidPackage p = ps.pkg;
if (p != null) {
// Compute GIDs only if requested
final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
: mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
// Compute granted permissions only if package has requested permissions
final Set permissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
|| ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
: mPermissionManager.getGrantedPermissions(ps.name, userId);
PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps);
if (packageInfo == null) {
return null;
}
packageInfo.packageName = packageInfo.applicationInfo.packageName =
resolveExternalPackageNameLPr(p);
return packageInfo;
} else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
PackageInfo pi = new PackageInfo();
pi.packageName = ps.name;
pi.setLongVersionCode(ps.versionCode);
pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
pi.firstInstallTime = ps.firstInstallTime;
pi.lastUpdateTime = ps.lastUpdateTime;
ApplicationInfo ai = new ApplicationInfo();
ai.packageName = ps.name;
ai.uid = UserHandle.getUid(userId, ps.appId);
ai.primaryCpuAbi = ps.primaryCpuAbiString;
ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
ai.setVersionCode(ps.versionCode);
ai.flags = ps.pkgFlags;
ai.privateFlags = ps.pkgPrivateFlags;
pi.applicationInfo =
PackageParser.generateApplicationInfo(ai, flags, state, userId);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["
+ ps.name + "]. Provides a minimum info.");
return pi;
} else {
return null;
}
}
public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
flags, Binder.getCallingUid(), userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out packages
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid,
userId);
}
protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
// reader
// Normalize package name to handle renamed packages and static libs
packageName = resolveInternalPackageNameLPr(packageName, versionCode);
final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
if (matchFactoryOnly) {
// Instant app filtering for APEX modules is ignored
if ((flags & MATCH_APEX) != 0) {
return mApexManager.getPackageInfo(packageName,
ApexManager.MATCH_FACTORY_PACKAGE);
}
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
}
}
AndroidPackage p = mPackages.get(packageName);
if (matchFactoryOnly && p != null && !p.isSystem()) {
return null;
}
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
final PackageSetting ps = getPackageSetting(p.getPackageName());
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) return null;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
}
if ((flags & MATCH_APEX) != 0) {
return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
}
return null;
}
@Nullable
public final PackageSetting getPackageSetting(String packageName) {
return getPackageSettingInternal(packageName, Binder.getCallingUid());
}
public PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
packageName = resolveInternalPackageNameInternalLocked(
packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
return mSettings.getPackageLPr(packageName);
}
public final ParceledListSlice getInstalledPackages(int flags, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return ParceledListSlice.emptyList();
}
if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId);
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "get installed packages");
return getInstalledPackagesBody(flags, userId, callingUid);
}
protected ParceledListSlice getInstalledPackagesBody(int flags, int userId,
int callingUid) {
// writer
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
final boolean listApex = (flags & MATCH_APEX) != 0;
final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
ArrayList list;
if (listUninstalled) {
list = new ArrayList<>(mSettings.getPackagesLocked().size());
for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
if (listFactory) {
if (!ps.isSystem()) {
continue;
}
PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
if (psDisabled != null) {
ps = psDisabled;
}
}
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
final PackageInfo pi = generatePackageInfo(ps, flags, userId);
if (pi != null) {
list.add(pi);
}
}
} else {
list = new ArrayList<>(mPackages.size());
for (AndroidPackage p : mPackages.values()) {
PackageSetting ps = getPackageSetting(p.getPackageName());
if (listFactory) {
if (!p.isSystem()) {
continue;
}
PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
if (psDisabled != null) {
ps = psDisabled;
}
}
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
final PackageInfo pi = generatePackageInfo(ps, flags, userId);
if (pi != null) {
list.add(pi);
}
}
}
if (listApex) {
if (listFactory) {
list.addAll(mApexManager.getFactoryPackages());
} else {
list.addAll(mApexManager.getActivePackages());
}
if (listUninstalled) {
list.addAll(mApexManager.getInactivePackages());
}
}
return new ParceledListSlice<>(list);
}
/**
* If the filter's target user can handle the intent and is enabled: a [ResolveInfo] that
* will forward the intent to the filter's target user, along with the highest approval of
* any handler in the target user. Otherwise, returns null.
*/
@Nullable
private CrossProfileDomainInfo createForwardingResolveInfo(
@NonNull CrossProfileIntentFilter filter, @NonNull Intent intent,
@Nullable String resolvedType, int flags, int sourceUserId) {
int targetUserId = filter.getTargetUserId();
if (!isUserEnabled(targetUserId)) {
return null;
}
List resultTargetUser = mComponentResolver.queryActivities(intent,
resolvedType, flags, targetUserId);
if (CollectionUtils.isEmpty(resultTargetUser)) {
return null;
}
ResolveInfo forwardingInfo = null;
for (int i = resultTargetUser.size() - 1; i >= 0; i--) {
ResolveInfo targetUserResolveInfo = resultTargetUser.get(i);
if ((targetUserResolveInfo.activityInfo.applicationInfo.flags
& ApplicationInfo.FLAG_SUSPENDED) == 0) {
forwardingInfo = createForwardingResolveInfoUnchecked(filter, sourceUserId,
targetUserId);
break;
}
}
if (forwardingInfo == null) {
// If all the matches in the target profile are suspended, return null.
return null;
}
int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
int size = resultTargetUser.size();
for (int i = 0; i < size; i++) {
ResolveInfo riTargetUser = resultTargetUser.get(i);
if (riTargetUser.handleAllWebDataURI) {
continue;
}
String packageName = riTargetUser.activityInfo.packageName;
PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null) {
continue;
}
highestApprovalLevel = Math.max(highestApprovalLevel, mDomainVerificationManager
.approvalLevelForDomain(ps, intent, flags, targetUserId));
}
return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel);
}
public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId) {
ResolveInfo forwardingResolveInfo = new ResolveInfo();
final long ident = Binder.clearCallingIdentity();
boolean targetIsProfile;
try {
targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
} finally {
Binder.restoreCallingIdentity(ident);
}
String className;
if (targetIsProfile) {
className = FORWARD_INTENT_TO_MANAGED_PROFILE;
} else {
className = FORWARD_INTENT_TO_PARENT;
}
ComponentName forwardingActivityComponentName = new ComponentName(
androidApplication().packageName, className);
ActivityInfo forwardingActivityInfo =
getActivityInfo(forwardingActivityComponentName, 0,
sourceUserId);
if (!targetIsProfile) {
forwardingActivityInfo.showUserIcon = targetUserId;
forwardingResolveInfo.noResourceId = true;
}
forwardingResolveInfo.activityInfo = forwardingActivityInfo;
forwardingResolveInfo.priority = 0;
forwardingResolveInfo.preferredOrder = 0;
forwardingResolveInfo.match = 0;
forwardingResolveInfo.isDefault = true;
forwardingResolveInfo.filter = new IntentFilter(filter.getIntentFilter());
forwardingResolveInfo.targetUserId = targetUserId;
return forwardingResolveInfo;
}
// Return matching ResolveInfo in target user if any.
@Nullable
private CrossProfileDomainInfo queryCrossProfileIntents(
List matchingFilters, Intent intent, String resolvedType,
int flags, int sourceUserId, boolean matchInCurrentProfile) {
if (matchingFilters == null) {
return null;
}
// Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
// match the same intent. For performance reasons, it is better not to
// run queryIntent twice for the same userId
SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
CrossProfileDomainInfo resultInfo = null;
int size = matchingFilters.size();
for (int i = 0; i < size; i++) {
CrossProfileIntentFilter filter = matchingFilters.get(i);
int targetUserId = filter.getTargetUserId();
boolean skipCurrentProfile =
(filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0;
boolean skipCurrentProfileIfNoMatchFound =
(filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0;
if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId)
&& (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) {
// Checking if there are activities in the target user that can handle the
// intent.
CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
resolvedType, flags, sourceUserId);
if (info != null) {
resultInfo = info;
break;
}
alreadyTriedUserIds.put(targetUserId, true);
}
}
if (resultInfo == null) {
return null;
}
ResolveInfo forwardingResolveInfo = resultInfo.resolveInfo;
if (!isUserEnabled(forwardingResolveInfo.targetUserId)) {
return null;
}
List filteredResult =
filterIfNotSystemUser(Collections.singletonList(forwardingResolveInfo),
sourceUserId);
if (filteredResult.isEmpty()) {
return null;
}
return resultInfo;
}
private ResolveInfo querySkipCurrentProfileIntents(
List matchingFilters, Intent intent, String resolvedType,
int flags, int sourceUserId) {
if (matchingFilters != null) {
int size = matchingFilters.size();
for (int i = 0; i < size; i ++) {
CrossProfileIntentFilter filter = matchingFilters.get(i);
if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
// Checking if there are activities in the target user that can handle the
// intent.
CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent,
resolvedType, flags, sourceUserId);
if (info != null) {
return info.resolveInfo;
}
}
}
}
return null;
}
public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId);
enforceCrossUserOrProfilePermission(callingUid, userId,
false /* requireFullPermission */,
false /* checkShell */, "get service info");
return getServiceInfoBody(component, flags, userId, callingUid);
}
protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
int callingUid) {
ParsedService s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
if (s == null) {
return null;
}
AndroidPackage pkg = mPackages.get(s.getPackageName());
if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
return PackageInfoUtils.generateServiceInfo(pkg,
s, flags, ps.readUserState(userId), userId, ps);
}
return null;
}
@Nullable
public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
return getSharedLibraryInfo(name, version, mSharedLibraries, null);
}
/**
* Returns the package name of the calling Uid if it's an instant app. If it isn't
* instant, returns {@code null}.
*/
public String getInstantAppPackageName(int callingUid) {
// If the caller is an isolated app use the owner's uid for the lookup.
if (Process.isIsolated(callingUid)) {
callingUid = getIsolatedOwner(callingUid);
}
final int appId = UserHandle.getAppId(callingUid);
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
return isInstantApp ? ps.pkg.getPackageName() : null;
}
return null;
}
/**
* Finds the owner for the provided isolated UID. Throws IllegalStateException if no such
* isolated UID is found.
*/
private int getIsolatedOwner(int isolatedUid) {
final int ownerUid = mIsolatedOwners.get(isolatedUid, -1);
if (ownerUid == -1) {
throw new IllegalStateException(
"No owner UID found for isolated UID " + isolatedUid);
}
return ownerUid;
}
public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
if (pkg.getStaticSharedLibName() != null) {
return pkg.getManifestPackageName();
}
return pkg.getPackageName();
}
private String resolveInternalPackageNameInternalLocked(
String packageName, long versionCode, int callingUid) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
// Is this a static library?
WatchedLongSparseArray versionedLib =
mStaticLibsByDeclaringPackage.get(packageName);
if (versionedLib == null || versionedLib.size() <= 0) {
return packageName;
}
// Figure out which lib versions the caller can see
LongSparseLongArray versionsCallerCanSee = null;
final int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
&& callingAppId != Process.ROOT_UID) {
versionsCallerCanSee = new LongSparseLongArray();
String libName = versionedLib.valueAt(0).getName();
String[] uidPackages = getPackagesForUidInternal(callingUid, callingUid);
if (uidPackages != null) {
for (String uidPackage : uidPackages) {
PackageSetting ps = mSettings.getPackageLPr(uidPackage);
final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
if (libIdx >= 0) {
final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
versionsCallerCanSee.append(libVersion, libVersion);
}
}
}
}
// Caller can see nothing - done
if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) {
return packageName;
}
// Find the version the caller can see and the app version code
SharedLibraryInfo highestVersion = null;
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
libraryInfo.getLongVersion()) < 0) {
continue;
}
final long libVersionCode = libraryInfo.getDeclaringPackage().getLongVersionCode();
if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (libVersionCode == versionCode) {
return libraryInfo.getPackageName();
}
} else if (highestVersion == null) {
highestVersion = libraryInfo;
} else if (libVersionCode > highestVersion
.getDeclaringPackage().getLongVersionCode()) {
highestVersion = libraryInfo;
}
}
if (highestVersion != null) {
return highestVersion.getPackageName();
}
return packageName;
}
public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
final int callingUid = Binder.getCallingUid();
return resolveInternalPackageNameInternalLocked(packageName, versionCode,
callingUid);
}
/**
* IMPORTANT: Not all packages returned by this method may be known
* to the system. There are two conditions in which this may occur:
*
* The package is on adoptable storage and the device has been removed
* The package is being removed and the internal structures are partially updated
*
* The second is an artifact of the current data structures and should be fixed. See
* b/111075456 for one such instance.
* This binder API is cached. If the algorithm in this method changes,
* or if the underlying objecs (as returned by getSettingLPr()) change
* then the logic that invalidates the cache must be revisited. See
* calls to invalidateGetPackagesForUidCache() to locate the points at
* which the cache is invalidated.
*/
public final String[] getPackagesForUid(int uid) {
return getPackagesForUidInternal(uid, Binder.getCallingUid());
}
private String[] getPackagesForUidInternal(int uid, int callingUid) {
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
}
protected String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
boolean isCallerInstantApp) {
// reader
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return null;
}
final SharedUserSetting sus = (SharedUserSetting) obj;
final int N = sus.packages.size();
String[] res = new String[N];
int i = 0;
for (int index = 0; index < N; index++) {
final PackageSetting ps = sus.packages.valueAt(index);
if (ps.getInstalled(userId)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
res[i++] = ps.name;
}
}
return ArrayUtils.trimToSize(res, i);
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (ps.getInstalled(userId)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return new String[]{ps.name};
}
}
return null;
}
public final UserInfo getProfileParent(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return mUserManager.getProfileParent(userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Returns whether or not instant apps have been disabled remotely.
*/
private boolean areWebInstantAppsDisabled(int userId) {
return mWebInstantAppsDisabled.get(userId);
}
/**
* Returns whether or not a full application can see an instant application.
*
* Currently, there are four cases in which this can occur:
*
* The calling application is a "special" process. Special processes
* are those with a UID < {@link Process#FIRST_APPLICATION_UID}.
* The calling application has the permission
* {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.
* The calling application is the default launcher on the
* system partition.
* The calling application is the default app prediction service.
*
*/
public final boolean canViewInstantApps(int callingUid, int userId) {
if (callingUid < Process.FIRST_APPLICATION_UID) {
return true;
}
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED) {
return true;
}
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.VIEW_INSTANT_APPS) == PERMISSION_GRANTED) {
final ComponentName homeComponent = getDefaultHomeActivity(userId);
if (homeComponent != null
&& isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
return true;
}
// TODO(b/122900055) Change/Remove this and replace with new permission role.
if (mAppPredictionServicePackage != null
&& isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
return true;
}
}
return false;
}
public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
int userId, int flags) {
// Callers can access only the libs they depend on, otherwise they need to explicitly
// ask for the shared libraries given the caller is allowed to access all static libs.
if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
// System/shell/root get to see all static libs
final int appId = UserHandle.getAppId(uid);
if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
|| appId == Process.ROOT_UID) {
return false;
}
// Installer gets to see all static libs.
if (PackageManager.PERMISSION_GRANTED
== checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) {
return false;
}
}
// No package means no static lib as it is always on internal storage
if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
return false;
}
final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
if (libraryInfo == null) {
return false;
}
final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
final String[] uidPackageNames = getPackagesForUid(resolvedUid);
if (uidPackageNames == null) {
return true;
}
for (String uidPackageName : uidPackageNames) {
if (ps.name.equals(uidPackageName)) {
return false;
}
PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName);
if (uidPs != null) {
final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries,
libraryInfo.getName());
if (index < 0) {
continue;
}
if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
== libraryInfo.getLongVersion()) {
return false;
}
}
}
return true;
}
private boolean hasCrossUserPermission(
int callingUid, int callingUserId, int userId, boolean requireFullPermission,
boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
return true;
}
if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
return true;
}
if (requireFullPermission) {
return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
|| hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
}
/**
* @param resolveInfos list of resolve infos in descending priority order
* @return if the list contains a resolve info with non-negative priority
*/
private boolean hasNonNegativePriority(List resolveInfos) {
return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
}
private boolean hasPermission(String permission) {
return mContext.checkCallingOrSelfPermission(permission)
== PackageManager.PERMISSION_GRANTED;
}
public final boolean isCallerSameApp(String packageName, int uid) {
AndroidPackage pkg = mPackages.get(packageName);
return pkg != null
&& UserHandle.getAppId(uid) == pkg.getUid();
}
public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
return true;
}
if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
return true;
}
if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) {
return true;
}
return false;
}
public final boolean isComponentVisibleToInstantApp(
@Nullable ComponentName component, @ComponentType int type) {
if (type == TYPE_ACTIVITY) {
final ParsedActivity activity = mComponentResolver.getActivity(component);
if (activity == null) {
return false;
}
final boolean visibleToInstantApp =
(activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
final boolean explicitlyVisibleToInstantApp =
(activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
== 0;
return visibleToInstantApp && explicitlyVisibleToInstantApp;
} else if (type == TYPE_RECEIVER) {
final ParsedActivity activity = mComponentResolver.getReceiver(component);
if (activity == null) {
return false;
}
final boolean visibleToInstantApp =
(activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
final boolean explicitlyVisibleToInstantApp =
(activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP)
== 0;
return visibleToInstantApp && !explicitlyVisibleToInstantApp;
} else if (type == TYPE_SERVICE) {
final ParsedService service = mComponentResolver.getService(component);
return service != null
&& (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
} else if (type == TYPE_PROVIDER) {
final ParsedProvider provider = mComponentResolver.getProvider(component);
return provider != null
&& (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
} else if (type == TYPE_UNKNOWN) {
return isComponentVisibleToInstantApp(component);
}
return false;
}
/**
* From Android R,
* camera intents have to match system apps. The only exception to this is if
* the DPC has set the camera persistent preferred activity. This case was introduced
* because it is important that the DPC has the ability to set both system and non-system
* camera persistent preferred activities.
*
* @return {@code true} if the intent is a camera intent and the persistent preferred
* activity was not set by the DPC.
*/
public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
int userId, String resolvedType, int flags) {
return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
intent, userId, resolvedType, flags);
}
public final boolean isInstantApp(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "isInstantApp");
return isInstantAppInternal(packageName, userId, callingUid);
}
public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
int callingUid) {
if (HIDE_EPHEMERAL_APIS) {
return false;
}
return isInstantAppInternalBody(packageName, userId, callingUid);
}
protected boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
int callingUid) {
if (Process.isIsolated(callingUid)) {
callingUid = getIsolatedOwner(callingUid);
}
final PackageSetting ps = mSettings.getPackageLPr(packageName);
final boolean returnAllowed =
ps != null
&& (isCallerSameApp(packageName, callingUid)
|| canViewInstantApps(callingUid, userId)
|| mInstantAppRegistry.isInstantAccessGranted(
userId, UserHandle.getAppId(callingUid), ps.appId));
if (returnAllowed) {
return ps.getInstantApp(userId);
}
return false;
}
private boolean isInstantAppResolutionAllowed(
Intent intent, List resolvedActivities, int userId,
boolean skipPackageCheck, int flags) {
if (mInstantAppResolverConnection == null) {
return false;
}
if (instantAppInstallerActivity() == null) {
return false;
}
if (intent.getComponent() != null) {
return false;
}
if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
return false;
}
if (!skipPackageCheck && intent.getPackage() != null) {
return false;
}
if (!intent.isWebIntent()) {
// for non web intents, we should not resolve externally if an app already exists to
// handle it or if the caller didn't explicitly request it.
if ((resolvedActivities != null && resolvedActivities.size() != 0)
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
return false;
}
} else {
if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
return false;
} else if (areWebInstantAppsDisabled(userId)) {
return false;
}
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
skipPackageCheck, flags);
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
protected boolean isInstantAppResolutionAllowedBody(
Intent intent, List resolvedActivities, int userId,
boolean skipPackageCheck, int flags) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
final ResolveInfo info = resolvedActivities.get(n);
final String packageName = info.activityInfo.packageName;
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
// only check domain verification status if the app is not a browser
if (!info.handleAllWebDataURI) {
if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
+ ", approved");
}
return false;
}
}
if (ps.getInstantApp(userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app installed;"
+ " pkg: " + packageName);
}
return false;
}
}
}
// We've exhausted all ways to deny ephemeral application; let the system look for them.
return true;
}
private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
String resolvedType, int flags) {
PersistentPreferredIntentResolver ppir =
mSettings.getPersistentPreferredActivities(userId);
//TODO(b/158003772): Remove double query
List pprefs = ppir != null
? ppir.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
userId)
: new ArrayList<>();
for (PersistentPreferredActivity ppa : pprefs) {
if (ppa.mIsSetByDpm) {
return true;
}
}
return false;
}
private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
if (!mInjector.getLocalService(ActivityTaskManagerInternal.class)
.isCallerRecents(callingUid)) {
return false;
}
final long token = Binder.clearCallingIdentity();
try {
final int callingUserId = UserHandle.getUserId(callingUid);
if (ActivityManager.getCurrentUser() != callingUserId) {
return false;
}
return mUserManager.isSameProfileGroup(callingUserId, targetUserId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
@UserIdInt int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private boolean isUserEnabled(int userId) {
final long callingId = Binder.clearCallingIdentity();
try {
UserInfo userInfo = mUserManager.getUserInfo(userId);
return userInfo != null && userInfo.isEnabled();
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
/**
* Returns whether or not access to the application should be filtered.
*
* Access may be limited based upon whether the calling or target applications
* are instant applications.
*
* @see #canViewInstantApps(int, int)
*/
public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
callingUid = getIsolatedOwner(callingUid);
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final boolean callerIsInstantApp = instantAppPkgName != null;
if (ps == null) {
if (callerIsInstantApp) {
// pretend the application exists, but, needs to be filtered
return true;
}
return false;
}
// if the target and caller are the same application, don't filter
if (isCallerSameApp(ps.name, callingUid)) {
return false;
}
if (callerIsInstantApp) {
// both caller and target are both instant, but, different applications, filter
if (ps.getInstantApp(userId)) {
return true;
}
// request for a specific component; if it hasn't been explicitly exposed through
// property or instrumentation target, filter
if (component != null) {
final ParsedInstrumentation instrumentation =
mInstrumentation.get(component);
if (instrumentation != null
&& isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
return false;
}
return !isComponentVisibleToInstantApp(component, componentType);
}
// request for application; if no components have been explicitly exposed, filter
return !ps.pkg.isVisibleToInstantApps();
}
if (ps.getInstantApp(userId)) {
// caller can see all components of all instant applications, don't filter
if (canViewInstantApps(callingUid, userId)) {
return false;
}
// request for a specific instant application component, filter
if (component != null) {
return true;
}
// request for an instant application; if the caller hasn't been granted access,
//filter
return !mInstantAppRegistry.isInstantAccessGranted(
userId, UserHandle.getAppId(callingUid), ps.appId);
}
int appId = UserHandle.getAppId(callingUid);
final SettingBase callingPs = mSettings.getSettingLPr(appId);
return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId);
}
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
public final boolean shouldFilterApplicationLocked(
@Nullable PackageSetting ps, int callingUid, int userId) {
return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
}
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
int callingUid, int userId) {
boolean filterApp = true;
for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) {
filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index),
callingUid, /* component */ null, TYPE_UNKNOWN, userId);
}
return filterApp;
}
/**
* Verification statuses are ordered from the worse to the best, except for
* INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
*/
private int bestDomainVerificationStatus(int status1, int status2) {
if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
return status2;
}
if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
return status1;
}
return (int) MathUtils.max(status1, status2);
}
// NOTE: Can't remove without a major refactor. Keep around for now.
public final int checkUidPermission(String permName, int uid) {
return mPermissionManager.checkUidPermission(uid, permName);
}
public int getPackageUidInternal(String packageName, int flags, int userId,
int callingUid) {
// reader
final AndroidPackage p = mPackages.get(packageName);
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return -1;
}
return UserHandle.getUid(userId, p.getUid());
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return UserHandle.getUid(userId, ps.appId);
}
}
return -1;
}
/**
* Update given flags based on encryption status of current user.
*/
private int updateFlags(int flags, int userId) {
if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
// Caller expressed an explicit opinion about what encryption
// aware/unaware components they want to see, so fall through and
// give them what they want
} else {
final UserManagerInternal umInternal = mInjector.getUserManagerInternal();
// Caller expressed no opinion, so match based on user state
if (umInternal.isUserUnlockingOrUnlocked(userId)) {
flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
} else {
flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE;
}
}
return flags;
}
/**
* Update given flags when being used to request {@link ApplicationInfo}.
*/
public final int updateFlagsForApplication(int flags, int userId) {
return updateFlagsForPackage(flags, userId);
}
/**
* Update given flags when being used to request {@link ComponentInfo}.
*/
public final int updateFlagsForComponent(int flags, int userId) {
return updateFlags(flags, userId);
}
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
public final int updateFlagsForPackage(int flags, int userId) {
final boolean isCallerSystemUser = UserHandle.getCallingUserId()
== UserHandle.USER_SYSTEM;
if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
// require the permission to be held; the calling uid and given user id referring
// to the same user is not sufficient
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
"MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission");
} else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0
&& isCallerSystemUser
&& mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
// If the caller wants all packages and has a restricted profile associated with it,
// then match all users. This is to make sure that launchers that need to access
//work
// profile apps don't start breaking. TODO: Remove this hack when launchers stop
//using
// MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
flags |= PackageManager.MATCH_ANY_USER;
}
return updateFlags(flags, userId);
}
/**
* Update given flags when being used to request {@link ResolveInfo}.
*
Instant apps are resolved specially, depending upon context. Minimally,
* {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
* flag set. However, this flag is only honoured in three circumstances:
*
* when called from a system process
* when the caller holds the permission {@code
* android.permission.ACCESS_INSTANT_APPS}
* when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
* action and a {@code android.intent.category.BROWSABLE} category
*
*/
public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, false /*onlyExposedExplicitly*/,
isImplicitImageCaptureIntentAndNotSetByDpc);
}
public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean onlyExposedExplicitly,
boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
// Safe mode means we shouldn't match any third-party components
if (safeMode() || isImplicitImageCaptureIntentAndNotSetByDpc) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
if (getInstantAppPackageName(callingUid) != null) {
// But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
if (onlyExposedExplicitly) {
flags |= PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY;
}
flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
flags |= PackageManager.MATCH_INSTANT;
} else {
final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
final boolean allowMatchInstant = wantInstantApps
|| (wantMatchInstant && canViewInstantApps(callingUid, userId));
flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
| PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
if (!allowMatchInstant) {
flags &= ~PackageManager.MATCH_INSTANT;
}
}
return updateFlagsForComponent(flags, userId);
}
/**
* Checks if the request is from the system or an app that has the appropriate cross-user
* permissions defined as follows:
*
* INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.
* INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
* to the caller.
* Otherwise,
* INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
* group as the caller.
*
*
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param message the message to log on security exception
*/
public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
if (checkShell) {
PackageManagerServiceUtils.enforceShellRestriction(
mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
/*requirePermissionWhenSameUser= */ false)) {
return;
}
final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
mContext,
android.Manifest.permission.INTERACT_ACROSS_PROFILES,
PermissionChecker.PID_UNKNOWN,
callingUid,
getPackage(callingUid).getPackageName())
== PermissionChecker.PERMISSION_GRANTED) {
return;
}
String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
callingUid, userId, message, requireFullPermission, isSameProfileGroup);
Slog.w(TAG, errorMessage);
throw new SecurityException(errorMessage);
}
/**
* Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
* or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
*
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param message the message to log on security exception
*/
public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false,
message);
}
/**
* Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
* or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
*
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param requirePermissionWhenSameUser When {@code true}, still require the cross user
* permission to be held even if the callingUid and
* userId
* reference the same user.
* @param message the message to log on security exception
*/
public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message) {
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
if (checkShell) {
PackageManagerServiceUtils.enforceShellRestriction(
mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(
callingUid, callingUserId, userId, requireFullPermission,
requirePermissionWhenSameUser)) {
return;
}
String errorMessage = buildInvalidCrossUserPermissionMessage(
callingUid, userId, message, requireFullPermission);
Slog.w(TAG, errorMessage);
throw new SecurityException(errorMessage);
}
public SigningDetails getSigningDetails(@NonNull String packageName) {
AndroidPackage p = mPackages.get(packageName);
if (p == null) {
return null;
}
return p.getSigningDetails();
}
public SigningDetails getSigningDetails(int uid) {
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
return ((SharedUserSetting) obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
return ps.signatures.mSigningDetails;
}
}
return SigningDetails.UNKNOWN;
}
public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
PackageSetting ps = getPackageSetting(pkg.getPackageName());
return shouldFilterApplicationLocked(ps, callingUid,
userId);
}
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
PackageSetting ps = getPackageSetting(packageName);
return shouldFilterApplicationLocked(ps, callingUid,
userId);
}
public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
final String packageName = dumpState.getTargetPackageName();
final boolean checkin = dumpState.isCheckIn();
switch (type) {
case DumpState.DUMP_VERSION:
{
if (dumpState.onTitlePrinted()) {
pw.println();
}
pw.println("Database versions:");
mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, " "));
break;
}
case DumpState.DUMP_LIBS:
{
boolean printedHeader = false;
final int numSharedLibraries = mSharedLibraries.size();
for (int index = 0; index < numSharedLibraries; index++) {
final String libName = mSharedLibraries.keyAt(index);
final WatchedLongSparseArray versionedLib =
mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
if (!checkin) {
if (!printedHeader) {
if (dumpState.onTitlePrinted()) {
pw.println();
}
pw.println("Libraries:");
printedHeader = true;
}
pw.print(" ");
} else {
pw.print("lib,");
}
pw.print(libraryInfo.getName());
if (libraryInfo.isStatic()) {
pw.print(" version=" + libraryInfo.getLongVersion());
}
if (!checkin) {
pw.print(" -> ");
}
if (libraryInfo.getPath() != null) {
if (libraryInfo.isNative()) {
pw.print(" (so) ");
} else {
pw.print(" (jar) ");
}
pw.print(libraryInfo.getPath());
} else {
pw.print(" (apk) ");
pw.print(libraryInfo.getPackageName());
}
pw.println();
}
}
break;
}
case DumpState.DUMP_PREFERRED:
mSettings.dumpPreferred(pw, dumpState, packageName);
break;
case DumpState.DUMP_PREFERRED_XML:
{
pw.flush();
FileOutputStream fout = new FileOutputStream(fd);
BufferedOutputStream str = new BufferedOutputStream(fout);
TypedXmlSerializer serializer = Xml.newFastSerializer();
try {
serializer.setOutput(str, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
mSettings.writePreferredActivitiesLPr(serializer, 0,
dumpState.isFullPreferred());
serializer.endDocument();
serializer.flush();
} catch (IllegalArgumentException e) {
pw.println("Failed writing: " + e);
} catch (IllegalStateException e) {
pw.println("Failed writing: " + e);
} catch (IOException e) {
pw.println("Failed writing: " + e);
}
break;
}
case DumpState.DUMP_QUERIES:
{
final PackageSetting setting = mSettings.getPackageLPr(packageName);
Integer filteringAppId = setting == null ? null : setting.appId;
mAppsFilter.dumpQueries(
pw, filteringAppId, dumpState, mUserManager.getUserIds(),
this::getPackagesForUidInternalBody);
break;
}
case DumpState.DUMP_DOMAIN_PREFERRED:
{
final android.util.IndentingPrintWriter writer =
new android.util.IndentingPrintWriter(pw);
if (dumpState.onTitlePrinted()) pw.println();
writer.println("Domain verification status:");
writer.increaseIndent();
try {
mDomainVerificationManager.printState(writer, packageName,
UserHandle.USER_ALL, mSettings::getPackageLPr);
} catch (Exception e) {
pw.println("Failure printing domain verification information");
Slog.e(TAG, "Failure printing domain verification information", e);
}
writer.decreaseIndent();
break;
}
case DumpState.DUMP_DEXOPT:
{
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println();
ipw.println("Dexopt state:");
ipw.increaseIndent();
Collection pkgSettings;
if (packageName != null) {
PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
if (targetPkgSetting != null) {
pkgSettings = Collections.singletonList(targetPkgSetting);
} else {
ipw.println("Unable to find package: " + packageName);
return;
}
} else {
pkgSettings = mSettings.getPackagesLocked().values();
}
for (PackageSetting pkgSetting : pkgSettings) {
final AndroidPackage pkg = pkgSetting.getPkg();
if (pkg == null) {
continue;
}
ipw.println("[" + pkgSetting.name + "]");
ipw.increaseIndent();
mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting,
mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
ipw.decreaseIndent();
}
break;
}
case DumpState.DUMP_COMPILER_STATS:
{
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println();
ipw.println("Compiler stats:");
ipw.increaseIndent();
Collection packages;
if (packageName != null) {
AndroidPackage targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
packages = Collections.singletonList(targetPackage);
} else {
ipw.println("Unable to find package: " + packageName);
return;
}
} else {
packages = mPackages.values();
}
for (AndroidPackage pkg : packages) {
final String pkgName = pkg.getPackageName();
ipw.println("[" + pkgName + "]");
ipw.increaseIndent();
CompilerStats.PackageStats stats = mCompilerStats.getPackageStats(pkgName);
if (stats == null) {
ipw.println("(No recorded stats)");
} else {
stats.dump(ipw);
}
ipw.decreaseIndent();
}
break;
}
} // switch
}
// The body of findPreferredActivity.
protected FindPreferredActivityBodyResult findPreferredActivityBody(
Intent intent, String resolvedType, int flags,
List query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
int callingUid, boolean isDeviceProvisioned) {
FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult();
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
resolvedType, flags));
intent = updateIntentForResolve(intent);
// Try to find a matching persistent preferred activity.
result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
resolvedType, flags, query, debug, userId);
// If a persistent preferred activity matched, use it.
if (result.mPreferredResolveInfo != null) {
return result;
}
PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
// Get the list of preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
List prefs = pir != null
? pir.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
userId)
: null;
if (prefs != null && prefs.size() > 0) {
// First figure out how good the original match set is.
// We will only allow preferred activities that came
// from the same match quality.
int match = 0;
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
final int N = query.size();
for (int j = 0; j < N; j++) {
final ResolveInfo ri = query.get(j);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Match for " + ri.activityInfo
+ ": 0x" + Integer.toHexString(match));
}
if (ri.match > match) {
match = ri.match;
}
}
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
}
match &= IntentFilter.MATCH_CATEGORY_MASK;
final int M = prefs.size();
for (int i = 0; i < M; i++) {
final PreferredActivity pa = prefs.get(i);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Checking PreferredActivity ds="
+ (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "")
+ "\n component=" + pa.mPref.mComponent);
pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
}
if (pa.mPref.mMatch != match) {
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Skipping bad match "
+ Integer.toHexString(pa.mPref.mMatch));
}
continue;
}
// If it's not an "always" type preferred activity and that's what we're
// looking for, skip it.
if (always && !pa.mPref.mAlways) {
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
continue;
}
final ActivityInfo ai = getActivityInfo(
pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
| MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found preferred activity:");
if (ai != null) {
ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
} else {
Slog.v(TAG, " null");
}
}
final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
&& !isDeviceProvisioned;
final boolean allowSetMutation = !excludeSetupWizardHomeActivity
&& !queryMayBeFiltered;
if (ai == null) {
// Do not remove launcher's preferred activity during SetupWizard
// due to it may not install yet
if (!allowSetMutation) {
continue;
}
// This previously registered preferred activity
// component is no longer known. Most likely an update
// to the app was installed and in the new version this
// component no longer exists. Clean it up by removing
// it from the preferred activities list, and skip it.
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
pir.removeFilter(pa);
result.mChanged = true;
continue;
}
for (int j = 0; j < N; j++) {
final ResolveInfo ri = query.get(j);
if (!ri.activityInfo.applicationInfo.packageName
.equals(ai.applicationInfo.packageName)) {
continue;
}
if (!ri.activityInfo.name.equals(ai.name)) {
continue;
}
if (removeMatches && allowSetMutation) {
pir.removeFilter(pa);
result.mChanged = true;
if (DEBUG_PREFERRED) {
Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
}
break;
}
// Okay we found a previously set preferred or last chosen app.
// If the result set is different from when this
// was created, and is not a subset of the preferred set, we need to
// clear it and re-ask the user their preference, if we're looking for
// an "always" type entry.
if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
if (allowSetMutation) {
// some components of the set are no longer present in
// the query, but the preferred activity can still be reused
if (DEBUG_PREFERRED) {
Slog.i(TAG, "Result set changed, but PreferredActivity"
+ " is still valid as only non-preferred"
+ " components were removed for " + intent
+ " type " + resolvedType);
}
// remove obsolete components and re-add the up-to-date
// filter
PreferredActivity freshPa = new PreferredActivity(pa,
pa.mPref.mMatch,
pa.mPref.discardObsoleteComponents(query),
pa.mPref.mComponent,
pa.mPref.mAlways);
pir.removeFilter(pa);
pir.addFilter(freshPa);
result.mChanged = true;
} else {
if (DEBUG_PREFERRED) {
Slog.i(TAG, "Do not remove preferred activity");
}
}
} else {
if (allowSetMutation) {
Slog.i(TAG,
"Result set changed, dropping preferred activity "
+ "for " + intent + " type "
+ resolvedType);
if (DEBUG_PREFERRED) {
Slog.v(TAG,
"Removing preferred activity since set changed "
+ pa.mPref.mComponent);
}
pir.removeFilter(pa);
// Re-add the filter as a "last chosen" entry (!always)
PreferredActivity lastChosen = new PreferredActivity(
pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
false);
pir.addFilter(lastChosen);
result.mChanged = true;
}
result.mPreferredResolveInfo = null;
return result;
}
}
// Yay! Either the set matched or we're looking for the last chosen
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Returning preferred activity: "
+ ri.activityInfo.packageName + "/" + ri.activityInfo.name);
}
result.mPreferredResolveInfo = ri;
return result;
}
}
}
return result;
}
public final FindPreferredActivityBodyResult findPreferredActivityInternal(
Intent intent, String resolvedType, int flags,
List query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
final int callingUid = Binder.getCallingUid();
// Do NOT hold the packages lock; this calls up into the settings provider which
// could cause a deadlock.
final boolean isDeviceProvisioned =
android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
// Find the preferred activity - the lock is held inside the method.
return findPreferredActivityBody(
intent, resolvedType, flags, query, always, removeMatches, debug,
userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
}
public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
String resolvedType,
int flags, List query, boolean debug, int userId) {
final int N = query.size();
PersistentPreferredIntentResolver ppir =
mSettings.getPersistentPreferredActivities(userId);
// Get the list of persistent preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Looking for persistent preferred activities...");
}
List pprefs = ppir != null
? ppir.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
userId)
: null;
if (pprefs != null && pprefs.size() > 0) {
final int M = pprefs.size();
for (int i = 0; i < M; i++) {
final PersistentPreferredActivity ppa = pprefs.get(i);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+ (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "")
+ "\n component=" + ppa.mComponent);
ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
}
final ActivityInfo ai = getActivityInfo(ppa.mComponent,
flags | MATCH_DISABLED_COMPONENTS, userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found persistent preferred activity:");
if (ai != null) {
ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
} else {
Slog.v(TAG, " null");
}
}
if (ai == null) {
// This previously registered persistent preferred activity
// component is no longer known. Ignore it and do NOT remove it.
continue;
}
for (int j = 0; j < N; j++) {
final ResolveInfo ri = query.get(j);
if (!ri.activityInfo.applicationInfo.packageName
.equals(ai.applicationInfo.packageName)) {
continue;
}
if (!ri.activityInfo.name.equals(ai.name)) {
continue;
}
// Found a persistent preference that can handle the intent.
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Returning persistent preferred activity: "
+ ri.activityInfo.packageName + "/" + ri.activityInfo.name);
}
return ri;
}
}
}
return null;
}
}
/**
* This subclass is the external interface to the live computer. Some internal helper
* methods are overridden to fetch live data instead of snapshot data. For each
* Computer interface that is overridden in this class, the override takes the PM lock
* and then delegates to the live computer engine. This is required because there are
* no locks taken in the engine itself.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected static class ComputerLocked extends ComputerEngine {
private final Object mLock;
ComputerLocked(Snapshot args) {
super(args);
mLock = mService.mLock;
}
protected final ComponentName resolveComponentName() {
return mService.mResolveComponentName;
}
protected final ActivityInfo instantAppInstallerActivity() {
return mService.mInstantAppInstallerActivity;
}
protected final ApplicationInfo androidApplication() {
return mService.mAndroidApplication;
}
public final @NonNull List queryIntentServicesInternalBody(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
String instantAppPkgName) {
synchronized (mLock) {
return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
callingUid, instantAppPkgName);
}
}
public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName) {
synchronized (mLock) {
return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
instantAppPkgName);
}
}
public final ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
userId);
}
}
public final AndroidPackage getPackage(String packageName) {
synchronized (mLock) {
return super.getPackage(packageName);
}
}
public final AndroidPackage getPackage(int uid) {
synchronized (mLock) {
return super.getPackage(uid);
}
}
public final ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
userId);
}
}
public final ArrayList filterCandidatesWithDomainPreferredActivitiesLPrBody(
Intent intent, int matchFlags, List candidates,
CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
synchronized (mLock) {
return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
matchFlags, candidates, xpDomainInfo, userId, debug);
}
}
public final PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
synchronized (mLock) {
return super.getPackageInfoInternalBody(packageName, versionCode, flags,
filterCallingUid, userId);
}
}
public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
synchronized (mLock) {
return super.getPackageSettingInternal(packageName, callingUid);
}
}
public final ParceledListSlice getInstalledPackagesBody(int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getInstalledPackagesBody(flags, userId, callingUid);
}
}
public final ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getServiceInfoBody(component, flags, userId, callingUid);
}
}
public final String getInstantAppPackageName(int callingUid) {
synchronized (mLock) {
return super.getInstantAppPackageName(callingUid);
}
}
public final String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
boolean isCallerInstantApp) {
synchronized (mLock) {
return super.getPackagesForUidInternalBody(callingUid, userId, appId,
isCallerInstantApp);
}
}
public final boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
int callingUid) {
synchronized (mLock) {
return super.isInstantAppInternalBody(packageName, userId, callingUid);
}
}
public final boolean isInstantAppResolutionAllowedBody(Intent intent,
List resolvedActivities, int userId, boolean skipPackageCheck,
int flags) {
synchronized (mLock) {
return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
skipPackageCheck, flags);
}
}
public final int getPackageUidInternal(String packageName, int flags, int userId,
int callingUid) {
synchronized (mLock) {
return super.getPackageUidInternal(packageName, flags, userId, callingUid);
}
}
public final SigningDetails getSigningDetails(@NonNull String packageName) {
synchronized (mLock) {
return super.getSigningDetails(packageName);
}
}
public final SigningDetails getSigningDetails(int uid) {
synchronized (mLock) {
return super.getSigningDetails(uid);
}
}
public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
synchronized (mLock) {
return super.filterAppAccess(pkg, callingUid, userId);
}
}
public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
synchronized (mLock) {
return super.filterAppAccess(packageName, callingUid, userId);
}
}
public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
synchronized (mLock) {
super.dump(type, fd, pw, dumpState);
}
}
public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
String resolvedType, int flags, List query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
int callingUid, boolean isDeviceProvisioned) {
synchronized (mLock) {
return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
removeMatches, debug, userId, queryMayBeFiltered, callingUid,
isDeviceProvisioned);
}
}
}
/**
* This subclass delegates to methods in a Computer after reference-counting the computer.
*/
private static class ComputerTracker implements Computer {
// The number of times a thread reused a computer in its stack instead of fetching
// a snapshot computer.
private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
// The number of times a thread reused a computer in its stack instead of fetching
// a live computer.
private final AtomicInteger mReusedLive = new AtomicInteger(0);
private PackageManagerService mService;
ComputerTracker(PackageManagerService s) {
mService = s;
}
private ThreadComputer live() {
ThreadComputer current = mService.sThreadComputer.get();
if (current.mRefCount > 0) {
current.acquire();
mReusedLive.incrementAndGet();
} else {
current.acquire(mService.liveComputer());
}
return current;
}
private ThreadComputer snapshot() {
ThreadComputer current = mService.sThreadComputer.get();
if (current.mRefCount > 0) {
current.acquire();
mReusedSnapshot.incrementAndGet();
} else {
current.acquire(mService.snapshotComputer());
}
return current;
}
public final @NonNull List queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart,
boolean allowDynamicSplits) {
ThreadComputer current = snapshot();
try {
return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
privateResolveFlags, filterCallingUid, userId, resolveForStart,
allowDynamicSplits);
} finally {
current.release();
}
}
public final @NonNull List queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
} finally {
current.release();
}
}
public final @NonNull List queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
ThreadComputer current = snapshot();
try {
return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
userId, callingUid, includeInstantApps);
} finally {
current.release();
}
}
public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName) {
ThreadComputer current = live();
try {
return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
pkgName, instantAppPkgName);
} finally {
current.release();
}
}
public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getActivityInfo(component, flags, userId);
} finally {
current.release();
}
}
public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
userId);
} finally {
current.release();
}
}
public final AndroidPackage getPackage(String packageName) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getPackage(packageName);
} finally {
current.release();
}
}
public final AndroidPackage getPackage(int uid) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getPackage(uid);
} finally {
current.release();
}
}
public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName,
int flags, int filterCallingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags,
filterCallingUid, userId);
} finally {
current.release();
}
}
public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getApplicationInfo(packageName, flags, userId);
} finally {
current.release();
}
}
public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getApplicationInfoInternal(packageName, flags,
filterCallingUid, userId);
} finally {
current.release();
}
}
public final ComponentName getDefaultHomeActivity(int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getDefaultHomeActivity(userId);
} finally {
current.release();
}
}
public final ComponentName getHomeActivitiesAsUser(List allHomeCandidates,
int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
} finally {
current.release();
}
}
public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
String resolvedType, int flags, int sourceUserId, int parentUserId) {
ThreadComputer current = live();
try {
return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
flags, sourceUserId, parentUserId);
} finally {
current.release();
}
}
public final Intent getHomeIntent() {
ThreadComputer current = live();
try {
return current.mComputer.getHomeIntent();
} finally {
current.release();
}
}
public final List getMatchingCrossProfileIntentFilters(
Intent intent, String resolvedType, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
userId);
} finally {
current.release();
}
}
public final List applyPostResolutionFilter(
@NonNull List resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent) {
ThreadComputer current = live();
try {
return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
} finally {
current.release();
}
}
public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.generatePackageInfo(ps, flags, userId);
} finally {
current.release();
}
}
public final PackageInfo getPackageInfo(String packageName, int flags, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getPackageInfo(packageName, flags, userId);
} finally {
current.release();
}
}
public final PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
filterCallingUid, userId);
} finally {
current.release();
}
}
public final PackageSetting getPackageSetting(String packageName) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getPackageSetting(packageName);
} finally {
current.release();
}
}
public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
ThreadComputer current = live();
try {
return current.mComputer.getPackageSettingInternal(packageName, callingUid);
} finally {
current.release();
}
}
public final ParceledListSlice getInstalledPackages(int flags, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getInstalledPackages(flags, userId);
} finally {
current.release();
}
}
public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId) {
ThreadComputer current = live();
try {
return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
targetUserId);
} finally {
current.release();
}
}
public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getServiceInfo(component, flags, userId);
} finally {
current.release();
}
}
public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
ThreadComputer current = live();
try {
return current.mComputer.getSharedLibraryInfoLPr(name, version);
} finally {
current.release();
}
}
public final SigningDetails getSigningDetails(@NonNull String packageName) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getSigningDetails(packageName);
} finally {
current.release();
}
}
public final SigningDetails getSigningDetails(int uid) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getSigningDetails(uid);
} finally {
current.release();
}
}
public final String getInstantAppPackageName(int callingUid) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getInstantAppPackageName(callingUid);
} finally {
current.release();
}
}
public final String resolveExternalPackageNameLPr(AndroidPackage pkg) {
ThreadComputer current = live();
try {
return current.mComputer.resolveExternalPackageNameLPr(pkg);
} finally {
current.release();
}
}
public final String resolveInternalPackageNameLPr(String packageName, long versionCode) {
ThreadComputer current = live();
try {
return current.mComputer.resolveInternalPackageNameLPr(packageName, versionCode);
} finally {
current.release();
}
}
public final String[] getPackagesForUid(int uid) {
ThreadComputer current = snapshot();
try {
return current.mComputer.getPackagesForUid(uid);
} finally {
current.release();
}
}
public final UserInfo getProfileParent(int userId) {
ThreadComputer current = live();
try {
return current.mComputer.getProfileParent(userId);
} finally {
current.release();
}
}
public final boolean canViewInstantApps(int callingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.canViewInstantApps(callingUid, userId);
} finally {
current.release();
}
}
public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.filterAppAccess(pkg, callingUid, userId);
} finally {
current.release();
}
}
public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.filterAppAccess(packageName, callingUid, userId);
} finally {
current.release();
}
}
public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid,
int userId, int flags) {
ThreadComputer current = live();
try {
return current.mComputer.filterSharedLibPackageLPr(ps, uid, userId, flags);
} finally {
current.release();
}
}
public final boolean isCallerSameApp(String packageName, int uid) {
ThreadComputer current = live();
try {
return current.mComputer.isCallerSameApp(packageName, uid);
} finally {
current.release();
}
}
public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
ThreadComputer current = live();
try {
return current.mComputer.isComponentVisibleToInstantApp(component);
} finally {
current.release();
}
}
public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@ComponentType int type) {
ThreadComputer current = live();
try {
return current.mComputer.isComponentVisibleToInstantApp(component, type);
} finally {
current.release();
}
}
public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
int userId, String resolvedType, int flags) {
ThreadComputer current = live();
try {
return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
userId, resolvedType, flags);
} finally {
current.release();
}
}
public final boolean isInstantApp(String packageName, int userId) {
ThreadComputer current = snapshot();
try {
return current.mComputer.isInstantApp(packageName, userId);
} finally {
current.release();
}
}
public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
int callingUid) {
ThreadComputer current = live();
try {
return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
} finally {
current.release();
}
}
public final boolean isSameProfileGroup(@UserIdInt int callerUserId,
@UserIdInt int userId) {
ThreadComputer current = live();
try {
return current.mComputer.isSameProfileGroup(callerUserId, userId);
} finally {
current.release();
}
}
public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus,
int callingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.shouldFilterApplicationLocked(sus, callingUid, userId);
} finally {
current.release();
}
}
public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, component,
componentType, userId);
} finally {
current.release();
}
}
public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps,
int callingUid, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, userId);
} finally {
current.release();
}
}
public final int checkUidPermission(String permName, int uid) {
ThreadComputer current = snapshot();
try {
return current.mComputer.checkUidPermission(permName, uid);
} finally {
current.release();
}
}
public final int getPackageUidInternal(String packageName, int flags, int userId,
int callingUid) {
ThreadComputer current = live();
try {
return current.mComputer.getPackageUidInternal(packageName, flags, userId,
callingUid);
} finally {
current.release();
}
}
public final int updateFlagsForApplication(int flags, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.updateFlagsForApplication(flags, userId);
} finally {
current.release();
}
}
public final int updateFlagsForComponent(int flags, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.updateFlagsForComponent(flags, userId);
} finally {
current.release();
}
}
public final int updateFlagsForPackage(int flags, int userId) {
ThreadComputer current = live();
try {
return current.mComputer.updateFlagsForPackage(flags, userId);
} finally {
current.release();
}
}
public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
ThreadComputer current = live();
try {
return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
} finally {
current.release();
}
}
public final int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean onlyExposedExplicitly,
boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
ThreadComputer current = live();
try {
return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, onlyExposedExplicitly,
isImplicitImageCaptureIntentAndNotSetByDpc);
} finally {
current.release();
}
}
public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
ThreadComputer current = live();
try {
current.mComputer.dump(type, fd, pw, dumpState);
} finally {
current.release();
}
}
public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
ThreadComputer current = live();
try {
current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
requireFullPermission, checkShell, message);
} finally {
current.release();
}
}
public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message) {
ThreadComputer current = live();
try {
current.mComputer.enforceCrossUserPermission(callingUid, userId,
requireFullPermission, checkShell, message);
} finally {
current.release();
}
}
public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message) {
ThreadComputer current = live();
try {
current.mComputer.enforceCrossUserPermission(callingUid, userId,
requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
} finally {
current.release();
}
}
public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
String resolvedType, int flags, List query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
ThreadComputer current = live();
try {
return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
query, always, removeMatches, debug, userId, queryMayBeFiltered);
} finally {
current.release();
}
}
public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
String resolvedType, int flags, List query, boolean debug,
int userId) {
ThreadComputer current = live();
try {
return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
flags, query, debug, userId);
} finally {
current.release();
}
}
}
// Compute read-only functions, based on live data. This attribute may be modified multiple
// times during the PackageManagerService constructor but it should not be modified thereafter.
private ComputerLocked mLiveComputer;
// A lock-free cache for frequently called functions.
private volatile Computer mSnapshotComputer;
// A trampoline that directs callers to either the live or snapshot computer.
private final ComputerTracker mComputer = new ComputerTracker(this);
// If true, the snapshot is invalid (stale). The attribute is static since it may be
// set from outside classes. The attribute may be set to true anywhere, although it
// should only be set true while holding mLock. However, the attribute id guaranteed
// to be set false only while mLock and mSnapshotLock are both held.
private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
// The package manager that is using snapshots.
private static PackageManagerService sSnapshotConsumer = null;
// If true, the snapshot is corked. Do not create a new snapshot but use the live
// computer. This throttles snapshot creation during periods of churn in Package
// Manager.
private static AtomicInteger sSnapshotCorked = new AtomicInteger(0);
/**
* This class records the Computer being used by a thread and the Computer's reference
* count. There is a thread-local copy of this class.
*/
private static class ThreadComputer {
Computer mComputer = null;
int mRefCount = 0;
void acquire(Computer c) {
if (mRefCount != 0 && mComputer != c) {
throw new RuntimeException("computer mismatch, count = " + mRefCount);
}
mComputer = c;
mRefCount++;
}
void acquire() {
if (mRefCount == 0 || mComputer == null) {
throw new RuntimeException("computer acquire on empty ref count");
}
mRefCount++;
}
void release() {
if (--mRefCount == 0) {
mComputer = null;
}
}
}
private static ThreadLocal sThreadComputer = new ThreadLocal<>() {
@Override protected ThreadComputer initialValue() {
return new ThreadComputer();
}};
/**
* This lock is used to make reads from {@link #sSnapshotInvalid} and
* {@link #mSnapshotComputer} atomic inside {@code snapshotComputer()}. This lock is
* not meant to be used outside that method. This lock must be taken before
* {@link #mLock} is taken.
*/
private final Object mSnapshotLock = new Object();
/**
* The snapshot statistics. These are collected to track performance and to identify
* situations in which the snapshots are misbehaving.
*/
private final SnapshotStatistics mSnapshotStatistics;
// The snapshot disable/enable switch. An image with the flag set true uses snapshots
// and an image with the flag set false does not use snapshots.
private static final boolean SNAPSHOT_ENABLED = true;
// The default auto-cork delay for snapshots. This is 1s.
private static final long SNAPSHOT_AUTOCORK_DELAY_MS = TimeUnit.SECONDS.toMillis(1);
// The per-instance snapshot disable/enable flag. This is generally set to false in
// test instances and set to SNAPSHOT_ENABLED in operational instances.
private final boolean mSnapshotEnabled;
/**
* Return the live computer.
*/
private Computer liveComputer() {
return mLiveComputer;
}
/**
* Return the cached computer. The method will rebuild the cached computer if necessary.
* The live computer will be returned if snapshots are disabled.
*/
private Computer snapshotComputer() {
if (!mSnapshotEnabled) {
return mLiveComputer;
}
if (Thread.holdsLock(mLock)) {
// If the current thread holds mLock then it may have modified state but not
// yet invalidated the snapshot. Always give the thread the live computer.
return mLiveComputer;
} else if (sSnapshotCorked.get() > 0) {
// Snapshots are corked, which means new ones should not be built right now.
mSnapshotStatistics.corked();
return mLiveComputer;
}
synchronized (mSnapshotLock) {
// This synchronization block serializes access to the snapshot computer and
// to the code that samples mSnapshotInvalid.
Computer c = mSnapshotComputer;
if (sSnapshotInvalid.getAndSet(false) || (c == null)) {
// The snapshot is invalid if it is marked as invalid or if it is null. If it
// is null, then it is currently being rebuilt by rebuildSnapshot().
synchronized (mLock) {
// Rebuild the snapshot if it is invalid. Note that the snapshot might be
// invalidated as it is rebuilt. However, the snapshot is still
// self-consistent (the lock is being held) and is current as of the time
// this function is entered.
rebuildSnapshot();
// Guaranteed to be non-null. mSnapshotComputer is only be set to null
// temporarily in rebuildSnapshot(), which is guarded by mLock(). Since
// the mLock is held in this block and since rebuildSnapshot() is
// complete, the attribute can not now be null.
c = mSnapshotComputer;
}
}
c.use();
return c;
}
}
/**
* Rebuild the cached computer. mSnapshotComputer is temporarily set to null to block other
* threads from using the invalid computer until it is rebuilt.
*/
@GuardedBy({ "mLock", "mSnapshotLock"})
private void rebuildSnapshot() {
final long now = SystemClock.currentTimeMicro();
final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed();
mSnapshotComputer = null;
final Snapshot args = new Snapshot(Snapshot.SNAPPED);
mSnapshotComputer = new ComputerEngine(args);
final long done = SystemClock.currentTimeMicro();
mSnapshotStatistics.rebuild(now, done, hits);
}
/**
* Create a new snapshot. Used for testing only. This does collect statistics or
* update the snapshot used by other actors. It does not alter the invalidation
* flag. This method takes the mLock internally.
*/
private Computer createNewSnapshot() {
synchronized (mLock) {
final Snapshot args = new Snapshot(Snapshot.SNAPPED);
return new ComputerEngine(args);
}
}
/**
* Cork snapshots. This times out after the programmed delay.
*/
private void corkSnapshots(int multiplier) {
int corking = sSnapshotCorked.getAndIncrement();
if (TRACE_SNAPSHOTS && corking == 0) {
Log.i(TAG, "snapshot: corking goes positive");
}
Message message = mHandler.obtainMessage(SNAPSHOT_UNCORK);
mHandler.sendMessageDelayed(message, SNAPSHOT_AUTOCORK_DELAY_MS * multiplier);
}
/**
* Create a live computer
*/
private ComputerLocked createLiveComputer() {
return new ComputerLocked(new Snapshot(Snapshot.LIVE));
}
/**
* This method is called when the state of PackageManagerService changes so as to
* invalidate the current snapshot.
* @param what The {@link Watchable} that reported the change
* @hide
*/
public static void onChange(@Nullable Watchable what) {
if (TRACE_SNAPSHOTS) {
Log.i(TAG, "snapshot: onChange(" + what + ")");
}
sSnapshotInvalid.set(true);
}
/**
* Report a locally-detected change to observers. The parameter is left null,
* but it signifies that the change was detected by PackageManagerService itself.
*/
private static void onChanged() {
onChange(null);
}
class PackageHandler extends Handler {
PackageHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
case SEND_PENDING_BROADCAST: {
String packages[];
ArrayList components[];
int size = 0;
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
size = mPendingBroadcasts.size();
if (size <= 0) {
// Nothing to be done. Just return
return;
}
packages = new String[size];
components = new ArrayList[size];
uids = new int[size];
int i = 0; // filling out the above arrays
for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) {
final int packageUserId = mPendingBroadcasts.userIdAt(n);
final ArrayMap> componentsToBroadcast =
mPendingBroadcasts.packagesForUserId(packageUserId);
final int numComponents = componentsToBroadcast.size();
for (int index = 0; i < size && index < numComponents; index++) {
packages[i] = componentsToBroadcast.keyAt(index);
components[i] = componentsToBroadcast.valueAt(index);
final PackageSetting ps = mSettings.getPackageLPr(packages[i]);
uids[i] = (ps != null)
? UserHandle.getUid(packageUserId, ps.appId)
: -1;
i++;
}
}
size = i;
mPendingBroadcasts.clear();
}
// Send broadcasts
for (int i = 0; i < size; i++) {
sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
components[i], uids[i], null /* reason */);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
}
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
PostInstallData data = mRunningInstalls.get(msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
if (data != null && data.res.freezer != null) {
data.res.freezer.close();
}
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
} else if (data != null && data.args != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
handlePackagePostInstall(parentRes, killApp, virtualPreload,
didRestore, args.installSource.installerPackageName, args.observer,
args.mDataLoaderType);
// Log tracing if needed
if (args.traceMethod != null) {
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
} else if (DEBUG_INSTALL) {
// No post-install when we run restore from installExistingPackageForUser
Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
case DEFERRED_NO_KILL_POST_DELETE: {
synchronized (mInstallLock) {
InstallArgs args = (InstallArgs) msg.obj;
if (args != null) {
args.doPostDeleteLI(true);
}
}
} break;
case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
String packageName = (String) msg.obj;
if (packageName != null) {
notifyInstallObserver(packageName);
}
} break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
writeSettingsLPrTEMP();
mDirtyUsers.clear();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_RESTRICTIONS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
mSettings.writePackageRestrictionsLPr(userId);
}
mDirtyUsers.clear();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_LIST: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case CHECK_PENDING_VERIFICATION: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.isVerificationComplete()
&& !state.timeoutExtended()) {
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
final UserHandle user = params.getUser();
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
Slog.i(TAG, "Continuing with installation of " + originUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType,
user);
} else {
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, null,
params.mDataLoaderType, user);
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_REJECT);
}
if (state.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
params.handleVerificationFinished();
}
break;
}
case CHECK_PENDING_INTEGRITY_VERIFICATION: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if (state != null && !state.isIntegrityVerificationComplete()) {
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Integrity verification timed out for " + originUri);
state.setIntegrityVerificationResult(
getDefaultIntegrityVerificationResponse());
if (getDefaultIntegrityVerificationResponse()
== PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
} else {
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
if (state.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER,
"integrity_verification",
verificationId);
params.handleIntegrityVerificationFinished();
}
break;
}
case PACKAGE_VERIFIED: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if (state == null) {
Slog.w(TAG, "Verification with id " + verificationId
+ " not found."
+ " It may be invalid or overridden by integrity verification");
break;
}
final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj;
state.setVerifierResponse(response.callerUid, response.code);
if (state.isVerificationComplete()) {
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
if (state.isInstallAllowed()) {
broadcastPackageVerified(verificationId, originUri,
response.code, null, params.mDataLoaderType, params.getUser());
} else {
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
if (state.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
params.handleVerificationFinished();
}
break;
}
case INTEGRITY_VERIFICATION_COMPLETE: {
final int verificationId = msg.arg1;
final PackageVerificationState state = mPendingVerification.get(verificationId);
if (state == null) {
Slog.w(TAG, "Integrity verification with id " + verificationId
+ " not found. It may be invalid or overridden by verifier");
break;
}
final int response = (Integer) msg.obj;
final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
state.setIntegrityVerificationResult(response);
if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
Slog.i(TAG, "Integrity check passed for " + originUri);
} else {
params.setReturnCode(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
if (state.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER,
"integrity_verification",
verificationId);
params.handleIntegrityVerificationFinished();
break;
}
case INSTANT_APP_RESOLUTION_PHASE_TWO: {
InstantAppResolver.doInstantAppResolutionPhaseTwo(mContext,
mInstantAppResolverConnection,
(InstantAppRequest) msg.obj,
mInstantAppInstallerActivity,
mHandler);
break;
}
case ENABLE_ROLLBACK_STATUS: {
final int enableRollbackToken = msg.arg1;
final int enableRollbackCode = msg.arg2;
final VerificationParams params =
mPendingEnableRollback.get(enableRollbackToken);
if (params == null) {
Slog.w(TAG, "Invalid rollback enabled token "
+ enableRollbackToken + " received");
break;
}
mPendingEnableRollback.remove(enableRollbackToken);
if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.w(TAG, "Failed to enable rollback for " + originUri);
Slog.w(TAG, "Continuing with installation of " + originUri);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
params.handleRollbackEnabled();
break;
}
case ENABLE_ROLLBACK_TIMEOUT: {
final int enableRollbackToken = msg.arg1;
final int sessionId = msg.arg2;
final VerificationParams params =
mPendingEnableRollback.get(enableRollbackToken);
if (params != null) {
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.w(TAG, "Enable rollback timed out for " + originUri);
mPendingEnableRollback.remove(enableRollbackToken);
Slog.w(TAG, "Continuing with installation of " + originUri);
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
params.handleRollbackEnabled();
Intent rollbackTimeoutIntent = new Intent(
Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
rollbackTimeoutIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
sessionId);
rollbackTimeoutIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
}
break;
}
case DOMAIN_VERIFICATION: {
int messageCode = msg.arg1;
Object object = msg.obj;
mDomainVerificationManager.runMessage(messageCode, object);
break;
}
case SNAPSHOT_UNCORK: {
int corking = sSnapshotCorked.decrementAndGet();
if (TRACE_SNAPSHOTS && corking == 0) {
Log.e(TAG, "snapshot: corking goes to zero in message handler");
}
break;
}
}
}
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
final String packageName = res.name;
final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
final boolean removedBeforeUpdate = (pkgSetting == null)
|| (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath()));
if (succeeded && removedBeforeUpdate) {
Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ "could be executed");
res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED;
res.returnMsg = "Package was removed before install could complete.";
// Remove the update failed package's older resources safely now
InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
if (args != null) {
synchronized (mInstallLock) {
args.doPostDeleteLI(true);
}
}
notifyInstallObserver(res, installObserver);
return;
}
if (succeeded) {
// Clear the uid cache after we installed a new package.
mPerUidReadTimeoutsCache = null;
// Send the removed broadcasts
if (res.removedInfo != null) {
res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
: res.removedInfo != null
? res.removedInfo.installerPackageName
: null;
synchronized (mLock) {
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
int[] firstUserIds = EMPTY_INT_ARRAY;
int[] firstInstantUserIds = EMPTY_INT_ARRAY;
int[] updateUserIds = EMPTY_INT_ARRAY;
int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
final PackageSetting ps = pkgSetting;
for (int newUser : res.newUsers) {
final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
continue;
}
boolean isNew = true;
for (int origUser : res.origUsers) {
if (origUser == newUser) {
isNew = false;
break;
}
}
if (isNew) {
if (isInstantApp) {
firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
} else {
firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
}
} else {
if (isInstantApp) {
instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
} else {
updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
}
}
}
// Send installed broadcasts if the package is not a static shared lib.
if (res.pkg.getStaticSharedLibName() == null) {
mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.isSystem();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
// Send to all running apps.
final SparseArray newBroadcastAllowList;
synchronized (mLock) {
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(res.name, Process.SYSTEM_UID),
updateUserIds, mSettings.getPackagesLocked());
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, newBroadcastAllowList, null);
if (installerPackageName != null) {
// Send to the installer, even if it's not running.
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// if the required verifier is defined, but, is not the installer of record
// for the package, it gets notified
final boolean notifyVerifier = mRequiredVerifierPackage != null
&& !mRequiredVerifierPackage.equals(installerPackageName);
if (notifyVerifier) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// If package installer is defined, notify package installer about new
// app installed
if (mRequiredInstallerPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
mRequiredInstallerPackage, null /*finishedReceiver*/,
firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// Send replaced for users that don't see the package for the first time
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList,
null);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
}
if (notifyVerifier) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/, null);
}
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds,
null /*broadcastAllowList*/,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
.toBundle());
} else if (launchedForRestore && !res.pkg.isSystem()) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
+ " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
}
sendFirstLaunchBroadcast(packageName, installerPackage,
firstUserIds, firstInstantUserIds);
}
// Send broadcast package appeared if external for all users
if (res.pkg.isExternalStorage()) {
if (!update) {
final StorageManager storage = mInjector.getSystemService(
StorageManager.class);
VolumeInfo volume =
storage.findVolumeByUuid(
res.pkg.getStorageUuid().toString());
int packageExternalStorageType =
getPackageExternalStorageType(volume, res.pkg.isExternalStorage());
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
FrameworkStatsLog.write(
FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
packageExternalStorageType, packageName);
}
}
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
}
final int[] uidArray = new int[]{res.pkg.getUid()};
ArrayList pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
} else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
int[] allUsers = mInjector.getUserManagerService().getUserIds();
for (int i = 0; i < res.libraryConsumers.size(); i++) {
AndroidPackage pkg = res.libraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(), null);
}
}
// Work that needs to happen on first install within each user
if (firstUserIds != null && firstUserIds.length > 0) {
for (int userId : firstUserIds) {
restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
pkgSetting.getInstallReason(userId), userId);
}
}
if (allNewUsers && !update) {
notifyPackageAdded(packageName, res.uid);
} else {
notifyPackageChanged(packageName, res.uid);
}
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
if (args != null) {
if (!killApp) {
// If we didn't kill the app, defer the deletion of code/resource files, since
// they may still be in use by the running application. This mitigates problems
// in cases where resources or code is loaded by a new Activity before
// ApplicationInfo changes have propagated to all application threads.
scheduleDeferredNoKillPostDelete(args);
} else {
synchronized (mInstallLock) {
args.doPostDeleteLI(true);
}
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
// and not block here.
VMRuntime.getRuntime().requestConcurrentGC();
}
// Notify DexManager that the package was installed for new users.
// The updated users should already be indexed and the package code paths
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an
// uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
}
}
}
final boolean deferInstallObserver = succeeded && update && !killApp;
if (deferInstallObserver) {
scheduleDeferredNoKillInstallObserver(res, installObserver);
} else {
notifyInstallObserver(res, installObserver);
}
}
@Override
public void notifyPackagesReplacedReceived(String[] packages) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
for (String packageName : packages) {
final boolean filterApp;
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
filterApp = shouldFilterApplicationLocked(ps, callingUid, callingUserId);
}
if (!filterApp) {
notifyInstallObserver(packageName);
}
}
}
private void notifyInstallObserver(String packageName) {
Pair pair =
mNoKillInstallObservers.remove(packageName);
if (pair != null) {
notifyInstallObserver(pair.first, pair.second);
}
}
private void notifyInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(info);
installObserver.onPackageInstalled(info.name, info.returnCode,
info.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
}
private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
String packageName = info.pkg.getPackageName();
mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
@Override
public void requestChecksums(@NonNull String packageName, boolean includeSplits,
@Checksum.TypeMask int optional,
@Checksum.TypeMask int required, @Nullable List trustedInstallers,
@NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {
requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(),
mInjector.getBackgroundHandler());
}
private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
@Checksum.TypeMask int optional, @Checksum.TypeMask int required,
@Nullable List trustedInstallers,
@NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
@NonNull Executor executor, @NonNull Handler handler) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(onChecksumsReadyListener);
Objects.requireNonNull(executor);
Objects.requireNonNull(handler);
final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
Binder.getCallingUid(), userId);
if (applicationInfo == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
}
final InstallSourceInfo installSourceInfo = getInstallSourceInfo(packageName);
final String installerPackageName =
installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null;
List> filesToChecksum = new ArrayList<>();
// Adding base split.
filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir)));
// Adding other splits.
if (includeSplits && applicationInfo.splitNames != null) {
for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) {
filesToChecksum.add(Pair.create(applicationInfo.splitNames[i],
new File(applicationInfo.splitSourceDirs[i])));
}
}
final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
trustedInstallers) : null;
executor.execute(() -> {
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
() -> mInjector.getIncrementalManager(),
() -> mPmInternal);
ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
trustedCerts, onChecksumsReadyListener, injector);
});
}
private static @NonNull Certificate[] decodeCertificates(@NonNull List certs) {
try {
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final Certificate[] result = new Certificate[certs.size()];
for (int i = 0, size = certs.size(); i < size; ++i) {
final InputStream is = new ByteArrayInputStream((byte[]) certs.get(i));
final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
result[i] = cert;
}
return result;
} catch (CertificateException e) {
throw ExceptionUtils.propagate(e);
}
}
/**
* Gets the type of the external storage a package is installed on.
* @param packageVolume The storage volume of the package.
* @param packageIsExternal true if the package is currently installed on
* external/removable/unprotected storage.
* @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the
* corresponding {@link StorageEnums} storage type value if it is.
* corresponding {@link StorageEnums} storage type value if it is.
*/
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
if (packageVolume != null) {
DiskInfo disk = packageVolume.getDisk();
if (disk != null) {
if (disk.isSd()) {
return StorageEnums.SD_CARD;
}
if (disk.isUsb()) {
return StorageEnums.USB;
}
if (packageIsExternal) {
return StorageEnums.OTHER;
}
}
}
return StorageEnums.UNKNOWN;
}
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
if (vol.type == VolumeInfo.TYPE_PRIVATE) {
if (vol.state == VolumeInfo.STATE_MOUNTED) {
final String volumeUuid = vol.getFsUuid();
// Clean up any users or apps that were removed or recreated
// while this volume was missing
mUserManager.reconcileUsers(volumeUuid);
reconcileApps(volumeUuid);
// Clean up any install sessions that expired or were
// cancelled while this volume was missing
mInstallerService.onPrivateVolumeMounted(volumeUuid);
loadPrivatePackages(vol);
} else if (vol.state == VolumeInfo.STATE_EJECTING) {
unloadPrivatePackages(vol);
}
}
}
@Override
public void onVolumeForgotten(String fsUuid) {
if (TextUtils.isEmpty(fsUuid)) {
Slog.e(TAG, "Forgetting internal storage is probably a mistake; ignoring");
return;
}
// Remove any apps installed on the forgotten volume
synchronized (mLock) {
final List packages = mSettings.getVolumePackagesLPr(fsUuid);
for (PackageSetting ps : packages) {
Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten");
deletePackageVersioned(new VersionedPackage(ps.name,
PackageManager.VERSION_CODE_HIGHEST),
new LegacyPackageDeleteObserver(null).getBinder(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS);
// Try very hard to release any references to this package
// so we don't risk the system server being killed due to
// open FDs
AttributeCache.instance().removePackage(ps.name);
}
mSettings.onVolumeForgotten(fsUuid);
writeSettingsLPrTEMP();
}
}
};
Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
switch (res.returnCode) {
case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
extras = new Bundle();
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
res.origPermission);
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
res.origPackage);
break;
}
case PackageManager.INSTALL_SUCCEEDED: {
extras = new Bundle();
extras.putBoolean(Intent.EXTRA_REPLACING,
res.removedInfo != null && res.removedInfo.removedPackage != null);
break;
}
}
return extras;
}
void scheduleWriteSettingsLocked() {
// We normally invalidate when we write settings, but in cases where we delay and
// coalesce settings writes, this strategy would have us invalidate the cache too late.
// Invalidating on schedule addresses this problem.
invalidatePackageInfoCache();
if (!mHandler.hasMessages(WRITE_SETTINGS)) {
mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
}
}
void scheduleWritePackageListLocked(int userId) {
invalidatePackageInfoCache();
if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST);
msg.arg1 = userId;
mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
}
}
void scheduleWritePackageRestrictionsLocked(UserHandle user) {
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
scheduleWritePackageRestrictionsLocked(userId);
}
void scheduleWritePackageRestrictionsLocked(int userId) {
invalidatePackageInfoCache();
final int[] userIds = (userId == UserHandle.USER_ALL)
? mUserManager.getUserIds() : new int[]{userId};
for (int nextUserId : userIds) {
if (!mUserManager.exists(nextUserId)) return;
mDirtyUsers.add(nextUserId);
if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
}
}
}
public static PackageManagerService main(Context context, Installer installer,
@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
t.traceBegin("create package manager");
final PackageManagerTracedLock lock = new PackageManagerTracedLock();
final Object installLock = new Object();
HandlerThread backgroundThread = new HandlerThread("PackageManagerBg");
backgroundThread.start();
Handler backgroundHandler = new Handler(backgroundThread.getLooper());
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
backgroundHandler,
SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) -> PermissionManagerService.create(context,
i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context, onlyCore),
lock),
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
(i, pm) -> AppsFilter.create(pm.mPmInternal, i),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
(i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(),
i.getInstaller(), i.getInstallLock()),
(i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(),
i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
(i, pm) -> (IncrementalManager)
i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
(i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
() -> LocalServices.getService(UserManagerInternal.class)),
(i, pm) -> new DisplayMetrics(),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
i.getDisplayMetrics(), pm.mCacheDir,
pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* scanningPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
// Prepare a supplier of package parser for the staging manager to parse apex file
// during the staging installation.
(i, pm) -> new PackageInstallerService(
i.getContext(), pm, i::getScanningPackageParser),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
(i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
thread.start();
return pm.new PackageHandler(thread.getLooper());
},
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService);
if (Build.VERSION.SDK_INT <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
Build.VERSION.INCREMENTAL);
t.traceEnd(); // "create package manager"
final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
synchronized (m.mInstallLock) {
final AndroidPackage pkg;
final PackageSetting ps;
final SharedUserSetting sharedUser;
final String oldSeInfo;
synchronized (m.mLock) {
ps = m.mSettings.getPackageLPr(packageName);
if (ps == null) {
Slog.e(TAG, "Failed to find package setting " + packageName);
return;
}
pkg = ps.pkg;
sharedUser = ps.getSharedUser();
oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
}
if (pkg == null) {
Slog.e(TAG, "Failed to find package " + packageName);
return;
}
final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
m.mInjector.getCompatibility());
if (!newSeInfo.equals(oldSeInfo)) {
Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
+ oldSeInfo + " to: " + newSeInfo);
ps.getPkgState().setOverrideSeInfo(newSeInfo);
m.prepareAppDataAfterInstallLIF(pkg);
}
}
};
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
selinuxChangeListener);
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES,
selinuxChangeListener);
m.installWhitelistedSystemPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
/** Install/uninstall system packages for all users based on their user-type, as applicable. */
private void installWhitelistedSystemPackages() {
synchronized (mLock) {
final boolean scheduleWrite = mUserManager.installWhitelistedSystemPackages(
isFirstBoot(), isDeviceUpgrading(), mExistingPackages);
if (scheduleWrite) {
scheduleWritePackageRestrictionsLocked(UserHandle.USER_ALL);
scheduleWriteSettingsLocked();
}
}
}
/**
* Requests that files preopted on a secondary system partition be copied to the data partition
* if possible. Note that the actual copying of the files is accomplished by init for security
* reasons. This simply requests that the copy takes place and awaits confirmation of its
* completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
*/
private static void requestCopyPreoptedFiles(Injector injector) {
final int WAIT_TIME_MS = 100;
final String CP_PREOPT_PROPERTY = "sys.cppreopt";
if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
// We will wait for up to 100 seconds.
final long timeStart = SystemClock.uptimeMillis();
final long timeEnd = timeStart + 100 * 1000;
long timeNow = timeStart;
while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
try {
Thread.sleep(WAIT_TIME_MS);
} catch (InterruptedException e) {
// Do nothing
}
timeNow = SystemClock.uptimeMillis();
if (timeNow > timeEnd) {
SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
Slog.wtf(TAG, "cppreopt did not finish!");
break;
}
}
Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms");
}
}
@VisibleForTesting
public static class ScanPartition extends SystemPartition {
@ScanFlags
public final int scanFlag;
public ScanPartition(@NonNull SystemPartition partition) {
super(partition);
scanFlag = scanFlagForPartition(partition);
}
/**
* Creates a partition containing the same folders as the original partition but with a
* different root folder. The new partition will include the scan flags of the original
* partition along with any specified additional scan flags.
*/
public ScanPartition(@NonNull File folder, @NonNull ScanPartition original,
@ScanFlags int additionalScanFlag) {
super(folder, original);
this.scanFlag = original.scanFlag | additionalScanFlag;
}
private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) {
switch (partition.type) {
case PackagePartitions.PARTITION_SYSTEM:
return 0;
case PackagePartitions.PARTITION_VENDOR:
return SCAN_AS_VENDOR;
case PackagePartitions.PARTITION_ODM:
return SCAN_AS_ODM;
case PackagePartitions.PARTITION_OEM:
return SCAN_AS_OEM;
case PackagePartitions.PARTITION_PRODUCT:
return SCAN_AS_PRODUCT;
case PackagePartitions.PARTITION_SYSTEM_EXT:
return SCAN_AS_SYSTEM_EXT;
default:
throw new IllegalStateException("Unable to determine scan flag for "
+ partition.getFolder());
}
}
@Override
public String toString() {
return getFolder().getAbsolutePath() + ":" + scanFlag;
}
}
// Link watchables to the class
private void registerObserver() {
mPackages.registerObserver(mWatcher);
mSharedLibraries.registerObserver(mWatcher);
mStaticLibsByDeclaringPackage.registerObserver(mWatcher);
mInstrumentation.registerObserver(mWatcher);
mWebInstantAppsDisabled.registerObserver(mWatcher);
mAppsFilter.registerObserver(mWatcher);
mInstantAppRegistry.registerObserver(mWatcher);
mSettings.registerObserver(mWatcher);
mIsolatedOwners.registerObserver(mWatcher);
mComponentResolver.registerObserver(mWatcher);
// If neither "build" attribute is true then this may be a mockito test, and verification
// can fail as a false positive.
Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild));
}
/**
* A extremely minimal constructor designed to start up a PackageManagerService instance for
* testing.
*
* It is assumed that all methods under test will mock the internal fields and thus
* none of the initialization is needed.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public PackageManagerService(@NonNull Injector injector, @NonNull TestParams testParams) {
mInjector = injector;
mInjector.bootstrap(this);
mAppsFilter = injector.getAppsFilter();
mComponentResolver = injector.getComponentResolver();
mContext = injector.getContext();
mInstaller = injector.getInstaller();
mInstallLock = injector.getInstallLock();
mLock = injector.getLock();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mUserManager = injector.getUserManagerService();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mHandler = injector.getHandler();
mApexManager = testParams.apexManager;
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mDefParseFlags = testParams.defParseFlags;
mDefaultAppProvider = testParams.defaultAppProvider;
mLegacyPermissionManager = testParams.legacyPermissionManagerInternal;
mDexManager = testParams.dexManager;
mDirsToScanAsSystem = testParams.dirsToScanAsSystem;
mFactoryTest = testParams.factoryTest;
mIncrementalManager = testParams.incrementalManager;
mInstallerService = testParams.installerService;
mInstantAppRegistry = testParams.instantAppRegistry;
mInstantAppResolverConnection = testParams.instantAppResolverConnection;
mInstantAppResolverSettingsComponent = testParams.instantAppResolverSettingsComponent;
mIsPreNMR1Upgrade = testParams.isPreNmr1Upgrade;
mIsPreNUpgrade = testParams.isPreNupgrade;
mIsPreQUpgrade = testParams.isPreQupgrade;
mIsUpgrade = testParams.isUpgrade;
mMetrics = testParams.Metrics;
mModuleInfoProvider = testParams.moduleInfoProvider;
mMoveCallbacks = testParams.moveCallbacks;
mOnlyCore = testParams.onlyCore;
mOverlayConfig = testParams.overlayConfig;
mPackageDexOptimizer = testParams.packageDexOptimizer;
mPackageParserCallback = testParams.packageParserCallback;
mPendingBroadcasts = testParams.pendingPackageBroadcasts;
mPmInternal = testParams.pmInternal;
mTestUtilityService = testParams.testUtilityService;
mProcessLoggingHandler = testParams.processLoggingHandler;
mProtectedPackages = testParams.protectedPackages;
mSeparateProcesses = testParams.separateProcesses;
mViewCompiler = testParams.viewCompiler;
mRequiredVerifierPackage = testParams.requiredVerifierPackage;
mRequiredInstallerPackage = testParams.requiredInstallerPackage;
mRequiredUninstallerPackage = testParams.requiredUninstallerPackage;
mRequiredPermissionControllerPackage = testParams.requiredPermissionControllerPackage;
mSetupWizardPackage = testParams.setupWizardPackage;
mStorageManagerPackage = testParams.storageManagerPackage;
mDefaultTextClassifierPackage = testParams.defaultTextClassifierPackage;
mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
mRetailDemoPackage = testParams.retailDemoPackage;
mRecentsPackage = testParams.recentsPackage;
mDocumenterPackage = testParams.documenterPackage;
mConfiguratorPackage = testParams.configuratorPackage;
mAppPredictionServicePackage = testParams.appPredictionServicePackage;
mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
mResolveComponentName = testParams.resolveComponentName;
// Disable snapshots in this instance of PackageManagerService, which is only used
// for testing. The instance still needs a live computer. The snapshot computer
// is set to null since it must never be used by this instance.
mSnapshotEnabled = false;
mLiveComputer = createLiveComputer();
mSnapshotComputer = null;
mSnapshotStatistics = null;
mPackages.putAll(testParams.packages);
mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
mSdkVersion = testParams.sdkVersion;
mSystemWrapper = testParams.systemWrapper;
mAppInstallDir = testParams.appInstallDir;
mAppLib32InstallDir = testParams.appLib32InstallDir;
mIsEngBuild = testParams.isEngBuild;
mIsUserDebugBuild = testParams.isUserDebugBuild;
mIncrementalVersion = testParams.incrementalVersion;
invalidatePackageInfoCache();
}
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
mIsEngBuild = isEngBuild;
mIsUserDebugBuild = isUserDebugBuild;
mSdkVersion = sdkVersion;
mIncrementalVersion = incrementalVersion;
mInjector = injector;
mInjector.getSystemWrapper().disablePackageCaches();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
mPendingBroadcasts = new PendingPackageBroadcasts();
mInjector.bootstrap(this);
mLock = injector.getLock();
mInstallLock = injector.getInstallLock();
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
mSystemWrapper = injector.getSystemWrapper();
mContext = injector.getContext();
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = injector.getDisplayMetrics();
mInstaller = injector.getInstaller();
mEnableFreeCacheV2 = SystemProperties.getBoolean("fw.free_cache_v2", true);
// Create sub-components that provide services / data. Order here is important.
t.traceBegin("createSubComponents");
// Expose private service for system components to use.
mPmInternal = new PackageManagerInternalImpl();
LocalServices.addService(TestUtilityService.class, this);
mTestUtilityService = LocalServices.getService(TestUtilityService.class);
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
mUserManager = injector.getUserManagerService();
mComponentResolver = injector.getComponentResolver();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mIncrementalManager = mInjector.getIncrementalManager();
mDefaultAppProvider = mInjector.getDefaultAppProvider();
mLegacyPermissionManager = mInjector.getLegacyPermissionManagerInternal();
PlatformCompat platformCompat = mInjector.getCompatibility();
mPackageParserCallback = new PackageParser2.Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
return platformCompat.isChangeEnabled(changeId, appInfo);
}
@Override
public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
};
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
t.traceBegin("addSharedUsers");
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
t.traceEnd();
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = ParsingPackageUtils.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
Slog.w(TAG, "Running with debug.separate_processes: "
+ separateProcesses);
}
} else {
mDefParseFlags = 0;
mSeparateProcesses = null;
}
mPackageDexOptimizer = injector.getPackageDexOptimizer();
mDexManager = injector.getDexManager();
mArtManagerService = injector.getArtManagerService();
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = injector.getViewCompiler();
mContext.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
t.traceBegin("get system config");
SystemConfig systemConfig = injector.getSystemConfig();
mAvailableFeatures = systemConfig.getAvailableFeatures();
t.traceEnd();
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = injector.getApexManager();
mAppsFilter = mInjector.getAppsFilter();
final List scanPartitions = new ArrayList<>();
final List activeApexInfos = mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
scanPartitions.add(scanPartition);
}
}
mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
mDirsToScanAsSystem = new ArrayList<>();
mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
mDirsToScanAsSystem.addAll(scanPartitions);
Slog.d(TAG, "Directories scanned as system partitions: " + mDirsToScanAsSystem);
mAppInstallDir = new File(Environment.getDataDirectory(), "app");
mAppLib32InstallDir = getAppLib32InstallDir();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mDomainVerificationManager.setConnection(mDomainVerificationConnection);
synchronized (mLock) {
// Create the computer as soon as the state objects have been installed. The
// cached computer is the same as the live computer until the end of the
// constructor, at which time the invalidation method updates it. The cache is
// corked initially to ensure a cached computer is not built until the end of the
// constructor.
mSnapshotStatistics = new SnapshotStatistics();
sSnapshotConsumer = this;
sSnapshotCorked.set(1);
sSnapshotInvalid.set(true);
mLiveComputer = createLiveComputer();
mSnapshotComputer = null;
mSnapshotEnabled = SNAPSHOT_ENABLED;
registerObserver();
}
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
mHandler = injector.getHandler();
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
ArrayMap libConfig
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
addBuiltInSharedLibraryLocked(libConfig.valueAt(i));
}
// Now that we have added all the libraries, iterate again to add dependency
// information IFF their dependencies are added.
long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED;
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
final int dependencyCount = entry.dependencies.length;
for (int j = 0; j < dependencyCount; j++) {
final SharedLibraryInfo dependency =
getSharedLibraryInfoLPr(entry.dependencies[j], undefinedVersion);
if (dependency != null) {
getSharedLibraryInfoLPr(name, undefinedVersion).addDependency(dependency);
}
}
}
SELinuxMMAC.readInstallPolicy();
t.traceBegin("loadFallbacks");
FallbackCategoryProvider.loadFallbacks();
t.traceEnd();
t.traceBegin("read user settings");
mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
/* excludePreCreated= */ false));
t.traceEnd();
mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
mPermissionManager.readLegacyPermissionStateTEMP();
if (!mOnlyCore && mFirstBoot) {
requestCopyPreoptedFiles(mInjector);
}
String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivityName);
}
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath == null) {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath == null) {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade =
!buildFingerprint.equals(ver.fingerprint);
if (mIsUpgrade) {
PackageManagerServiceUtils.logCriticalInfo(Log.INFO,
"Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
}
// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// When upgrading from pre-N, we need to handle package extraction like first boot,
// as there is no profiling data available.
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
final WatchedArrayMap packageSettings =
mSettings.getPackagesLocked();
// Save the names of pre-existing packages prior to scanning, so we can determine
// which system packages are completely new due to an upgrade.
if (isDeviceUpgrading()) {
mExistingPackages = new ArraySet<>(packageSettings.size());
for (PackageSetting ps : packageSettings.values()) {
mExistingPackages.add(ps.name);
}
}
mCacheDir = preparePackageParserCache(mIsEngBuild);
// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
if (mIsUpgrade || mFirstBoot) {
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}
final int systemParseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
PackageParser2 packageParser = injector.getScanningCachingPackageParser();
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Prepare apex package info before scanning APKs, these information are needed when
// scanning apk in apex.
mApexManager.scanApexPackagesTraced(packageParser, executorService);
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
// any apps.)
// For security and version matching reason, only consider overlay packages if they
// reside in the right directory.
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, systemParseFlags,
systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
if (!mPackages.containsKey("android")) {
throw new IllegalStateException(
"Failed to load frameworks package; check log for warnings");
}
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
mOverlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPmInternal.forEachPackage(
pkg -> consumer.accept(pkg, pkg.isSystem())));
// Prune any system packages that no longer exist.
final List possiblyDeletedUpdatedSystemApps = new ArrayList<>();
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List stubSystemApps = new ArrayList<>();
final int[] userIds = mUserManager.getUserIds();
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
final int numPackages = mPackages.size();
for (int index = 0; index < numPackages; index++) {
final AndroidPackage pkg = mPackages.valueAt(index);
if (pkg.isStub()) {
stubSystemApps.add(pkg.getPackageName());
}
}
// Iterates PackageSettings in reversed order because the item could be removed
// during the iteration.
for (int index = packageSettings.size() - 1; index >= 0; index--) {
final PackageSetting ps = packageSettings.valueAt(index);
/*
* If this is not a system app, it can't be a
* disable system app.
*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
final AndroidPackage scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN,
"Expecting better updated system app for " + ps.name
+ "; removing system app. Last known"
+ " codePath=" + ps.getPathString()
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.getPath());
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; it's data will be wiped");
removePackageDataLIF(ps, userIds, null, 0, false);
} else {
// we still have a disabled system package, but, it still might have
// been removed. check the code path still exists and check there's
// still a package. the latter can happen if an OTA keeps the same
// code path, but, changes the package name.
final PackageSetting disabledPs =
mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
|| disabledPs.pkg == null) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
} else {
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
}
}
}
}
final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
final long systemScanTime = SystemClock.uptimeMillis() - startTime;
final int systemPackagesCount = mPackages.size();
Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ " ms, packageCount: " + systemPackagesCount
+ " , timePerPackage: "
+ (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ " , cached: " + cachedSystemApps);
if (mIsUpgrade && systemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
systemScanTime / systemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
packageParser.close();
List unfinishedTasks = executorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
if (!mOnlyCore) {
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final AndroidPackage pkg = mPackages.get(packageName);
final String msg;
// remove from the disabled system list; do this first so any future
// scans of this package are performed without this state
mSettings.removeDisabledSystemPackageLPw(packageName);
if (pkg == null) {
// should have found an update, but, we didn't; remove everything
msg = "Updated system package " + packageName
+ " no longer exists; removing its data";
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
// found an update; revoke system privileges
msg = "Updated system package " + packageName
+ " no longer exists; rescanning package on data";
// NOTE: We don't do anything special if a stub is removed from the
// system image. But, if we were [like removing the uncompressed
// version from the /data partition], this is where it'd be done.
// remove the package from the system and re-scan it without any
// special privileges
removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
}
}
// one final check. if we still have a package setting [ie. it was
// previously scanned and known to the system], but, we don't have
// a package [ie. there was an error scanning it from the /data
// partition], completely remove the package data.
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && mPackages.get(packageName) == null) {
removePackageDataLIF(ps, userIds, null, 0, false);
}
logCriticalInfo(Log.WARN, msg);
}
/*
* Make sure all system apps that we expected to appear on
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
@ParseFlags int reparseFlags = 0;
@ScanFlags int rescanFlags = 0;
for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i1);
if (partition.containsPrivApp(scanFile)) {
reparseFlags = systemParseFlags;
rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
| partition.scanFlag;
break;
}
if (partition.containsApp(scanFile)) {
reparseFlags = systemParseFlags;
rescanFlags = systemScanFlags | partition.scanFlag;
break;
}
}
if (rescanFlags == 0) {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
continue;
}
mSettings.enableSystemPackageLPw(packageName);
try {
final AndroidPackage newPkg = scanPackageTracedLI(
scanFile, reparseFlags, rescanFlags, 0, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
}
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
installSystemStubPackages(stubSystemApps, scanFlags);
final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- cachedSystemApps;
final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
final int dataPackagesCount = mPackages.size() - systemPackagesCount;
Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ " ms, packageCount: " + dataPackagesCount
+ " , timePerPackage: "
+ (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ " , cached: " + cachedNonSystemApps);
if (mIsUpgrade && dataPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
dataScanTime / dataPackagesCount);
//CHECKSTYLE:OFF IndentationCheck
}
}
mExpectingBetter.clear();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageNameImpl();
mComponentResolver.fixProtectedFilterPriorities();
mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName();
mSystemTextClassifierPackageName = getSystemTextClassifierPackageName();
mDocumenterPackage = getDocumenterPackageName();
mConfiguratorPackage = getDeviceConfiguratorPackageName();
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mRetailDemoPackage = getRetailDemoPackageName();
mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
mRecentsPackage = getRecentsPackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
final List changedAbiCodePath =
applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
setting.packages, null /*scannedPackage*/));
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
try {
mInstaller.rmdex(codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
} catch (InstallerException ignored) {
}
}
}
// Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
// SELinux domain.
setting.fixSeInfoLocked();
setting.updateProcesses();
}
// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.read(packageSettings);
mCompilerStats.read();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
// If the build fingerprint has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
if (mIsUpgrade) {
Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to "
+ Build.FINGERPRINT + "; regranting permissions for internal storage");
}
mPermissionManager.onStorageVolumeMounted(
StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(user.id);
}
}
// Prepare storage for system user really early during boot,
// since core system apps like SettingsProvider and SystemUI
// can't wait for user to start
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
List deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
true /* onlyCoreApps */);
mPrepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
Trace.TRACE_TAG_PACKAGE_MANAGER);
traceLog.traceBegin("AppDataFixup");
try {
mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
} catch (InstallerException e) {
Slog.w(TAG, "Trouble fixing GIDs", e);
}
traceLog.traceEnd();
traceLog.traceBegin("AppDataPrepare");
if (deferPackages == null || deferPackages.isEmpty()) {
return;
}
int count = 0;
final Installer.Batch batch = new Installer.Batch();
for (String pkgName : deferPackages) {
AndroidPackage pkg = null;
synchronized (mLock) {
PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
pkg = ps.pkg;
}
}
if (pkg != null) {
prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags,
true /* maybeMigrateAppData */);
count++;
}
}
synchronized (mInstallLock) {
executeBatchLI(batch);
}
traceLog.traceEnd();
Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
}, "prepareAppData");
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
// Note that we do *not* clear the application profiles. These remain valid
// across OTAs and are used to drive profile verification (post OTA) and
// profile compilation (without waiting to collect a fresh set of profiles).
if (mIsUpgrade && !mOnlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < packageSettings.size(); i++) {
final PackageSetting ps = packageSettings.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
// Legacy existing (installed before Q) non-system apps to hide
// their icons in launcher.
if (!mOnlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
int size = packageSettings.size();
for (int i = 0; i < size; i++) {
final PackageSetting ps = packageSettings.valueAt(i);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
UserHandle.USER_SYSTEM);
}
}
// clear only after permissions and other defaults have been updated
mPromoteSystemApps = false;
// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader
t.traceBegin("write settings");
writeSettingsLPrTEMP();
t.traceEnd();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
if (!mOnlyCore) {
mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mRequiredUninstallerPackage = getRequiredUninstallerLPr();
ComponentName intentFilterVerifierComponent =
getIntentFilterVerifierComponentNameLPr();
ComponentName domainVerificationAgent =
getDomainVerificationAgentComponentNameLPr();
DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy(
intentFilterVerifierComponent, domainVerificationAgent, mContext,
mDomainVerificationManager, mDomainVerificationManager.getCollector(),
mDomainVerificationConnection);
mDomainVerificationManager.setProxy(domainVerificationProxy);
mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
SharedLibraryInfo.VERSION_UNDEFINED);
} else {
mRequiredVerifierPackage = null;
mRequiredInstallerPackage = null;
mRequiredUninstallerPackage = null;
mServicesExtensionPackageName = null;
mSharedSystemSharedLibraryPackageName = null;
}
// PermissionController hosts default permission granting and role management, so it's a
// critical part of the core system.
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
mSettings.setPermissionControllerVersion(
getPackageInfo(mRequiredPermissionControllerPackage, 0,
UserHandle.USER_SYSTEM).getLongVersionCode());
// Initialize InstantAppRegistry's Instant App list for all users.
for (AndroidPackage pkg : mPackages.values()) {
if (pkg.isSystem()) {
continue;
}
for (int userId : userIds) {
final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
continue;
}
mInstantAppRegistry.addInstantAppLPw(userId, ps.appId);
}
}
mInstallerService = mInjector.getPackageInstallerService();
final ComponentName instantAppResolverComponent = getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
}
mInstantAppResolverConnection =
mInjector.getInstantAppResolverConnection(instantAppResolverComponent);
mInstantAppResolverSettingsComponent =
getInstantAppResolverSettingsLPr(instantAppResolverComponent);
} else {
mInstantAppResolverConnection = null;
mInstantAppResolverSettingsComponent = null;
}
updateInstantAppInstallerLocked(null);
// Read and update the usage of dex files.
// Do this at the end of PM init so that all the packages have their
// data directory reconciled.
// At this point we know the code paths of the packages, so we can validate
// the disk file and build the internal cache.
// The usage file is expected to be small so loading and verifying it
// should take a fairly small time compare to the other activities (e.g. package
// scanning).
final Map> userPackages = new HashMap<>();
for (int userId : userIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
if (mIsUpgrade) {
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
SystemClock.uptimeMillis() - startTime);
}
// Rebild the live computer since some attributes have been rebuilt.
mLiveComputer = createLiveComputer();
} // synchronized (mLock)
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck
mModuleInfoProvider = mInjector.getModuleInfoProvider();
mInjector.getSystemWrapper().enablePackageCaches();
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
t.traceBegin("GC");
VMRuntime.getRuntime().requestConcurrentGC();
t.traceEnd();
// The initial scanning above does many calls into installd while
// holding the mPackages lock, but we're mostly interested in yelling
// once we have a booted system.
mInstaller.setWarnIfHeld(mLock);
ParsingPackageUtils.readConfigUseRoundIcon(mContext.getResources());
mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
Slog.i(TAG, "Fix for b/169414761 is applied");
}
/**
* Uncompress and install stub applications.
* In order to save space on the system partition, some applications are shipped in a
* compressed form. In addition the compressed bits for the full application, the
* system image contains a tiny stub comprised of only the Android manifest.
*
During the first boot, attempt to uncompress and install the full application. If
* the application can't be installed for any reason, disable the stub and prevent
* uncompressing the full application during future boots.
*
In order to forcefully attempt an installation of a full application, go to app
* settings and enable the application.
*/
private void installSystemStubPackages(@NonNull List systemStubPackageNames,
@ScanFlags int scanFlags) {
for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
final String packageName = systemStubPackageNames.get(i);
// skip if the system package is already disabled
if (mSettings.isDisabledSystemPackageLPr(packageName)) {
systemStubPackageNames.remove(i);
continue;
}
// skip if the package isn't installed (?!); this should never happen
final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
systemStubPackageNames.remove(i);
continue;
}
// skip if the package has been disabled by the user
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
systemStubPackageNames.remove(i);
continue;
}
}
// install the package to replace the stub on /system
try {
installStubPackageLI(pkg, 0, scanFlags);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
UserHandle.USER_SYSTEM, "android");
systemStubPackageNames.remove(i);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
}
// any failed attempt to install the package will be cleaned up later
}
// disable any stub still left; these failed to install the full application
for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
final String pkgName = systemStubPackageNames.get(i);
final PackageSetting ps = mSettings.getPackageLPr(pkgName);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
}
}
/**
* Extract, install and enable a stub package.
* If the compressed file can not be extracted / installed for any reason, the stub
* APK will be installed and the package will be disabled. To recover from this situation,
* the user will need to go into system settings and re-enable the package.
*/
private boolean enableCompressedPackage(AndroidPackage stubPkg,
@NonNull PackageSetting stubPkgSetting) {
final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE;
synchronized (mInstallLock) {
final AndroidPackage pkg;
try (PackageFreezer freezer =
freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
synchronized (mLock) {
prepareAppDataAfterInstallLIF(pkg);
try {
updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
Collections.unmodifiableMap(mPackages));
} catch (PackageManagerException e) {
Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
mPermissionManager.onPackageInstalled(pkg,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
UserHandle.USER_ALL);
writeSettingsLPrTEMP();
}
} catch (PackageManagerException e) {
// Whoops! Something went very wrong; roll back to the stub and disable the package
try (PackageFreezer freezer =
freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
synchronized (mLock) {
// NOTE: Ensure the system package is enabled; even for a compressed stub.
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
installPackageFromSystemLIF(stubPkg.getPath(),
mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/,
true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
pme);
} finally {
// Disable the package; the stub by itself is not runnable
synchronized (mLock) {
final PackageSetting stubPs = mSettings.getPackageLPr(
stubPkg.getPackageName());
if (stubPs != null) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
writeSettingsLPrTEMP();
}
}
return false;
}
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
| FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
mDexManager.notifyPackageUpdated(pkg.getPackageName(),
pkg.getBaseApkPath(), pkg.getSplitCodePaths());
}
return true;
}
private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags)
throws PackageManagerException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
}
// uncompress the binary to its eventual destination on /data
final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
if (scanFile == null) {
throw new PackageManagerException(
"Unable to decompress stub at " + stubPkg.getPath());
}
synchronized (mLock) {
mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
}
removePackageLI(stubPkg, true /*chatty*/);
try {
return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
// Remove the failed install
removeCodePathLI(scanFile);
throw e;
}
}
/**
* Decompresses the given package on the system image onto
* the /data partition.
* @return The directory the package was decompressed into. Otherwise, {@code null}.
*/
private File decompressPackage(String packageName, String codePath) {
final File[] compressedFiles = getCompressedFiles(codePath);
if (compressedFiles == null || compressedFiles.length == 0) {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "No files to decompress: " + codePath);
}
return null;
}
final File dstCodePath =
getNextCodePath(Environment.getDataAppDirectory(null), packageName);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
makeDirRecursive(dstCodePath, 0755);
for (File srcFile : compressedFiles) {
final String srcFileName = srcFile.getName();
final String dstFileName = srcFileName.substring(
0, srcFileName.length() - COMPRESSED_EXTENSION.length());
final File dstFile = new File(dstCodePath, dstFileName);
ret = decompressFile(srcFile, dstFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", file: " + dstFileName);
break;
}
}
} catch (ErrnoException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
+ "; pkg: " + packageName
+ ", err: " + e.errno);
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(dstCodePath);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
null /*abiOverride*/, false /*isIncremental*/);
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
+ "; pkg: " + packageName);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
// NOTE: During boot, we have to delay releasing cblocks for no other reason than
// we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}.
// When we no longer need to read that setting, cblock release can occur always
// occur here directly
if (!mSystemReady) {
if (mReleaseOnSystemReady == null) {
mReleaseOnSystemReady = new ArrayList<>();
}
mReleaseOnSystemReady.add(dstCodePath);
} else {
final ContentResolver resolver = mContext.getContentResolver();
F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
}
}
if (ret != PackageManager.INSTALL_SUCCEEDED) {
if (!dstCodePath.exists()) {
return null;
}
removeCodePathLI(dstCodePath);
return null;
}
return dstCodePath;
}
@GuardedBy("mLock")
private void updateInstantAppInstallerLocked(String modifiedPackage) {
// we're only interested in updating the installer appliction when 1) it's not
// already set or 2) the modified package is the installer
if (mInstantAppInstallerActivity != null
&& !mInstantAppInstallerActivity.getComponentName().getPackageName()
.equals(modifiedPackage)) {
return;
}
setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
}
private @Nullable File preparePackageParserCache(boolean forEngBuild) {
if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
return null;
}
// Disable package parsing on eng builds to allow for faster incremental development.
if (forEngBuild) {
return null;
}
if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
Slog.i(TAG, "Disabling package parser cache due to system property.");
return null;
}
}
// The base directory for the package parser cache lives under /data/system/.
final File cacheBaseDir = Environment.getPackageCacheDirectory();
if (!FileUtils.createDir(cacheBaseDir)) {
return null;
}
// There are several items that need to be combined together to safely
// identify cached items. In particular, changing the value of certain
// feature flags should cause us to invalidate any caches.
final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
: SystemProperties.digestOf("ro.build.fingerprint");
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
if (Objects.equals(cacheName, cacheDir.getName())) {
Slog.d(TAG, "Keeping known cache " + cacheDir.getName());
} else {
Slog.d(TAG, "Destroying unknown cache " + cacheDir.getName());
FileUtils.deleteContentsAndDir(cacheDir);
}
}
// Return the versioned package cache directory.
File cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
if (cacheDir == null) {
// Something went wrong. Attempt to delete everything and return.
Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir);
FileUtils.deleteContentsAndDir(cacheBaseDir);
return null;
}
// The following is a workaround to aid development on non-numbered userdebug
// builds or cases where "adb sync" is used on userdebug builds. If we detect that
// the system partition is newer.
//
// NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
// that starts with "eng." to signify that this is an engineering build and not
// destined for release.
if (mIsUserDebugBuild && mIncrementalVersion.startsWith("eng.")) {
Slog.w(TAG, "Wiping cache directory because the system partition changed.");
// Heuristic: If the /system directory has been modified recently due to an "adb sync"
// or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
// in general and should not be used for production changes. In this specific case,
// we know that they will work.
File frameworkDir =
new File(Environment.getRootDirectory(), "framework");
if (cacheDir.lastModified() < frameworkDir.lastModified()) {
FileUtils.deleteContents(cacheBaseDir);
cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
}
}
return cacheDir;
}
@Override
public boolean isFirstBoot() {
// allow instant applications
return mFirstBoot;
}
@Override
public boolean isOnlyCoreApps() {
// allow instant applications
return mOnlyCore;
}
@Override
public boolean isDeviceUpgrading() {
// allow instant applications
// The system property allows testing ota flow when upgraded to the same image.
return mIsUpgrade || SystemProperties.getBoolean(
"persist.pm.mock-upgrade", false /* default */);
}
private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() {
final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
final List matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
if (matches.size() == 1) {
return matches.get(0).getComponentInfo().packageName;
} else if (matches.size() == 0) {
Log.w(TAG, "There should probably be a verifier, but, none were found");
return null;
}
throw new RuntimeException("There must be exactly one verifier; found " + matches);
}
private @NonNull String getRequiredSharedLibraryLPr(String name, int version) {
synchronized (mLock) {
SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version);
if (libraryInfo == null) {
throw new IllegalStateException("Missing required shared library:" + name);
}
String packageName = libraryInfo.getPackageName();
if (packageName == null) {
throw new IllegalStateException("Expected a package for shared library " + name);
}
return packageName;
}
}
@NonNull
private String getRequiredServicesExtensionPackageLPr() {
String servicesExtensionPackage =
ensureSystemPackageName(
mContext.getString(R.string.config_servicesExtensionPackage));
if (TextUtils.isEmpty(servicesExtensionPackage)) {
throw new RuntimeException(
"Required services extension package is missing, check "
+ "config_servicesExtensionPackage.");
}
return servicesExtensionPackage;
}
private @NonNull String getRequiredInstallerLPr() {
final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.parse("content://com.example/foo.apk"), PACKAGE_MIME_TYPE);
final List matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
ResolveInfo resolveInfo = matches.get(0);
if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
throw new RuntimeException("The installer must be a privileged app");
}
return matches.get(0).getComponentInfo().packageName;
} else {
throw new RuntimeException("There must be exactly one installer; found " + matches);
}
}
private @NonNull String getRequiredUninstallerLPr() {
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null));
final ResolveInfo resolveInfo = resolveIntent(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM);
if (resolveInfo == null ||
mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) {
throw new RuntimeException("There must be exactly one uninstaller; found "
+ resolveInfo);
}
return resolveInfo.getComponentInfo().packageName;
}
private @NonNull String getRequiredPermissionControllerLPr() {
final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
final List matches = queryIntentActivitiesInternal(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM);
if (matches.size() == 1) {
ResolveInfo resolveInfo = matches.get(0);
if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
throw new RuntimeException("The permissions manager must be a privileged app");
}
return matches.get(0).getComponentInfo().packageName;
} else {
throw new RuntimeException("There must be exactly one permissions manager; found "
+ matches);
}
}
private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
final List matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
ResolveInfo best = null;
final int N = matches.size();
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
}
if (best == null || cur.priority > best.priority) {
best = cur;
}
}
if (best != null) {
return best.getComponentInfo().getComponentName();
}
Slog.w(TAG, "Intent filter verifier not found");
return null;
}
@Nullable
private ComponentName getDomainVerificationAgentComponentNameLPr() {
Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION);
List matches = queryIntentReceiversInternal(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
ResolveInfo best = null;
final int N = matches.size();
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Domain verification agent found but does not hold permission: "
+ packageName);
continue;
}
if (best == null || cur.priority > best.priority) {
if (isComponentEffectivelyEnabled(cur.getComponentInfo(), UserHandle.USER_SYSTEM)) {
best = cur;
} else {
Slog.w(TAG, "Domain verification agent found but not enabled");
}
}
}
if (best != null) {
return best.getComponentInfo().getComponentName();
}
Slog.w(TAG, "Domain verification agent not found");
return null;
}
@Override
public @Nullable ComponentName getInstantAppResolverComponent() {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
synchronized (mLock) {
final ComponentName instantAppResolver = getInstantAppResolverLPr();
if (instantAppResolver == null) {
return null;
}
return instantAppResolver;
}
}
private @Nullable ComponentName getInstantAppResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver NOT found; empty package list");
}
return null;
}
final int callingUid = Binder.getCallingUid();
final int resolveFlags =
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
List resolvers = queryIntentServicesInternal(resolverIntent, null,
resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
final int N = resolvers.size();
if (N == 0) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver NOT found; no matching intent filters");
}
return null;
}
final Set possiblePackages = new ArraySet<>(Arrays.asList(packageArray));
for (int i = 0; i < N; i++) {
final ResolveInfo info = resolvers.get(i);
if (info.serviceInfo == null) {
continue;
}
final String packageName = info.serviceInfo.packageName;
if (!possiblePackages.contains(packageName) && !Build.IS_DEBUGGABLE) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver not in allowed package list;"
+ " pkg: " + packageName + ", info:" + info);
}
continue;
}
if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver found;"
+ " pkg: " + packageName + ", info:" + info);
}
return new ComponentName(packageName, info.serviceInfo.name);
}
if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver NOT found");
}
return null;
}
@GuardedBy("mLock")
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
String[] orderedActions = mIsEngBuild
? new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST",
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE}
: new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE};
final int resolveFlags =
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| Intent.FLAG_IGNORE_EPHEMERAL
| (mIsEngBuild ? 0 : MATCH_SYSTEM_ONLY);
final Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
List matches = null;
for (String action : orderedActions) {
intent.setAction(action);
matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
resolveFlags, UserHandle.USER_SYSTEM);
if (matches.isEmpty()) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Instant App installer not found with " + action);
}
} else {
break;
}
}
Iterator iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
if (checkPermission(
Manifest.permission.INSTALL_PACKAGES,
rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
continue;
}
iter.remove();
}
if (matches.size() == 0) {
return null;
} else if (matches.size() == 1) {
return (ActivityInfo) matches.get(0).getComponentInfo();
} else {
throw new RuntimeException(
"There must be at most one ephemeral installer; found " + matches);
}
}
private @Nullable ComponentName getInstantAppResolverSettingsLPr(
@NonNull ComponentName resolver) {
final Intent intent = new Intent(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS)
.addCategory(Intent.CATEGORY_DEFAULT)
.setPackage(resolver.getPackageName());
final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
List matches = queryIntentActivitiesInternal(intent, null, resolveFlags,
UserHandle.USER_SYSTEM);
if (matches.isEmpty()) {
return null;
}
return matches.get(0).getComponentInfo().getComponentName();
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
return super.onTransact(code, data, reply, flags);
} catch (RuntimeException e) {
if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) {
Slog.wtf(TAG, "Package Manager Crash", e);
}
throw e;
}
}
/**
* Returns whether or not a full application can see an instant application.
*
* Currently, there are four cases in which this can occur:
*
* The calling application is a "special" process. Special processes
* are those with a UID < {@link Process#FIRST_APPLICATION_UID}.
* The calling application has the permission
* {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.
* The calling application is the default launcher on the
* system partition.
* The calling application is the default app prediction service.
*
*/
private boolean canViewInstantApps(int callingUid, int userId) {
return mComputer.canViewInstantApps(callingUid, userId);
}
private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
return mComputer.generatePackageInfo(ps, flags, userId);
}
@Override
public void checkPackageStartable(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant applications don't have access to this method");
}
if (!mUserManager.exists(userId)) {
throw new SecurityException("User doesn't exist");
}
enforceCrossUserPermission(callingUid, userId, false, false, "checkPackageStartable");
switch (getPackageStartability(packageName, callingUid, userId)) {
case PACKAGE_STARTABILITY_NOT_FOUND:
throw new SecurityException("Package " + packageName + " was not found!");
case PACKAGE_STARTABILITY_NOT_SYSTEM:
throw new SecurityException("Package " + packageName + " not a system app!");
case PACKAGE_STARTABILITY_FROZEN:
throw new SecurityException("Package " + packageName + " is currently frozen!");
case PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED:
throw new SecurityException("Package " + packageName + " is not encryption aware!");
case PACKAGE_STARTABILITY_OK:
default:
return;
}
}
private @PackageStartability int getPackageStartability(String packageName,
int callingUid, int userId) {
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)
|| !ps.getInstalled(userId)) {
return PACKAGE_STARTABILITY_NOT_FOUND;
}
if (mSafeMode && !ps.isSystem()) {
return PACKAGE_STARTABILITY_NOT_SYSTEM;
}
if (mFrozenPackages.contains(packageName)) {
return PACKAGE_STARTABILITY_FROZEN;
}
if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) {
return PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED;
}
}
return PACKAGE_STARTABILITY_OK;
}
@Override
public boolean isPackageAvailable(String packageName, int userId) {
if (!mUserManager.exists(userId)) return false;
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "is package available");
synchronized (mLock) {
AndroidPackage p = mPackages.get(packageName);
if (p != null) {
final PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return false;
}
if (ps != null) {
final PackageUserState state = ps.readUserState(userId);
if (state != null) {
return PackageParser.isAvailable(state);
}
}
}
}
return false;
}
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
return mComputer.getPackageInfo(packageName, flags, userId);
}
@Override
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out packages
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
return mComputer.getPackageInfoInternal(packageName, versionCode,
flags, filterCallingUid, userId);
}
private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
return mComputer.isComponentVisibleToInstantApp(component);
}
private boolean isComponentVisibleToInstantApp(
@Nullable ComponentName component, @ComponentType int type) {
return mComputer.isComponentVisibleToInstantApp(
component, type);
}
/**
* Returns whether or not access to the application should be filtered.
*
* Access may be limited based upon whether the calling or target applications
* are instant applications.
*
* @see #canViewInstantApps(int, int)
*/
@GuardedBy("mLock")
private boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
return mComputer.shouldFilterApplicationLocked(ps, callingUid,
component, componentType, userId);
}
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
@GuardedBy("mLock")
private boolean shouldFilterApplicationLocked(
@Nullable PackageSetting ps, int callingUid, int userId) {
return mComputer.shouldFilterApplicationLocked(
ps, callingUid, userId);
}
/**
* @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
@GuardedBy("mLock")
private boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid,
int userId) {
return mComputer.shouldFilterApplicationLocked(sus, callingUid, userId);
}
@GuardedBy("mLock")
private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags) {
return mComputer.filterSharedLibPackageLPr(ps, uid, userId,
flags);
}
@Override
public String[] currentToCanonicalPackageNames(String[] names) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return names;
}
final String[] out = new String[names.length];
// reader
synchronized (mLock) {
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
for (int i=names.length-1; i>=0; i--) {
final PackageSetting ps = mSettings.getPackageLPr(names[i]);
boolean translateName = false;
if (ps != null && ps.realName != null) {
final boolean targetIsInstantApp = ps.getInstantApp(callingUserId);
translateName = !targetIsInstantApp
|| canViewInstantApps
|| mInstantAppRegistry.isInstantAccessGranted(callingUserId,
UserHandle.getAppId(callingUid), ps.appId);
}
out[i] = translateName ? ps.realName : names[i];
}
}
return out;
}
@Override
public String[] canonicalToCurrentPackageNames(String[] names) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return names;
}
final String[] out = new String[names.length];
// reader
synchronized (mLock) {
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
for (int i=names.length-1; i>=0; i--) {
final String cur = mSettings.getRenamedPackageLPr(names[i]);
boolean translateName = false;
if (cur != null) {
final PackageSetting ps = mSettings.getPackageLPr(names[i]);
final boolean targetIsInstantApp =
ps != null && ps.getInstantApp(callingUserId);
translateName = !targetIsInstantApp
|| canViewInstantApps
|| mInstantAppRegistry.isInstantAccessGranted(callingUserId,
UserHandle.getAppId(callingUid), ps.appId);
}
out[i] = translateName ? cur : names[i];
}
}
return out;
}
@Override
public int getPackageUid(String packageName, int flags, int userId) {
if (!mUserManager.exists(userId)) return -1;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId);
enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "getPackageUid");
return getPackageUidInternal(packageName, flags, userId, callingUid);
}
private int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) {
return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid);
}
@Override
public int[] getPackageGids(String packageName, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId);
enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "getPackageGids");
// reader
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
}
// TODO: Shouldn't this be checking for package installed state for userId and
// return null?
return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
}
}
return null;
}
// NOTE: Can't remove due to unsupported app usage
@Override
public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
// Because this is accessed via the package manager service AIDL,
// go through the permission manager service AIDL
return mContext.getSystemService(PermissionManager.class)
.getPermissionGroupInfo(groupName, flags);
}
@GuardedBy("mLock")
private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId) {
return mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags,
filterCallingUid, userId);
}
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
return mComputer.getApplicationInfo(packageName, flags, userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out applications
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
private ApplicationInfo getApplicationInfoInternal(String packageName, int flags,
int filterCallingUid, int userId) {
return mComputer.getApplicationInfoInternal(packageName, flags,
filterCallingUid, userId);
}
@GuardedBy("mLock")
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
}
@Override
public void deletePreloadsFileCache() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
"deletePreloadsFileCache");
File dir = Environment.getDataPreloadsFileCacheDirectory();
Slog.i(TAG, "Deleting preloaded file cache " + dir);
FileUtils.deleteContents(dir);
}
@Override
public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize,
final int storageFlags, final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
mHandler.post(() -> {
boolean success = false;
try {
freeStorage(volumeUuid, freeStorageSize, storageFlags);
success = true;
} catch (IOException e) {
Slog.w(TAG, e);
}
if (observer != null) {
try {
observer.onRemoveCompleted(null, success);
} catch (RemoteException e) {
Slog.w(TAG, e);
}
}
});
}
@Override
public void freeStorage(final String volumeUuid, final long freeStorageSize,
final int storageFlags, final IntentSender pi) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, TAG);
mHandler.post(() -> {
boolean success = false;
try {
freeStorage(volumeUuid, freeStorageSize, storageFlags);
success = true;
} catch (IOException e) {
Slog.w(TAG, e);
}
if (pi != null) {
try {
pi.sendIntent(null, success ? 1 : 0, null, null, null);
} catch (SendIntentException e) {
Slog.w(TAG, e);
}
}
});
}
/**
* Blocking call to clear various types of cached data across the system
* until the requested bytes are available.
*/
public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException {
final StorageManager storage = mInjector.getSystemService(StorageManager.class);
final File file = storage.findPathForUuid(volumeUuid);
if (file.getUsableSpace() >= bytes) return;
if (mEnableFreeCacheV2) {
final boolean internalVolume = Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL,
volumeUuid);
final boolean aggressive = (storageFlags
& StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
final long reservedBytes = storage.getStorageCacheBytes(file, storageFlags);
// 1. Pre-flight to determine if we have any chance to succeed
// 2. Consider preloaded data (after 1w honeymoon, unless aggressive)
if (internalVolume && (aggressive || SystemProperties
.getBoolean("persist.sys.preloads.file_cache_expired", false))) {
deletePreloadsFileCache();
if (file.getUsableSpace() >= bytes) return;
}
// 3. Consider parsed APK data (aggressive only)
if (internalVolume && aggressive) {
FileUtils.deleteContents(mCacheDir);
if (file.getUsableSpace() >= bytes) return;
}
// 4. Consider cached app data (above quotas)
try {
mInstaller.freeCache(volumeUuid, bytes, reservedBytes,
Installer.FLAG_FREE_CACHE_V2);
} catch (InstallerException ignored) {
}
if (file.getUsableSpace() >= bytes) return;
// 5. Consider shared libraries with refcount=0 and age>min cache period
if (internalVolume && pruneUnusedStaticSharedLibraries(bytes,
android.provider.Settings.Global.getLong(mContext.getContentResolver(),
Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) {
return;
}
// 6. Consider dexopt output (aggressive only)
// TODO: Implement
// 7. Consider installed instant apps unused longer than min cache period
if (internalVolume && mInstantAppRegistry.pruneInstalledInstantApps(bytes,
android.provider.Settings.Global.getLong(mContext.getContentResolver(),
Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
InstantAppRegistry.DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
return;
}
// 8. Consider cached app data (below quotas)
try {
mInstaller.freeCache(volumeUuid, bytes, reservedBytes,
Installer.FLAG_FREE_CACHE_V2 | Installer.FLAG_FREE_CACHE_V2_DEFY_QUOTA);
} catch (InstallerException ignored) {
}
if (file.getUsableSpace() >= bytes) return;
// 9. Consider DropBox entries
// TODO: Implement
// 10. Consider instant meta-data (uninstalled apps) older that min cache period
if (internalVolume && mInstantAppRegistry.pruneUninstalledInstantApps(bytes,
android.provider.Settings.Global.getLong(mContext.getContentResolver(),
Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
return;
}
// 11. Free storage service cache
StorageManagerInternal smInternal =
mInjector.getLocalService(StorageManagerInternal.class);
long freeBytesRequired = bytes - file.getUsableSpace();
if (freeBytesRequired > 0) {
smInternal.freeCache(volumeUuid, freeBytesRequired);
}
// 12. Clear temp install session files
mInstallerService.freeStageDirs(volumeUuid);
if (file.getUsableSpace() >= bytes) return;
} else {
try {
mInstaller.freeCache(volumeUuid, bytes, 0, 0);
} catch (InstallerException ignored) {
}
if (file.getUsableSpace() >= bytes) return;
}
throw new IOException("Failed to free " + bytes + " on storage device at " + file);
}
private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
throws IOException {
final StorageManager storage = mInjector.getSystemService(StorageManager.class);
final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
List packagesToDelete = null;
final long now = System.currentTimeMillis();
synchronized (mLock) {
final int[] allUsers = mUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
final WatchedLongSparseArray versionedLib
= mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int j = 0; j < versionCount; j++) {
SharedLibraryInfo libInfo = versionedLib.valueAt(j);
// Skip packages that are not static shared libs.
if (!libInfo.isStatic()) {
break;
}
// Important: We skip static shared libs used for some user since
// in such a case we need to keep the APK on the device. The check for
// a lib being used for any user is performed by the uninstall call.
final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
// Resolve the package name - we use synthetic package names internally
final String internalPackageName = resolveInternalPackageNameLPr(
declaringPackage.getPackageName(),
declaringPackage.getLongVersionCode());
final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
// Skip unused static shared libs cached less than the min period
// to prevent pruning a lib needed by a subsequently installed package.
if (ps == null || now - ps.lastUpdateTime < maxCachePeriod) {
continue;
}
if (ps.pkg.isSystem()) {
continue;
}
if (packagesToDelete == null) {
packagesToDelete = new ArrayList<>();
}
packagesToDelete.add(new VersionedPackage(internalPackageName,
declaringPackage.getLongVersionCode()));
}
}
}
if (packagesToDelete != null) {
final int packageCount = packagesToDelete.size();
for (int i = 0; i < packageCount; i++) {
final VersionedPackage pkgToDelete = packagesToDelete.get(i);
// Delete the package synchronously (will fail of the lib used for any user).
if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS,
true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
if (volume.getUsableSpace() >= neededSpace) {
return true;
}
}
}
}
return false;
}
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
private int updateFlagsForPackage(int flags, int userId) {
return mComputer.updateFlagsForPackage(flags, userId);
}
/**
* Update given flags when being used to request {@link ApplicationInfo}.
*/
private int updateFlagsForApplication(int flags, int userId) {
return mComputer.updateFlagsForApplication(flags, userId);
}
/**
* Update given flags when being used to request {@link ComponentInfo}.
*/
private int updateFlagsForComponent(int flags, int userId) {
return mComputer.updateFlagsForComponent(flags, userId);
}
/**
* Update given intent when being used to request {@link ResolveInfo}.
*/
private static Intent updateIntentForResolve(Intent intent) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) {
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
}
return intent;
}
/**
* Update given flags when being used to request {@link ResolveInfo}.
* Instant apps are resolved specially, depending upon context. Minimally,
* {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
* flag set. However, this flag is only honoured in three circumstances:
*
* when called from a system process
* when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}
* when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
* action and a {@code android.intent.category.BROWSABLE} category
*
*/
private int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return mComputer.updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
}
private int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean onlyExposedExplicitly,
boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return mComputer.updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, onlyExposedExplicitly,
isImplicitImageCaptureIntentAndNotSetByDpc);
}
@Override
public int getTargetSdkVersion(String packageName) {
synchronized (mLock) {
final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null) {
return -1;
}
final PackageSetting ps = getPackageSetting(pkg.getPackageName());
if (shouldFilterApplicationLocked(ps, Binder.getCallingUid(),
UserHandle.getCallingUserId())) {
return -1;
}
return pkg.getTargetSdkVersion();
}
}
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return mComputer.getActivityInfo(component, flags, userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out activities
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, its value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
int filterCallingUid, int userId) {
return mComputer.getActivityInfoInternal(component, flags,
filterCallingUid, userId);
}
@Override
public boolean activitySupportsIntent(ComponentName component, Intent intent,
String resolvedType) {
synchronized (mLock) {
if (component.equals(mResolveComponentName)) {
// The resolver supports EVERYTHING!
return true;
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
ParsedActivity a = mComponentResolver.getActivity(component);
if (a == null) {
return false;
}
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) {
return false;
}
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
return false;
}
for (int i=0; i< a.getIntents().size(); i++) {
if (a.getIntents().get(i).match(intent.getAction(), resolvedType, intent.getScheme(),
intent.getData(), intent.getCategories(), TAG) >= 0) {
return true;
}
}
return false;
}
}
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId);
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "get receiver info");
synchronized (mLock) {
ParsedActivity a = mComponentResolver.getReceiver(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
if (a == null) {
return null;
}
AndroidPackage pkg = mPackages.get(a.getPackageName());
if (pkg == null) {
return null;
}
if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_RECEIVER, userId)) {
return null;
}
return PackageInfoUtils.generateActivityInfo(pkg,
a, flags, ps.readUserState(userId), userId, ps);
}
}
return null;
}
@Override
public ParceledListSlice getSharedLibraries(String packageName,
int flags, int userId) {
if (!mUserManager.exists(userId)) return null;
Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return null;
}
flags = updateFlagsForPackage(flags, userId);
final boolean canSeeStaticLibraries =
mContext.checkCallingOrSelfPermission(INSTALL_PACKAGES)
== PERMISSION_GRANTED
|| mContext.checkCallingOrSelfPermission(DELETE_PACKAGES)
== PERMISSION_GRANTED
|| canRequestPackageInstallsInternal(packageName, callingUid, userId,
false /* throwIfPermNotDeclared*/)
|| mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES)
== PERMISSION_GRANTED
|| mContext.checkCallingOrSelfPermission(
Manifest.permission.ACCESS_SHARED_LIBRARIES) == PERMISSION_GRANTED;
synchronized (mLock) {
List result = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
WatchedLongSparseArray versionedLib =
mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int j = 0; j < versionCount; j++) {
SharedLibraryInfo libInfo = versionedLib.valueAt(j);
if (!canSeeStaticLibraries && libInfo.isStatic()) {
break;
}
final long identity = Binder.clearCallingIdentity();
try {
PackageInfo packageInfo = getPackageInfoVersioned(
libInfo.getDeclaringPackage(), flags
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
if (packageInfo == null) {
continue;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getAllCodePaths(),
libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), libInfo.getDeclaringPackage(),
getPackagesUsingSharedLibraryLPr(libInfo, flags, callingUid, userId),
(libInfo.getDependencies() == null
? null
: new ArrayList<>(libInfo.getDependencies())),
libInfo.isNative());
if (result == null) {
result = new ArrayList<>();
}
result.add(resLibInfo);
}
}
return result != null ? new ParceledListSlice<>(result) : null;
}
}
@Nullable
@Override
public ParceledListSlice getDeclaredSharedLibraries(
@NonNull String packageName, int flags, @NonNull int userId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES,
"getDeclaredSharedLibraries");
int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "getDeclaredSharedLibraries");
Preconditions.checkNotNull(packageName, "packageName cannot be null");
Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
if (!mUserManager.exists(userId)) {
return null;
}
if (getInstantAppPackageName(callingUid) != null) {
return null;
}
synchronized (mLock) {
List