| /* |
| * 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.MANAGE_DEVICE_ADMINS; |
| import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; |
| import static android.app.AppOpsManager.MODE_IGNORED; |
| 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.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_SYSTEM_ONLY; |
| import static android.content.pm.PackageManager.PERMISSION_GRANTED; |
| import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; |
| import static android.os.Process.INVALID_UID; |
| import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; |
| 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 android.util.FeatureFlagUtils.SETTINGS_TREAT_PAUSE_AS_QUARANTINE; |
| |
| import static com.android.internal.annotations.VisibleForTesting.Visibility; |
| import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME; |
| import static com.android.server.pm.DexOptHelper.useArtService; |
| import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; |
| import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; |
| import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures; |
| import static com.android.server.pm.PackageManagerServiceUtils.isInstalledByAdb; |
| import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; |
| |
| 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.AppOpsManager; |
| import android.app.ApplicationExitInfo; |
| import android.app.ApplicationPackageManager; |
| import android.app.BroadcastOptions; |
| import android.app.IActivityManager; |
| 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.Intent; |
| import android.content.IntentFilter; |
| import android.content.IntentSender; |
| import android.content.IntentSender.SendIntentException; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.ArchivedPackageParcel; |
| 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.Flags; |
| import android.content.pm.IDexModuleRegisterCallback; |
| import android.content.pm.IOnChecksumsReadyListener; |
| import android.content.pm.IPackageDataObserver; |
| import android.content.pm.IPackageDeleteObserver2; |
| import android.content.pm.IPackageLoadingProgressCallback; |
| import android.content.pm.IPackageMoveObserver; |
| import android.content.pm.IncrementalStatesInfo; |
| import android.content.pm.InstallSourceInfo; |
| import android.content.pm.InstantAppInfo; |
| import android.content.pm.InstantAppRequest; |
| import android.content.pm.ModuleInfo; |
| 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.ComponentEnabledSetting; |
| import android.content.pm.PackageManagerInternal; |
| import android.content.pm.PackagePartitions; |
| import android.content.pm.ParceledListSlice; |
| import android.content.pm.PermissionGroupInfo; |
| import android.content.pm.ProviderInfo; |
| import android.content.pm.ResolveInfo; |
| import android.content.pm.SharedLibraryInfo; |
| import android.content.pm.Signature; |
| import android.content.pm.SigningDetails; |
| import android.content.pm.SuspendDialogInfo; |
| import android.content.pm.TestUtilityService; |
| import android.content.pm.UserInfo; |
| import android.content.pm.UserPackage; |
| import android.content.pm.VerifierDeviceIdentity; |
| import android.content.pm.VerifierInfo; |
| import android.content.pm.VersionedPackage; |
| import android.content.pm.overlay.OverlayPaths; |
| import android.content.pm.parsing.PackageLite; |
| 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.HandlerThread; |
| import android.os.IBinder; |
| import android.os.IRemoteCallback; |
| import android.os.Message; |
| import android.os.Parcel; |
| import android.os.ParcelFileDescriptor; |
| import android.os.ParcelableException; |
| import android.os.PersistableBundle; |
| import android.os.Process; |
| import android.os.ReconcileSdkDataArgs; |
| import android.os.RemoteException; |
| import android.os.ResultReceiver; |
| 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.PerUidReadTimeouts; |
| import android.os.storage.StorageManager; |
| import android.os.storage.StorageManagerInternal; |
| import android.os.storage.VolumeRecord; |
| import android.permission.PermissionManager; |
| import android.provider.DeviceConfig; |
| import android.provider.Settings.Global; |
| import android.provider.Settings.Secure; |
| import android.text.TextUtils; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.DisplayMetrics; |
| import android.util.EventLog; |
| import android.util.ExceptionUtils; |
| import android.util.FeatureFlagUtils; |
| import android.util.Log; |
| import android.util.Pair; |
| import android.util.Slog; |
| import android.util.SparseArray; |
| import android.util.SparseBooleanArray; |
| import android.util.Xml; |
| 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.InstallLocationUtils; |
| import com.android.internal.content.om.OverlayConfig; |
| import com.android.internal.pm.parsing.pkg.AndroidPackageInternal; |
| import com.android.internal.pm.parsing.pkg.ParsedPackage; |
| import com.android.internal.pm.pkg.component.ParsedInstrumentation; |
| import com.android.internal.pm.pkg.component.ParsedMainComponent; |
| import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; |
| 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.Preconditions; |
| import com.android.modules.utils.TypedXmlPullParser; |
| import com.android.modules.utils.TypedXmlSerializer; |
| import com.android.permission.persistence.RuntimePermissionsPersistence; |
| import com.android.permission.persistence.RuntimePermissionsState; |
| import com.android.server.EventLogTags; |
| import com.android.server.FgThread; |
| import com.android.server.LocalManagerRegistry; |
| 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.ThreadPriorityBooster; |
| import com.android.server.Watchdog; |
| import com.android.server.apphibernation.AppHibernationManagerInternal; |
| import com.android.server.art.DexUseManagerLocal; |
| import com.android.server.art.model.DeleteResult; |
| import com.android.server.compat.CompatChange; |
| import com.android.server.compat.PlatformCompat; |
| import com.android.server.pm.Installer.InstallerException; |
| import com.android.server.pm.Installer.LegacyDexoptDisabledException; |
| 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.DynamicCodeLogger; |
| import com.android.server.pm.local.PackageManagerLocalImpl; |
| import com.android.server.pm.parsing.PackageInfoUtils; |
| import com.android.server.pm.parsing.PackageParser2; |
| import com.android.server.pm.parsing.pkg.AndroidPackageUtils; |
| import com.android.server.pm.permission.LegacyPermissionManagerInternal; |
| import com.android.server.pm.permission.LegacyPermissionManagerService; |
| import com.android.server.pm.permission.LegacyPermissionSettings; |
| import com.android.server.pm.permission.PermissionManagerService; |
| import com.android.server.pm.permission.PermissionManagerServiceInternal; |
| import com.android.server.pm.pkg.AndroidPackage; |
| import com.android.server.pm.pkg.ArchiveState; |
| import com.android.server.pm.pkg.PackageState; |
| import com.android.server.pm.pkg.PackageStateInternal; |
| import com.android.server.pm.pkg.PackageUserState; |
| import com.android.server.pm.pkg.PackageUserStateInternal; |
| import com.android.server.pm.pkg.SharedUserApi; |
| import com.android.server.pm.pkg.mutate.PackageStateMutator; |
| import com.android.server.pm.pkg.mutate.PackageStateWrite; |
| import com.android.server.pm.pkg.mutate.PackageUserStateWrite; |
| import com.android.server.pm.resolution.ComponentResolver; |
| import com.android.server.pm.resolution.ComponentResolverApi; |
| import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; |
| import com.android.server.pm.verify.domain.DomainVerificationService; |
| import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy; |
| import com.android.server.sdksandbox.SdkSandboxManagerLocal; |
| import com.android.server.storage.DeviceStorageMonitorInternal; |
| 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.WatchedSparseBooleanArray; |
| import com.android.server.utils.WatchedSparseIntArray; |
| import com.android.server.utils.Watcher; |
| |
| import dalvik.system.VMRuntime; |
| |
| import libcore.util.EmptyArray; |
| import libcore.util.HexEncoding; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileDescriptor; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| 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.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.concurrent.atomic.AtomicReference; |
| import java.util.function.Consumer; |
| import java.util.function.Predicate; |
| |
| /** |
| * Keep track of all those APKs everywhere. |
| * <p> |
| * Internally there are three important locks: |
| * <ul> |
| * <li>{@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. |
| * <li>{@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}. |
| * <li>{@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}. |
| * </ul> |
| * Many internal methods rely on the caller to hold the appropriate locks, and |
| * this contract is expressed through method name suffixes: |
| * <ul> |
| * <li>fooLI(): the caller must hold {@link #mInstallLock} |
| * <li>fooLIF(): the caller must hold {@link #mInstallLock} and the package |
| * being modified must be frozen |
| * <li>fooLPr(): the caller must hold {@link #mLock} for reading |
| * <li>fooLPw(): the caller must hold {@link #mLock} for writing |
| * </ul> |
| * {@link #mSnapshotLock} is taken in exactly one place - {@code snapshotComputer()}. It |
| * should not be taken anywhere else or used for any other purpose. |
| * <p> |
| * Because this class is very central to the platform's security; please run all |
| * CTS and unit tests whenever making modifications: |
| * |
| * <pre> |
| * $ runtest -c android.content.pm.PackageManagerTests frameworks-core |
| * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases |
| * </pre> |
| */ |
| public class PackageManagerService 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; |
| static final boolean DEBUG_BACKUP = false; |
| public static final boolean DEBUG_INSTALL = false; |
| public static final boolean DEBUG_REMOVE = false; |
| static final boolean DEBUG_PACKAGE_INFO = false; |
| static final boolean DEBUG_INTENT_MATCHING = false; |
| public static final boolean DEBUG_PACKAGE_SCANNING = false; |
| static final boolean DEBUG_VERIFY = false; |
| public static final boolean DEBUG_PERMISSIONS = 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; |
| public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE; |
| |
| static final String SHELL_PACKAGE_NAME = "com.android.shell"; |
| |
| static final boolean HIDE_EPHEMERAL_APIS = false; |
| |
| 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; |
| static final int SCAN_DROP_CACHE = 1 << 24; |
| static final int SCAN_AS_FACTORY = 1 << 25; |
| static final int SCAN_AS_APEX = 1 << 26; |
| static final int SCAN_AS_STOPPED_SYSTEM_APP = 1 << 27; |
| |
| @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, |
| SCAN_AS_STOPPED_SYSTEM_APP, |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface ScanFlags {} |
| |
| /** |
| * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int, |
| * int)}. |
| */ |
| @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 Computer#getPackageStartability(boolean, String, int, |
| * int)} to indicate the given package is allowed to start. |
| */ |
| public static final int PACKAGE_STARTABILITY_OK = 0; |
| |
| /** |
| * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int, |
| * int)} to indicate the given package is <b>not</b> allowed to start because it's not found |
| * (could be due to that package is invisible to the given user). |
| */ |
| public static final int PACKAGE_STARTABILITY_NOT_FOUND = 1; |
| |
| /** |
| * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int, |
| * int)} to indicate the given package is <b>not</b> allowed to start because it's not a system |
| * app and the system is running in safe mode. |
| */ |
| public static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2; |
| |
| /** |
| * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int, |
| * int)} to indicate the given package is <b>not</b> allowed to start because it's currently |
| * frozen. |
| */ |
| public static final int PACKAGE_STARTABILITY_FROZEN = 3; |
| |
| /** |
| * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int, |
| * int)} to indicate the given package is <b>not</b> allowed to start because it doesn't support |
| * direct boot. |
| */ |
| public 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"; |
| |
| 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 |
| |
| /** |
| * Default IncFs timeouts. Maximum values in IncFs is 1hr. |
| * |
| * <p>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"; |
| |
| /** |
| * Whether or not requesting the approval before committing sessions is available. |
| * |
| * Flag type: {@code boolean} |
| * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE |
| */ |
| private static final String PROPERTY_IS_PRE_APPROVAL_REQUEST_AVAILABLE = |
| "is_preapproval_available"; |
| |
| /** |
| * Whether or not the update ownership enforcement is available. |
| * |
| * Flag type: {@code boolean} |
| * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE |
| */ |
| private static final String PROPERTY_IS_UPDATE_OWNERSHIP_ENFORCEMENT_AVAILABLE = |
| "is_update_ownership_enforcement_available"; |
| |
| private static final String PROPERTY_DEFERRED_NO_KILL_POST_DELETE_DELAY_MS_EXTENDED = |
| "deferred_no_kill_post_delete_delay_ms_extended"; |
| |
| /** |
| * The default response for package verification timeout. |
| * |
| * This can be either PackageManager.VERIFICATION_ALLOW or |
| * PackageManager.VERIFICATION_REJECT. |
| */ |
| 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; |
| |
| public static final String PLATFORM_PACKAGE_NAME = "android"; |
| |
| static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; |
| |
| static final String PACKAGE_SCHEME = "package"; |
| |
| private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager"; |
| |
| // How many required verifiers can be on the system. |
| private static final int REQUIRED_VERIFIERS_MAX_COUNT = 2; |
| |
| /** |
| * Specifies the minimum target SDK version an apk must specify in order to be installed |
| * on the system. This improves security and privacy by blocking low |
| * target sdk apps as malware can target older sdk versions to avoid |
| * the enforcement of new API behavior. |
| */ |
| public static final int MIN_INSTALLABLE_TARGET_SDK = Build.VERSION_CODES.M; |
| |
| // Compilation reasons. |
| // TODO(b/260124949): Clean this up with the legacy dexopt code. |
| 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_BOOT_AFTER_MAINLINE_UPDATE = 13; |
| public static final int REASON_SHARED = 14; |
| |
| public static final int REASON_LAST = REASON_SHARED; |
| |
| static final String RANDOM_DIR_PREFIX = "~~"; |
| static final char RANDOM_CODEPATH_PREFIX = '-'; |
| |
| static final String APP_METADATA_FILE_NAME = "app.metadata"; |
| |
| final Handler mHandler; |
| final Handler mBackgroundHandler; |
| |
| final ProcessLoggingHandler mProcessLoggingHandler; |
| |
| private final int mSdkVersion; |
| final Context mContext; |
| final boolean mFactoryTest; |
| final DisplayMetrics mMetrics; |
| private final int mDefParseFlags; |
| private final String[] mSeparateProcesses; |
| private final boolean mIsUpgrade; |
| private final boolean mIsPreNMR1Upgrade; |
| private final boolean mIsPreQUpgrade; |
| |
| // 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; |
| |
| // ---------------------------------------------------------------- |
| |
| // 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; |
| |
| // Ensures order of overlay updates until data storage can be moved to overlay code |
| private final PackageManagerTracedLock mOverlayPathsLock = new PackageManagerTracedLock(); |
| |
| // Lock alias for doing package state mutation |
| private final PackageManagerTracedLock mPackageStateWriteLock; |
| |
| private final PackageStateMutator mPackageStateMutator = new PackageStateMutator( |
| this::getPackageSettingForMutation, |
| this::getDisabledPackageSettingForMutation); |
| |
| // Keys are String (package name), values are Package. |
| @Watched |
| @GuardedBy("mLock") |
| final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>(); |
| private final SnapshotCache<WatchedArrayMap<String, AndroidPackage>> 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<WatchedSparseIntArray> mIsolatedOwnersSnapshot = |
| new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners, |
| "PackageManagerService.mIsolatedOwners"); |
| |
| /** |
| * 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<String> mExistingPackages = null; |
| |
| /** |
| * List of code paths that need to be released when the system becomes ready. |
| * <p> |
| * 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() |
| */ |
| @Nullable List<File> mReleaseOnSystemReady; |
| |
| /** |
| * Whether or not system app permissions should be promoted from install to runtime. |
| */ |
| boolean mPromoteSystemApps; |
| |
| private final TestUtilityService mTestUtilityService; |
| |
| @Watched |
| @GuardedBy("mLock") |
| final Settings mSettings; |
| |
| /** |
| * Map of package names to frozen counts 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 WatchedArrayMap<String, Integer> mFrozenPackages = new WatchedArrayMap<>(); |
| private final SnapshotCache<WatchedArrayMap<String, Integer>> mFrozenPackagesSnapshot = |
| new SnapshotCache.Auto(mFrozenPackages, mFrozenPackages, |
| "PackageManagerService.mFrozenPackages"); |
| |
| final ProtectedPackages mProtectedPackages; |
| |
| private boolean mFirstBoot; |
| |
| final boolean mIsEngBuild; |
| private final boolean mIsUserDebugBuild; |
| private final String mIncrementalVersion; |
| |
| PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; |
| |
| @GuardedBy("mAvailableFeatures") |
| private final ArrayMap<String, FeatureInfo> mAvailableFeatures; |
| |
| @Watched |
| final InstantAppRegistry mInstantAppRegistry; |
| |
| @NonNull |
| final ChangedPackagesTracker mChangedPackagesTracker; |
| |
| @NonNull |
| private final PackageObserverHelper mPackageObserverHelper = new PackageObserverHelper(); |
| |
| @NonNull |
| private final PackageMonitorCallbackHelper mPackageMonitorCallbackHelper; |
| |
| private final ModuleInfoProvider mModuleInfoProvider; |
| |
| final ApexManager mApexManager; |
| |
| final PackageManagerServiceInjector mInjector; |
| |
| /** |
| * 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.PACKAGE) |
| public static final List<ScanPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList( |
| PackagePartitions.getOrderedPartitions(ScanPartition::new)); |
| |
| private @NonNull final OverlayConfig mOverlayConfig; |
| |
| // Cached parsed flag value. Invalidated on each flag change. |
| PerUidReadTimeouts[] mPerUidReadTimeoutsCache; |
| |
| private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {}; |
| |
| private static class DefaultSystemWrapper implements |
| PackageManagerServiceInjector.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(); |
| PackageManager.corkPackageInfoCache(); |
| } |
| |
| @Override |
| public void enablePackageCaches() { |
| PackageManager.uncorkPackageInfoCache(); |
| } |
| } |
| |
| @Watched |
| final AppsFilterImpl mAppsFilter; |
| |
| final PackageParser2.Callback mPackageParserCallback; |
| |
| // Currently known shared libraries. |
| @Watched |
| private final SharedLibrariesImpl mSharedLibraries; |
| |
| // Mapping from instrumentation class names to info about them. |
| @Watched |
| private final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation = |
| new WatchedArrayMap<>(); |
| private final SnapshotCache<WatchedArrayMap<ComponentName, ParsedInstrumentation>> |
| mInstrumentationSnapshot = |
| new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation, |
| "PackageManagerService.mInstrumentation"); |
| |
| // Packages whose data we have transfered into another package, thus |
| // should no longer exist. |
| final ArraySet<String> mTransferredPackages = new ArraySet<>(); |
| |
| // Broadcast actions that are only available to the system. |
| @GuardedBy("mProtectedBroadcasts") |
| final ArraySet<String> mProtectedBroadcasts = new ArraySet<>(); |
| |
| /** |
| * List of packages waiting for verification. |
| * Handler thread only! |
| */ |
| final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>(); |
| |
| /** |
| * List of packages waiting for rollback to be enabled. |
| * Handler thread only! |
| */ |
| final SparseArray<VerifyingSession> mPendingEnableRollback = new SparseArray<>(); |
| |
| final PackageInstallerService mInstallerService; |
| final ArtManagerService mArtManagerService; |
| |
| // TODO(b/260124949): Remove these. |
| final PackageDexOptimizer mPackageDexOptimizer; |
| @Nullable |
| final BackgroundDexOptService mBackgroundDexOptService; // null when ART Service is in use. |
| // 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 DynamicCodeLogger mDynamicCodeLogger; |
| |
| private final AtomicInteger mNextMoveId = new AtomicInteger(); |
| final MovePackageHelper.MoveCallbacks mMoveCallbacks; |
| |
| /** |
| * Token for keys in mPendingVerification. |
| * Handler thread only! |
| */ |
| int mPendingVerificationToken = 0; |
| |
| /** |
| * Token for keys in mPendingEnableRollback. |
| * Handler thread only! |
| */ |
| int mPendingEnableRollbackToken = 0; |
| |
| @Watched(manual = true) |
| private volatile boolean mSystemReady; |
| @Watched(manual = true) |
| private volatile boolean mSafeMode; |
| @Watched |
| private final WatchedSparseBooleanArray mWebInstantAppsDisabled = |
| new WatchedSparseBooleanArray(); |
| |
| @Watched(manual = true) |
| private ApplicationInfo mAndroidApplication; |
| @Watched(manual = true) |
| private final ActivityInfo mResolveActivity = new ActivityInfo(); |
| private final ResolveInfo mResolveInfo = new ResolveInfo(); |
| @Watched(manual = true) |
| ComponentName mResolveComponentName; |
| private AndroidPackage mPlatformPackage; |
| ComponentName mCustomResolverComponentName; |
| |
| // Recorded overlay paths configuration for the Android app info. |
| private String[] mPlatformPackageOverlayPaths = null; |
| private String[] mPlatformPackageOverlayResourceDirs = null; |
| // And the same paths for the replaced resolver activity package |
| private String[] mReplacedResolverPackageOverlayPaths = null; |
| private String[] mReplacedResolverPackageOverlayResourceDirs = null; |
| |
| private boolean mResolverReplaced = false; |
| |
| @NonNull |
| 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) |
| ActivityInfo mInstantAppInstallerActivity; |
| @Watched(manual = true) |
| private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo(); |
| |
| private final Map<String, InstallRequest> |
| mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>()); |
| |
| private final Map<String, InstallRequest> |
| mPendingKillInstallObservers = Collections.synchronizedMap(new HashMap<>()); |
| |
| // Internal interface for permission manager |
| final PermissionManagerServiceInternal mPermissionManager; |
| |
| @Watched |
| final ComponentResolver mComponentResolver; |
| |
| // Set of packages names to keep cached, even if they are uninstalled for all users |
| @GuardedBy("mKeepUninstalledPackages") |
| @NonNull |
| private final ArraySet<String> mKeepUninstalledPackages = new ArraySet<>(); |
| |
| // Cached reference to IDevicePolicyManager. |
| private IDevicePolicyManager mDevicePolicyManager = null; |
| |
| private File mCacheDir; |
| |
| private Future<?> mPrepareAppDataFuture; |
| |
| final IncrementalManager mIncrementalManager; |
| |
| private final DefaultAppProvider mDefaultAppProvider; |
| |
| private final LegacyPermissionManagerInternal mLegacyPermissionManager; |
| |
| private final PackageProperty mPackageProperty = new PackageProperty(); |
| |
| final PendingPackageBroadcasts mPendingBroadcasts; |
| |
| static final int SEND_PENDING_BROADCAST = 1; |
| // public static final int UNUSED = 5; |
| static final int POST_INSTALL = 9; |
| static final int WRITE_SETTINGS = 13; |
| static final int WRITE_DIRTY_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 PRUNE_UNUSED_STATIC_SHARED_LIBRARIES = 28; |
| static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER = 29; |
| |
| static final int WRITE_USER_PACKAGE_RESTRICTIONS = 30; |
| |
| private static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000; |
| |
| private static final long DEFERRED_NO_KILL_POST_DELETE_DELAY_MS_EXTENDED = |
| TimeUnit.DAYS.toMillis(1); |
| |
| private static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; |
| private static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER_DELAY_MS = 1000; |
| |
| 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) |
| |
| private static final long PRUNE_UNUSED_SHARED_LIBRARIES_DELAY = |
| TimeUnit.MINUTES.toMillis(3); // 3 minutes |
| |
| // When the service constructor finished plus a delay (used for broadcast delay computation) |
| private long mServiceStartWithDelay; |
| |
| static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD = |
| TimeUnit.DAYS.toMillis(7); /* 7 days */ |
| |
| final UserManagerService mUserManager; |
| |
| final UserNeedsBadgingCache mUserNeedsBadging; |
| |
| // Stores a list of users whose package restrictions file needs to be updated |
| final ArraySet<Integer> mDirtyUsers = new ArraySet<>(); |
| |
| final SparseArray<InstallRequest> mRunningInstalls = new SparseArray<>(); |
| int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows |
| |
| final @NonNull String[] mRequiredVerifierPackages; |
| 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 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; |
| final @Nullable String mAmbientContextDetectionPackage; |
| final @Nullable String mWearableSensingPackage; |
| final @NonNull Set<String> mInitialNonStoppedSystemPackages; |
| final boolean mShouldStopSystemPackagesByDefault; |
| private final @NonNull String mRequiredSdkSandboxPackage; |
| |
| @GuardedBy("mLock") |
| private final PackageUsage mPackageUsage = new PackageUsage(); |
| final CompilerStats mCompilerStats = new CompilerStats(); |
| |
| private final DomainVerificationConnection mDomainVerificationConnection; |
| |
| private final BroadcastHelper mBroadcastHelper; |
| private final RemovePackageHelper mRemovePackageHelper; |
| private final DeletePackageHelper mDeletePackageHelper; |
| private final InitAppsHelper mInitAppsHelper; |
| private final AppDataHelper mAppDataHelper; |
| @NonNull private final InstallPackageHelper mInstallPackageHelper; |
| private final PreferredActivityHelper mPreferredActivityHelper; |
| private final ResolveIntentHelper mResolveIntentHelper; |
| private final DexOptHelper mDexOptHelper; |
| private final SuspendPackageHelper mSuspendPackageHelper; |
| private final DistractingPackageHelper mDistractingPackageHelper; |
| private final StorageEventHelper mStorageEventHelper; |
| private final FreeStorageHelper mFreeStorageHelper; |
| |
| |
| private static final boolean ENABLE_BOOST = false; |
| |
| private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster( |
| Process.THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_PACKAGES); |
| |
| /** |
| * Boost the priority of the thread before holding PM traced lock. |
| * @hide |
| */ |
| public static void boostPriorityForPackageManagerTracedLockedSection() { |
| if (ENABLE_BOOST) { |
| sThreadPriorityBooster.boost(); |
| } |
| } |
| |
| |
| /** |
| * Restore the priority of the thread after release the PM traced lock. |
| * @hide |
| */ |
| public static void resetPriorityAfterPackageManagerTracedLockedSection() { |
| if (ENABLE_BOOST) { |
| sThreadPriorityBooster.reset(); |
| } |
| } |
| |
| /** |
| * 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.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. |
| */ |
| 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<String, AndroidPackage> packages; |
| public final WatchedArrayMap<ComponentName, ParsedInstrumentation> 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 AppsFilterSnapshot appsFilter; |
| public final ComponentResolverApi componentResolver; |
| public final PackageManagerService service; |
| public final WatchedArrayMap<String, Integer> frozenPackages; |
| public final SharedLibrariesRead sharedLibraries; |
| |
| Snapshot(int type) { |
| if (type == Snapshot.SNAPPED) { |
| settings = mSettings.snapshot(); |
| isolatedOwners = mIsolatedOwnersSnapshot.snapshot(); |
| packages = mPackagesSnapshot.snapshot(); |
| instrumentation = mInstrumentationSnapshot.snapshot(); |
| resolveComponentName = mResolveComponentName == null |
| ? null : 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(); |
| frozenPackages = mFrozenPackagesSnapshot.snapshot(); |
| sharedLibraries = mSharedLibraries.snapshot(); |
| } else if (type == Snapshot.LIVE) { |
| settings = mSettings; |
| isolatedOwners = mIsolatedOwners; |
| packages = mPackages; |
| instrumentation = mInstrumentation; |
| resolveComponentName = mResolveComponentName; |
| resolveActivity = mResolveActivity; |
| instantAppInstallerActivity = mInstantAppInstallerActivity; |
| instantAppInstallerInfo = mInstantAppInstallerInfo; |
| webInstantAppsDisabled = mWebInstantAppsDisabled; |
| instantAppRegistry = mInstantAppRegistry; |
| androidApplication = mAndroidApplication; |
| appPredictionServicePackage = mAppPredictionServicePackage; |
| appsFilter = mAppsFilter; |
| componentResolver = mComponentResolver; |
| frozenPackages = mFrozenPackages; |
| sharedLibraries = mSharedLibraries; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| service = PackageManagerService.this; |
| } |
| } |
| |
| // 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; |
| |
| private static final AtomicReference<Computer> sSnapshot = new AtomicReference<>(); |
| |
| // If this differs from Computer#getVersion, the snapshot is invalid (stale). |
| private static final AtomicInteger sSnapshotPendingVersion = new AtomicInteger(1); |
| |
| /** |
| * This lock is used to make reads from {@link #sSnapshotPendingVersion} and |
| * {@link #sSnapshot} atomic inside {@code snapshotComputer()} when the versions mismatch. |
| * 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. |
| */ |
| @Nullable |
| private final SnapshotStatistics mSnapshotStatistics; |
| |
| /** |
| * Return the cached computer. The method will rebuild the cached computer if necessary. |
| * The live computer will be returned if snapshots are disabled. |
| */ |
| @VisibleForTesting(visibility = Visibility.PACKAGE) |
| @NonNull |
| public Computer snapshotComputer() { |
| return snapshotComputer(true /*allowLiveComputer*/); |
| } |
| |
| /** |
| * This method should only ever be called from {@link PackageManagerLocal#snapshot()}. |
| * |
| * @param allowLiveComputer Whether to allow a live computer instance based on caller {@link |
| * #mLock} hold state. In certain cases, like for {@link |
| * PackageManagerLocal} API, it must be enforced that the caller gets |
| * a snapshot at time, and never the live variant. |
| * @deprecated Use {@link #snapshotComputer()} |
| */ |
| @Deprecated |
| @NonNull |
| public Computer snapshotComputer(boolean allowLiveComputer) { |
| var isHoldingPackageLock = Thread.holdsLock(mLock); |
| if (allowLiveComputer) { |
| if (isHoldingPackageLock) { |
| // 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; |
| } |
| } |
| |
| var oldSnapshot = sSnapshot.get(); |
| var pendingVersion = sSnapshotPendingVersion.get(); |
| |
| if (oldSnapshot != null && oldSnapshot.getVersion() == pendingVersion) { |
| return oldSnapshot.use(); |
| } |
| |
| if (isHoldingPackageLock) { |
| // If the current thread holds mLock then it already has exclusive write access to the |
| // two snapshot fields, and we can just go ahead and rebuild the snapshot. |
| @SuppressWarnings("GuardedBy") |
| var newSnapshot = rebuildSnapshot(oldSnapshot, pendingVersion); |
| sSnapshot.set(newSnapshot); |
| return newSnapshot.use(); |
| } |
| |
| synchronized (mSnapshotLock) { |
| // Re-capture pending version in case a new invalidation occurred since last check |
| var rebuildSnapshot = sSnapshot.get(); |
| var rebuildVersion = sSnapshotPendingVersion.get(); |
| |
| // Check the versions again while the lock is held, in case the rebuild time caused |
| // multiple threads to wait on the snapshot lock. When the first thread finishes |
| // a rebuild, the snapshot is now valid and the other waiting threads can use it |
| // without kicking off their own rebuilds. |
| if (rebuildSnapshot != null && rebuildSnapshot.getVersion() == rebuildVersion) { |
| return rebuildSnapshot.use(); |
| } |
| |
| synchronized (mLock) { |
| // Fetch version one last time to ensure that the rebuilt snapshot matches |
| // the latest invalidation, which could have come in between entering the |
| // SnapshotLock and mLock sync blocks. |
| rebuildSnapshot = sSnapshot.get(); |
| rebuildVersion = sSnapshotPendingVersion.get(); |
| if (rebuildSnapshot != null && rebuildSnapshot.getVersion() == rebuildVersion) { |
| return rebuildSnapshot.use(); |
| } |
| |
| // Build the snapshot for this version |
| var newSnapshot = rebuildSnapshot(rebuildSnapshot, rebuildVersion); |
| sSnapshot.set(newSnapshot); |
| return newSnapshot.use(); |
| } |
| } |
| } |
| |
| @GuardedBy("mLock") |
| private Computer rebuildSnapshot(@Nullable Computer oldSnapshot, int newVersion) { |
| var now = SystemClock.currentTimeMicro(); |
| var hits = oldSnapshot == null ? -1 : oldSnapshot.getUsed(); |
| var args = new Snapshot(Snapshot.SNAPPED); |
| var newSnapshot = new ComputerEngine(args, newVersion); |
| var done = SystemClock.currentTimeMicro(); |
| |
| if (mSnapshotStatistics != null) { |
| mSnapshotStatistics.rebuild(now, done, hits, newSnapshot.getPackageStates().size()); |
| } |
| return newSnapshot; |
| } |
| |
| /** |
| * 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 + ")"); |
| } |
| sSnapshotPendingVersion.incrementAndGet(); |
| } |
| |
| /** |
| * Report a locally-detected change to observers. The <what> parameter is left null, |
| * but it signifies that the change was detected by PackageManagerService itself. |
| */ |
| static void onChanged() { |
| onChange(null); |
| } |
| |
| void notifyInstallObserver(String packageName, boolean killApp) { |
| final InstallRequest installRequest = |
| killApp ? mPendingKillInstallObservers.remove(packageName) |
| : mNoKillInstallObservers.remove(packageName); |
| |
| if (installRequest != null) { |
| notifyInstallObserver(installRequest); |
| } |
| } |
| |
| void notifyInstallObserver(InstallRequest request) { |
| if (request.getObserver() != null) { |
| try { |
| Bundle extras = extrasForInstallResult(request); |
| request.getObserver().onPackageInstalled(request.getName(), |
| request.getReturnCode(), request.getReturnMsg(), extras); |
| } catch (RemoteException e) { |
| Slog.i(TAG, "Observer no longer exists."); |
| } |
| } |
| } |
| |
| void scheduleDeferredNoKillInstallObserver(InstallRequest request) { |
| String packageName = request.getPkg().getPackageName(); |
| mNoKillInstallObservers.put(packageName, request); |
| Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName); |
| mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS); |
| } |
| |
| void scheduleDeferredNoKillPostDelete(InstallArgs args) { |
| Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args); |
| // If the feature flag is on, retain the old files for a day. Otherwise, delete the old |
| // files after a few seconds. |
| long deleteDelayMillis = DEFERRED_NO_KILL_POST_DELETE_DELAY_MS; |
| if (Flags.improveInstallDontKill()) { |
| deleteDelayMillis = Binder.withCleanCallingIdentity(() -> { |
| return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, |
| /* name= */ PROPERTY_DEFERRED_NO_KILL_POST_DELETE_DELAY_MS_EXTENDED, |
| /* defaultValue= */ DEFERRED_NO_KILL_POST_DELETE_DELAY_MS_EXTENDED); |
| }); |
| Slog.w(TAG, "Delaying the deletion of <" + args.getCodePath() + "> by " |
| + deleteDelayMillis + "ms or till the next reboot"); |
| } |
| mHandler.sendMessageDelayed(message, deleteDelayMillis); |
| } |
| |
| void schedulePruneUnusedStaticSharedLibraries(boolean delay) { |
| mHandler.removeMessages(PRUNE_UNUSED_STATIC_SHARED_LIBRARIES); |
| mHandler.sendEmptyMessageDelayed(PRUNE_UNUSED_STATIC_SHARED_LIBRARIES, |
| delay ? getPruneUnusedSharedLibrariesDelay() : 0); |
| } |
| |
| void scheduleDeferredPendingKillInstallObserver(InstallRequest request) { |
| final String packageName = request.getPkg().getPackageName(); |
| mPendingKillInstallObservers.put(packageName, request); |
| final Message message = mHandler.obtainMessage(DEFERRED_PENDING_KILL_INSTALL_OBSERVER, |
| packageName); |
| mHandler.sendMessageDelayed(message, DEFERRED_PENDING_KILL_INSTALL_OBSERVER_DELAY_MS); |
| } |
| |
| private static long getPruneUnusedSharedLibrariesDelay() { |
| return SystemProperties.getLong("debug.pm.prune_unused_shared_libraries_delay", |
| PRUNE_UNUSED_SHARED_LIBRARIES_DELAY); |
| } |
| |
| /** |
| * Requests checksums for the APK file. |
| * See {@link PackageInstaller.Session#requestChecksums} for details. |
| */ |
| public void requestFileChecksums(@NonNull File file, |
| @NonNull String installerPackageName, @Checksum.TypeMask int optional, |
| @Checksum.TypeMask int required, @Nullable List trustedInstallers, |
| @NonNull IOnChecksumsReadyListener onChecksumsReadyListener) |
| throws FileNotFoundException { |
| if (!file.exists()) { |
| throw new FileNotFoundException(file.getAbsolutePath()); |
| } |
| |
| final Executor executor = mInjector.getBackgroundExecutor(); |
| final Handler handler = mInjector.getBackgroundHandler(); |
| final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates( |
| trustedInstallers) : null; |
| |
| final List<Pair<String, File>> filesToChecksum = new ArrayList<>(1); |
| filesToChecksum.add(Pair.create(null, file)); |
| |
| executor.execute(() -> { |
| ApkChecksums.Injector injector = new ApkChecksums.Injector( |
| () -> mContext, |
| () -> handler, |
| mInjector::getIncrementalManager, |
| () -> mInjector.getLocalService(PackageManagerInternal.class)); |
| ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName, |
| trustedCerts, onChecksumsReadyListener, injector); |
| }); |
| } |
| |
| void requestChecksumsInternal(@NonNull Computer snapshot, @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 = snapshot.getApplicationInfoInternal(packageName, 0, |
| Binder.getCallingUid(), userId); |
| if (applicationInfo == null) { |
| throw new ParcelableException(new PackageManager.NameNotFoundException(packageName)); |
| } |
| |
| final InstallSourceInfo installSourceInfo = snapshot.getInstallSourceInfo(packageName, |
| userId); |
| final String installerPackageName; |
| if (installSourceInfo != null) { |
| final String initiatingPackageName = installSourceInfo.getInitiatingPackageName(); |
| if (!isInstalledByAdb(initiatingPackageName)) { |
| installerPackageName = initiatingPackageName; |
| } else { |
| installerPackageName = installSourceInfo.getInstallingPackageName(); |
| } |
| } else { |
| installerPackageName = null; |
| } |
| |
| List<Pair<String, File>> 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, |
| () -> mInjector.getLocalService(PackageManagerInternal.class)); |
| 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); |
| } |
| } |
| |
| private static Bundle extrasForInstallResult(InstallRequest request) { |
| Bundle extras = null; |
| switch (request.getReturnCode()) { |
| case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: { |
| extras = new Bundle(); |
| extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION, |
| request.getOrigPermission()); |
| extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE, |
| request.getOrigPackage()); |
| break; |
| } |
| case PackageManager.INSTALL_SUCCEEDED: { |
| extras = new Bundle(); |
| extras.putBoolean(Intent.EXTRA_REPLACING, |
| request.getRemovedInfo() != null |
| && request.getRemovedInfo().mRemovedPackage != null); |
| break; |
| } |
| } |
| if (!request.getWarnings().isEmpty()) { |
| extras.putStringArrayList(PackageInstaller.EXTRA_WARNINGS, request.getWarnings()); |
| } |
| return extras; |
| } |
| |
| ArchivedPackageParcel getArchivedPackageInternal(@NonNull String packageName, int userId) { |
| Objects.requireNonNull(packageName); |
| int binderUid = Binder.getCallingUid(); |
| |
| Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(binderUid, userId, true, true, |
| "getArchivedPackage"); |
| |
| ArchivedPackageParcel archPkg = new ArchivedPackageParcel(); |
| archPkg.packageName = packageName; |
| |
| ArchiveState archiveState; |
| synchronized (mLock) { |
| PackageSetting ps = mSettings.getPackageLPr(packageName); |
| if (ps == null) { |
| return null; |
| } |
| var psi = ps.getUserStateOrDefault(userId); |
| archiveState = psi.getArchiveState(); |
| if (archiveState == null && !psi.isInstalled()) { |
| return null; |
| } |
| |
| archPkg.signingDetails = ps.getSigningDetails(); |
| |
| long longVersionCode = ps.getVersionCode(); |
| archPkg.versionCodeMajor = (int) (longVersionCode >> 32); |
| archPkg.versionCode = (int) longVersionCode; |
| |
| archPkg.targetSdkVersion = ps.getTargetSdkVersion(); |
| |
| // These get translated in flags important for user data management. |
| archPkg.defaultToDeviceProtectedStorage = String.valueOf( |
| ps.isDefaultToDeviceProtectedStorage()); |
| archPkg.requestLegacyExternalStorage = String.valueOf( |
| ps.isRequestLegacyExternalStorage()); |
| archPkg.userDataFragile = String.valueOf(ps.isUserDataFragile()); |
| } |
| |
| try { |
| if (archiveState != null) { |
| archPkg.archivedActivities = PackageArchiver.createArchivedActivities( |
| archiveState); |
| } else { |
| final int iconSize = mContext.getSystemService( |
| ActivityManager.class).getLauncherLargeIconSize(); |
| |
| var mainActivities = |
| mInstallerService.mPackageArchiver.getLauncherActivityInfos(packageName, |
| userId); |
| archPkg.archivedActivities = PackageArchiver.createArchivedActivities( |
| mainActivities, iconSize); |
| } |
| } catch (Exception e) { |
| throw new IllegalArgumentException("Package does not have a main activity", e); |
| } |
| |
| return archPkg; |
| } |
| |
| void markPackageAsArchivedIfNeeded(PackageSetting pkgSetting, |
| ArchivedPackageParcel archivePackage, int[] userIds) { |
| if (pkgSetting == null || archivePackage == null |
| || archivePackage.archivedActivities == null || userIds == null |
| || userIds.length == 0) { |
| return; |
| } |
| |
| String responsibleInstallerPackage = PackageArchiver.getResponsibleInstallerPackage( |
| pkgSetting); |
| // TODO(b/278553670) Check if responsibleInstallerPackage supports unarchival. |
| if (TextUtils.isEmpty(responsibleInstallerPackage)) { |
| Slog.e(TAG, "Can't create archive state: responsible installer is empty"); |
| return; |
| } |
| for (int userId : userIds) { |
| var archiveState = mInstallerService.mPackageArchiver.createArchiveState( |
| archivePackage, userId, responsibleInstallerPackage); |
| if (archiveState == null) { |
| continue; |
| } |
| pkgSetting |
| .setPkg(null) |
| .modifyUserState(userId) |
| .setInstalled(false) |
| .setArchiveState(archiveState); |
| } |
| } |
| |
| |
| void scheduleWriteSettings() { |
| // 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); |
| } |
| } |
| |
| private 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 scheduleWritePackageRestrictions(UserHandle user) { |
| final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); |
| scheduleWritePackageRestrictions(userId); |
| } |
| |
| void scheduleWritePackageRestrictions(int userId) { |
| invalidatePackageInfoCache(); |
| if (userId == UserHandle.USER_ALL) { |
| synchronized (mDirtyUsers) { |
| for (int aUserId : mUserManager.getUserIds()) { |
| mDirtyUsers.add(aUserId); |
| } |
| } |
| } else { |
| if (!mUserManager.exists(userId)) { |
| return; |
| } |
| synchronized (mDirtyUsers) { |
| mDirtyUsers.add(userId); |
| } |
| } |
| if (!mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS)) { |
| mBackgroundHandler.sendMessageDelayed( |
| mBackgroundHandler.obtainMessage(WRITE_DIRTY_PACKAGE_RESTRICTIONS, this), |
| WRITE_SETTINGS_DELAY); |
| } |
| } |
| |
| void writePendingRestrictions() { |
| final Integer[] dirtyUsers; |
| synchronized (mLock) { |
| mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS); |
| synchronized (mDirtyUsers) { |
| if (mDirtyUsers.isEmpty()) { |
| return; |
| } |
| dirtyUsers = mDirtyUsers.toArray(Integer[]::new); |
| mDirtyUsers.clear(); |
| } |
| } |
| mSettings.writePackageRestrictions(dirtyUsers); |
| } |
| |
| void writeSettings(boolean sync) { |
| synchronized (mLock) { |
| mHandler.removeMessages(WRITE_SETTINGS); |
| mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS); |
| writeSettingsLPrTEMP(sync); |
| synchronized (mDirtyUsers) { |
| mDirtyUsers.clear(); |
| } |
| } |
| } |
| |
| void writePackageList(int userId) { |
| synchronized (mLock) { |
| mHandler.removeMessages(WRITE_PACKAGE_LIST); |
| mSettings.writePackageListLPr(userId); |
| } |
| } |
| |
| private static final Handler.Callback BACKGROUND_HANDLER_CALLBACK = new Handler.Callback() { |
| @Override |
| public boolean handleMessage(@NonNull Message msg) { |
| switch (msg.what) { |
| case WRITE_DIRTY_PACKAGE_RESTRICTIONS: { |
| PackageManagerService pm = (PackageManagerService) msg.obj; |
| pm.writePendingRestrictions(); |
| return true; |
| } |
| case WRITE_USER_PACKAGE_RESTRICTIONS: { |
| final Runnable r = (Runnable) msg.obj; |
| r.run(); |
| return true; |
| } |
| } |
| return false; |
| } |
| }; |
| |
| /** Starts PackageManagerService. */ |
| public static PackageManagerService main(Context context, |
| Installer installer, @NonNull DomainVerificationService domainVerificationService, |
| boolean factoryTest) { |
| // 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 ServiceThread("PackageManagerBg", |
| Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); |
| backgroundThread.start(); |
| Handler backgroundHandler = new Handler(backgroundThread.getLooper(), |
| BACKGROUND_HANDLER_CALLBACK); |
| |
| PackageManagerServiceInjector injector = new PackageManagerServiceInjector( |
| context, lock, installer, installLock, new PackageAbiHelperImpl(), |
| backgroundHandler, |
| SYSTEM_PARTITIONS, |
| (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mUserNeedsBadging), |
| (i, pm) -> PermissionManagerService.create(context, |
| i.getSystemConfig().getAvailableFeatures()), |
| (i, pm) -> new UserManagerService(context, pm, |
| new UserDataPreparer(installer, installLock, context), lock), |
| (i, pm) -> new Settings(Environment.getDataDirectory(), |
| RuntimePermissionsPersistence.createInstance(), |
| i.getPermissionManagerServiceInternal(), |
| domainVerificationService, backgroundHandler, |
| lock), |
| (i, pm) -> AppsFilterImpl.create(i, |
| i.getLocalService(PackageManagerInternal.class)), |
| (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(), i.getPackageDexOptimizer(), |
| i.getInstaller(), i.getInstallLock(), i.getDynamicCodeLogger()), |
| (i, pm) -> new DynamicCodeLogger(i.getInstaller()), |
| (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(), |
| i.getInstallLock()), |
| (i, pm) -> ApexManager.getInstance(), |
| (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, i.getDisplayMetrics(), |
| pm.mCacheDir, |
| pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */, |
| (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null, |
| pm.mPackageParserCallback) /* scanningPackageParserProducer */, |
| (i, pm) -> new PackageParser2(pm.mSeparateProcesses, 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()), |
| (i, pm) -> LegacyPermissionManagerService.create(i.getContext()), |
| (i, pm) -> domainVerificationService, |
| (i, pm) -> { |
| HandlerThread thread = new ServiceThread(TAG, |
| Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); |
| thread.start(); |
| return new PackageHandler(thread.getLooper(), pm); |
| }, |
| new DefaultSystemWrapper(), |
| LocalServices::getService, |
| context::getSystemService, |
| (i, pm) -> { |
| if (useArtService()) { |
| return null; |
| } |
| try { |
| return new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm); |
| } catch (LegacyDexoptDisabledException e) { |
| throw new RuntimeException(e); |
| } |
| }, |
| (i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService( |
| Context.BACKUP_SERVICE)), |
| (i, pm) -> new SharedLibrariesImpl(pm, i), |
| (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(), |
| i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(), |
| context), |
| (i, pm) -> new UpdateOwnershipHelper(), |
| (i, pm) -> new PackageMonitorCallbackHelper()); |
| |
| if (Build.VERSION.SDK_INT <= 0) { |
| Slog.w(TAG, "**** ro.build.version.sdk not set!"); |
| } |
| |
| PackageManagerService m = new PackageManagerService(injector, factoryTest, |
| PackagePartitions.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 Computer snapshot = m.snapshotComputer(); |
| final PackageStateInternal packageState = |
| snapshot.getPackageStateInternal(packageName); |
| if (packageState == null) { |
| Slog.e(TAG, "Failed to find package setting " + packageName); |
| return; |
| } |
| AndroidPackage pkg = packageState.getPkg(); |
| SharedUserApi sharedUser = snapshot.getSharedUser( |
| packageState.getSharedUserAppId()); |
| String oldSeInfo = packageState.getSeInfo(); |
| |
| if (pkg == null) { |
| Slog.e(TAG, "Failed to find package " + packageName); |
| return; |
| } |
| final String newSeInfo = SELinuxMMAC.getSeInfo(packageState, pkg, sharedUser, |
| m.mInjector.getCompatibility()); |
| |
| if (!newSeInfo.equals(oldSeInfo)) { |
| Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " |
| + oldSeInfo + " to: " + newSeInfo); |
| m.commitPackageStateMutation(null, packageName, |
| state -> state.setOverrideSeInfo(newSeInfo)); |
| m.mAppDataHelper.prepareAppDataAfterInstallLIF(pkg); |
| } |
| } |
| }; |
| |
| injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES, |
| selinuxChangeListener); |
| injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES, |
| selinuxChangeListener); |
| |
| m.installAllowlistedSystemPackages(); |
| IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl(); |
| ServiceManager.addService("package", iPackageManager); |
| final PackageManagerNative pmn = new PackageManagerNative(m); |
| ServiceManager.addService("package_native", pmn); |
| return m; |
| } |
| |
| /** Install/uninstall system packages for all users based on their user-type, as applicable. */ |
| private void installAllowlistedSystemPackages() { |
| if (mUserManager.installWhitelistedSystemPackages(isFirstBoot(), isDeviceUpgrading(), |
| mExistingPackages)) { |
| scheduleWritePackageRestrictions(UserHandle.USER_ALL); |
| scheduleWriteSettings(); |
| } |
| } |
| |
| // Link watchables to the class |
| @SuppressWarnings("GuardedBy") |
| private void registerObservers(boolean verify) { |
| // Null check to handle nullable test parameters |
| if (mPackages != null) { |
| mPackages.registerObserver(mWatcher); |
| } |
| if (mSharedLibraries != null) { |
| mSharedLibraries.registerObserver(mWatcher); |
| } |
| if (mInstrumentation != null) { |
| mInstrumentation.registerObserver(mWatcher); |
| } |
| if (mWebInstantAppsDisabled != null) { |
| mWebInstantAppsDisabled.registerObserver(mWatcher); |
| } |
| if (mAppsFilter != null) { |
| mAppsFilter.registerObserver(mWatcher); |
| } |
| if (mInstantAppRegistry != null) { |
| mInstantAppRegistry.registerObserver(mWatcher); |
| } |
| if (mSettings != null) { |
| mSettings.registerObserver(mWatcher); |
| } |
| if (mIsolatedOwners != null) { |
| mIsolatedOwners.registerObserver(mWatcher); |
| } |
| if (mComponentResolver != null) { |
| mComponentResolver.registerObserver(mWatcher); |
| } |
| if (mFrozenPackages != null) { |
| mFrozenPackages.registerObserver(mWatcher); |
| } |
| if (verify) { |
| // 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)); |
| } |
| } |
| |
| /** |
| * An 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 PackageManagerServiceInjector injector, |
| @NonNull PackageManagerServiceTestParams testParams) { |
| mInjector = injector; |
| mInjector.bootstrap(this); |
| mAppsFilter = injector.getAppsFilter(); |
| mComponentResolver = injector.getComponentResolver(); |
| mContext = injector.getContext(); |
| mInstaller = injector.getInstaller(); |
| mInstallLock = injector.getInstallLock(); |
| mLock = injector.getLock(); |
| mPackageStateWriteLock = mLock; |
| mPermissionManager = injector.getPermissionManagerServiceInternal(); |
| mSettings = injector.getSettings(); |
| mUserManager = injector.getUserManagerService(); |
| mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager); |
| mDomainVerificationManager = injector.getDomainVerificationManagerInternal(); |
| mHandler = injector.getHandler(); |
| mBackgroundHandler = injector.getBackgroundHandler(); |
| mSharedLibraries = injector.getSharedLibrariesImpl(); |
| |
| mApexManager = testParams.apexManager; |
| mArtManagerService = testParams.artManagerService; |
| mAvailableFeatures = testParams.availableFeatures; |
| mBackgroundDexOptService = testParams.backgroundDexOptService; |
| mDefParseFlags = testParams.defParseFlags; |
| mDefaultAppProvider = testParams.defaultAppProvider; |
| mLegacyPermissionManager = testParams.legacyPermissionManagerInternal; |
| mDexManager = testParams.dexManager; |
| mDynamicCodeLogger = testParams.dynamicCodeLogger; |
| mFactoryTest = testParams.factoryTest; |
| mIncrementalManager = testParams.incrementalManager; |
| mInstallerService = testParams.installerService; |
| mInstantAppRegistry = testParams.instantAppRegistry; |
| mChangedPackagesTracker = testParams.changedPackagesTracker; |
| mInstantAppResolverConnection = testParams.instantAppResolverConnection; |
| mInstantAppResolverSettingsComponent = testParams.instantAppResolverSettingsComponent; |
| mIsPreNMR1Upgrade = testParams.isPreNmr1Upgrade; |
| mIsPreQUpgrade = testParams.isPreQupgrade; |
| mIsUpgrade = testParams.isUpgrade; |
| mMetrics = testParams.Metrics; |
| mModuleInfoProvider = testParams.moduleInfoProvider; |
| mMoveCallbacks = testParams.moveCallbacks; |
| mOverlayConfig = testParams.overlayConfig; |
| mPackageDexOptimizer = testParams.packageDexOptimizer; |
| mPackageParserCallback = testParams.packageParserCallback; |
| mPendingBroadcasts = testParams.pendingPackageBroadcasts; |
| mTestUtilityService = testParams.testUtilityService; |
| mProcessLoggingHandler = testParams.processLoggingHandler; |
| mProtectedPackages = testParams.protectedPackages; |
| mSeparateProcesses = testParams.separateProcesses; |
| mRequiredVerifierPackages = testParams.requiredVerifierPackages; |
| 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; |
| mAmbientContextDetectionPackage = testParams.ambientContextDetectionPackage; |
| mWearableSensingPackage = testParams.wearableSensingPackage; |
| mConfiguratorPackage = testParams.configuratorPackage; |
| mAppPredictionServicePackage = testParams.appPredictionServicePackage; |
| mIncidentReportApproverPackage = testParams.incidentReportApproverPackage; |
| mServicesExtensionPackageName = testParams.servicesExtensionPackageName; |
| mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName; |
| mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage; |
| mResolveComponentName = testParams.resolveComponentName; |
| mRequiredSdkSandboxPackage = testParams.requiredSdkSandboxPackage; |
| mInitialNonStoppedSystemPackages = testParams.initialNonStoppedSystemPackages; |
| mShouldStopSystemPackagesByDefault = testParams.shouldStopSystemPackagesByDefault; |
| |
| mLiveComputer = createLiveComputer(); |
| mSnapshotStatistics = null; |
| |
| mPackages.putAll(testParams.packages); |
| mFreeStorageHelper = testParams.freeStorageHelper; |
| mSdkVersion = testParams.sdkVersion; |
| mAppInstallDir = testParams.appInstallDir; |
| mIsEngBuild = testParams.isEngBuild; |
| mIsUserDebugBuild = testParams.isUserDebugBuild; |
| mIncrementalVersion = testParams.incrementalVersion; |
| mDomainVerificationConnection = new DomainVerificationConnection(this); |
| |
| mBroadcastHelper = testParams.broadcastHelper; |
| mAppDataHelper = testParams.appDataHelper; |
| mInstallPackageHelper = testParams.installPackageHelper; |
| mRemovePackageHelper = testParams.removePackageHelper; |
| mInitAppsHelper = testParams.initAndSystemPackageHelper; |
| mDeletePackageHelper = testParams.deletePackageHelper; |
| mPreferredActivityHelper = testParams.preferredActivityHelper; |
| mResolveIntentHelper = testParams.resolveIntentHelper; |
| mDexOptHelper = testParams.dexOptHelper; |
| mSuspendPackageHelper = testParams.suspendPackageHelper; |
| mDistractingPackageHelper = testParams.distractingPackageHelper; |
| |
| mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); |
| |
| mStorageEventHelper = testParams.storageEventHelper; |
| mPackageMonitorCallbackHelper = testParams.packageMonitorCallbackHelper; |
| |
| registerObservers(false); |
| invalidatePackageInfoCache(); |
| } |
| |
| public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest, |
| final String partitionsFingerprint, 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(); |
| mPackageStateWriteLock = mLock; |
| mInstallLock = injector.getInstallLock(); |
| LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES); |
| EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, |
| SystemClock.uptimeMillis()); |
| |
| mContext = injector.getContext(); |
| mFactoryTest = factoryTest; |
| mMetrics = injector.getDisplayMetrics(); |
| mInstaller = injector.getInstaller(); |
| mFreeStorageHelper = new FreeStorageHelper(this); |
| |
| // Create sub-components that provide services / data. Order here is important. |
| t.traceBegin("createSubComponents"); |
| |
| // Expose private service for system components to use. |
| LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl()); |
| LocalManagerRegistry.addManager(PackageManagerLocal.class, |
| new PackageManagerLocalImpl(this)); |
| LocalServices.addService(TestUtilityService.class, this); |
| mTestUtilityService = LocalServices.getService(TestUtilityService.class); |
| mUserManager = injector.getUserManagerService(); |
| mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager); |
| 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); |
| } |
| |
| @Override |
| public Set<String> getHiddenApiWhitelistedApps() { |
| return SystemConfig.getInstance().getHiddenApiWhitelistedApps(); |
| } |
| |
| @Override |
| public Set<String> getInstallConstraintsAllowlist() { |
| return SystemConfig.getInstance().getInstallConstraintsAllowlist(); |
| } |
| }; |
| |
| // 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(); |
| mDynamicCodeLogger = injector.getDynamicCodeLogger(); |
| mBackgroundDexOptService = injector.getBackgroundDexOptService(); |
| mArtManagerService = injector.getArtManagerService(); |
| mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper()); |
| mSharedLibraries = mInjector.getSharedLibrariesImpl(); |
| mBackgroundHandler = injector.getBackgroundHandler(); |
| |
| 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(); |
| |
| mChangedPackagesTracker = new ChangedPackagesTracker(); |
| |
| mAppInstallDir = new File(Environment.getDataDirectory(), "app"); |
| |
| mDomainVerificationConnection = new DomainVerificationConnection(this); |
| mDomainVerificationManager = injector.getDomainVerificationManagerInternal(); |
| mDomainVerificationManager.setConnection(mDomainVerificationConnection); |
| |
| mBroadcastHelper = new BroadcastHelper(mInjector); |
| mPackageMonitorCallbackHelper = injector.getPackageMonitorCallbackHelper(); |
| mAppDataHelper = new AppDataHelper(this); |
| mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper, mBroadcastHelper); |
| mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper, |
| mBroadcastHelper); |
| mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper, mRemovePackageHelper, |
| mDeletePackageHelper, mBroadcastHelper); |
| |
| mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager, |
| mInjector.getUserManagerInternal(), mDeletePackageHelper); |
| |
| mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); |
| mPreferredActivityHelper = new PreferredActivityHelper(this, mBroadcastHelper); |
| mResolveIntentHelper = new ResolveIntentHelper(mContext, mPreferredActivityHelper, |
| injector.getCompatibility(), mUserManager, mDomainVerificationManager, |
| mUserNeedsBadging, () -> mResolveInfo, () -> mInstantAppInstallerActivity, |
| injector.getBackgroundHandler()); |
| mDexOptHelper = new DexOptHelper(this); |
| mSuspendPackageHelper = new SuspendPackageHelper(this, mInjector, mBroadcastHelper, |
| mProtectedPackages); |
| mDistractingPackageHelper = new DistractingPackageHelper(this, mBroadcastHelper, |
| mSuspendPackageHelper); |
| mStorageEventHelper = new StorageEventHelper(this, mDeletePackageHelper, |
| mRemovePackageHelper); |
| |
| 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. |
| mSnapshotStatistics = new SnapshotStatistics(); |
| sSnapshotPendingVersion.incrementAndGet(); |
| mLiveComputer = createLiveComputer(); |
| registerObservers(true); |
| } |
| |
| Computer computer = mLiveComputer; |
| // CHECKSTYLE:OFF IndentationCheck |
| synchronized (mInstallLock) { |
| // writer |
| synchronized (mLock) { |
| mHandler = injector.getHandler(); |
| mProcessLoggingHandler = new ProcessLoggingHandler(); |
| Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); |
| |
| ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig |
| = systemConfig.getSharedLibraries(); |
| final int builtInLibCount = libConfig.size(); |
| for (int i = 0; i < builtInLibCount; i++) { |
| mSharedLibraries.addBuiltInSharedLibraryLPw(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 = |
| computer.getSharedLibraryInfo(entry.dependencies[j], undefinedVersion); |
| if (dependency != null) { |
| computer.getSharedLibraryInfo(name, undefinedVersion) |
| .addDependency(dependency); |
| } |
| } |
| } |
| |
| SELinuxMMAC.readInstallPolicy(); |
| |
| t.traceBegin("loadFallbacks"); |
| FallbackCategoryProvider.loadFallbacks(); |
| t.traceEnd(); |
| |
| t.traceBegin("read user settings"); |
| mFirstBoot = !mSettings.readLPw(computer, |
| mInjector.getUserManagerInternal().getUsers( |
| /* excludePartial= */ true, |
| /* excludeDying= */ false, |
| /* excludePreCreated= */ false)); |
| t.traceEnd(); |
| |
| if (mFirstBoot) { |
| t.traceBegin("setFirstBoot: "); |
| try { |
| mInstaller.setFirstBoot(); |
| } catch (InstallerException e) { |
| Slog.w(TAG, "Could not set First Boot: ", e); |
| } |
| t.traceEnd(); |
| } |
| |
| mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); |
| mPermissionManager.readLegacyPermissionStateTEMP(); |
| |
| if (mFirstBoot) { |
| DexOptHelper.requestCopyPreoptedFiles(); |
| } |
| |
| 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!"); |
| } |
| |
| final VersionInfo ver = mSettings.getInternalVersion(); |
| mIsUpgrade = |
| !partitionsFingerprint.equals(ver.fingerprint); |
| if (mIsUpgrade) { |
| PackageManagerServiceUtils.logCriticalInfo(Log.INFO, |
| "Upgrading from " + ver.fingerprint + " (" + ver.buildFingerprint + ") to " |
| + PackagePartitions.FINGERPRINT + " (" + Build.FINGERPRINT + ")"); |
| } |
| |
| mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper, |
| mInjector.getSystemPartitions()); |
| |
| // when upgrading from pre-M, promote system app permissions from install to runtime |
| mPromoteSystemApps = |
| mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1; |
| |
| mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1; |
| mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q; |
| |
| final WatchedArrayMap<String, PackageSetting> packageSettings = |
| mSettings.getPackagesLocked(); |
| |
| if (isDeviceUpgrading()) { |
| // Save the names of pre-existing packages prior to scanning, so we can determine |
| // which system packages are completely new due to an upgrade. |
| mExistingPackages = new ArraySet<>(packageSettings.size()); |
| for (int i = 0; i < packageSettings.size(); i++) { |
| mExistingPackages.add(packageSettings.valueAt(i).getPackageName()); |
| } |
| |
| // Triggering {@link com.android.server.pm.crossprofile. |
| // CrossProfileIntentFilterHelper.updateDefaultCrossProfileIntentFilter} to update |
| // {@link CrossProfileIntentFilter}s between eligible users and their parent |
| t.traceBegin("cross profile intent filter update"); |
| mInjector.getCrossProfileIntentFilterHelper() |
| .updateDefaultCrossProfileIntentFilter(); |
| t.traceEnd(); |
| } |
| |
| mCacheDir = PackageManagerServiceUtils.preparePackageParserCache( |
| mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion); |
| |
| mInitialNonStoppedSystemPackages = mInjector.getSystemConfig() |
| .getInitialNonStoppedSystemPackages(); |
| mShouldStopSystemPackagesByDefault = mContext.getResources() |
| .getBoolean(R.bool.config_stopSystemPackagesByDefault); |
| |
| final int[] userIds = mUserManager.getUserIds(); |
| PackageParser2 packageParser = mInjector.getScanningCachingPackageParser(); |
| mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds, |
| startTime); |
| mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime); |
| packageParser.close(); |
| |
| mRequiredVerifierPackages = getRequiredButNotReallyRequiredVerifiersLPr(computer); |
| mRequiredInstallerPackage = getRequiredInstallerLPr(computer); |
| mRequiredUninstallerPackage = getRequiredUninstallerLPr(computer); |
| |
| // PermissionController hosts default permission granting and role management, so it's a |
| // critical part of the core system. |
| mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(computer); |
| |
| // Resolve the storage manager. |
| mStorageManagerPackage = getStorageManagerPackageName(computer); |
| |
| // Resolve protected action filters. Only the setup wizard is allowed to |
| // have a high priority filter for these actions. |
| mSetupWizardPackage = getSetupWizardPackageNameImpl(computer); |
| mComponentResolver.fixProtectedFilterPriorities(mSetupWizardPackage); |
| |
| mDefaultTextClassifierPackage = ensureSystemPackageName(computer, |
| mContext.getString(R.string.config_servicesExtensionPackage)); |
| mSystemTextClassifierPackageName = ensureSystemPackageName(computer, |
| mContext.getString(R.string.config_defaultTextClassifierPackage)); |
| mConfiguratorPackage = ensureSystemPackageName(computer, |
| mContext.getString(R.string.config_deviceConfiguratorPackageName)); |
| mAppPredictionServicePackage = ensureSystemPackageName(computer, |
| getPackageFromComponentString(R.string.config_defaultAppPredictionService)); |
| mIncidentReportApproverPackage = ensureSystemPackageName(computer, |
| mContext.getString(R.string.config_incidentReportApproverPackage)); |
| mRetailDemoPackage = getRetailDemoPackageName(); |
| mOverlayConfigSignaturePackage = ensureSystemPackageName(computer, |
| mInjector.getSystemConfig().getOverlayConfigSignaturePackage()); |
| mRecentsPackage = ensureSystemPackageName(computer, |
| getPackageFromComponentString(R.string.config_recentsComponentName)); |
| mAmbientContextDetectionPackage = ensureSystemPackageName(computer, |
| getPackageFromComponentString( |
| R.string.config_defaultAmbientContextDetectionService)); |
| mWearableSensingPackage = ensureSystemPackageName(computer, |
| getPackageFromComponentString( |
| R.string.config_defaultWearableSensingService)); |
| |
| // Now that we know all of the shared libraries, update all clients to have |
| // the correct library paths. |
| mSharedLibraries.updateAllSharedLibrariesLPw( |
| 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<String> changedAbiCodePath = |
| ScanPackageUtils.applyAdjustedAbiToSharedUser(setting, |
| null /*scannedPackage*/, |
| mInjector.getAbiHelper().getAdjustedAbiForSharedUser( |
| setting.getPackageStates(), null /*scannedPackage*/)); |
| if (!useArtService() && // Skip for ART Service since it has its own dex file GC. |
| 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 (LegacyDexoptDisabledException e) { |
| throw new RuntimeException(e); |
| } 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 partitions 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, "Partitions fingerprint changed from " + ver.fingerprint + " to " |
| + PackagePartitions.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, then we need to initialize the |
| // default preferred apps across all defined users. |
| if (mPromoteSystemApps || mFirstBoot) { |
| final List<UserInfo> users = mInjector.getUserManagerInternal().getUsers(true); |
| for (int i = 0; i < users.size(); i++) { |
| mSettings.applyDefaultPreferredAppsLPw(users.get(i).id); |
| |
| } |
| } |
| |
| // If this is first boot after an OTA, 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) { |
| 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.getVolumeUuid())) { |
| // No apps are running this early, so no need to freeze |
| mAppDataHelper.clearAppDataLIF(ps.getPkg(), 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.buildFingerprint = Build.FINGERPRINT; |
| ver.fingerprint = PackagePartitions.FINGERPRINT; |
| } |
| |
| // Defer the app data fixup until we are done with app data clearing above. |
| mPrepareAppDataFuture = mAppDataHelper.fixAppsDataOnBoot(); |
| |
| // Legacy existing (installed before Q) non-system apps to hide |
| // their icons in launcher. |
| if (mIsPreQUpgrade) { |
| Slog.i(TAG, "Allowlisting 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.getFlags() & 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()); |
| |
| ComponentName intentFilterVerifierComponent = |
| getIntentFilterVerifierComponentNameLPr(computer); |
| ComponentName domainVerificationAgent = |
| getDomainVerificationAgentComponentNameLPr(computer); |
| |
| DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy( |
| intentFilterVerifierComponent, domainVerificationAgent, mContext, |
| mDomainVerificationManager, mDomainVerificationManager.getCollector(), |
| mDomainVerificationConnection); |
| |
| mDomainVerificationManager.setProxy(domainVerificationProxy); |
| |
| mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer); |
| mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer, |
| PackageManager.SYSTEM_SHARED_LIBRARY_SHARED, |
| SharedLibraryInfo.VERSION_UNDEFINED); |
| |
| mSettings.setPermissionControllerVersion( |
| computer.getPackageInfo(mRequiredPermissionControllerPackage, 0, |
| UserHandle.USER_SYSTEM).getLongVersionCode()); |
| |
| // Resolve the sdk sandbox package |
| mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName(computer); |
| |
| // Initialize InstantAppRegistry's Instant App list for all users. |
| forEachPackageState(computer, packageState -> { |
| var pkg = packageState.getAndroidPackage(); |
| if (pkg == null || packageState.isSystem()) { |
| return; |
| } |
| for (int userId : userIds) { |
| if (!packageState.getUserStateOrDefault(userId).isInstantApp() |
| || !packageState.getUserStateOrDefault(userId).isInstalled()) { |
| continue; |
| } |
| mInstantAppRegistry.addInstantApp(userId, packageState.getAppId()); |
| } |
| }); |
| |
| mInstallerService = mInjector.getPackageInstallerService(); |
| final ComponentName instantAppResolverComponent = getInstantAppResolver(computer); |
| if (instantAppResolverComponent != null) { |
| if (DEBUG_INSTANT) { |
| Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent); |
| } |
| mInstantAppResolverConnection = |
| mInjector.getInstantAppResolverConnection(instantAppResolverComponent); |
| mInstantAppResolverSettingsComponent = |
| getInstantAppResolverSettingsLPr(computer, |
| 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<Integer, List<PackageInfo>> userPackages = new HashMap<>(); |
| for (int userId : userIds) { |
| userPackages.put(userId, computer.getInstalledPackages(/*flags*/ 0, userId) |
| .getList()); |
| } |
| mDexManager.load(userPackages); |
| mDynamicCodeLogger.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); |
| } |
| |
| // If this is first boot or first boot after OTA then set the file path to the app |
| // metadata files for preloaded packages. |
| if (mFirstBoot || isDeviceUpgrading()) { |
| ArrayMap<String, String> paths = systemConfig.getAppMetadataFilePaths(); |
| for (Map.Entry<String, String> entry : paths.entrySet()) { |
| String pkgName = entry.getKey(); |
| String path = entry.getValue(); |
| File file = new File(path); |
| if (!file.exists()) { |
| path = null; |
| } |
| PackageSetting disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(pkgName); |
| if (disabledPkgSetting == null) { |
| PackageSetting pkgSetting = mSettings.getPackageLPr(pkgName); |
| if (pkgSetting != null) { |
| pkgSetting.setAppMetadataFilePath(path); |
| } else { |
| Slog.w(TAG, "Cannot set app metadata file for nonexistent package " |
| + pkgName); |
| } |
| } else { |
| disabledPkgSetting.setAppMetadataFilePath(path); |
| } |
| } |
| } |
| |
| // Rebuild the live computer since some attributes have been rebuilt. |
| mLiveComputer = createLiveComputer(); |
| |
| } // synchronized (mLock) |
| } // synchronized (mInstallLock) |
| // CHECKSTYLE:ON IndentationCheck |
| |
| mModuleInfoProvider = mInjector.getModuleInfoProvider(); |
| |
| mInjector.getSystemWrapper().enablePackageCaches(); |
| |
| // 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"); |
| } |
| |
| @GuardedBy("mLock") |
| void updateInstantAppInstallerLocked(String modifiedPackage) { |
| // we're only interested in updating the installer application 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()); |
| } |
| |
| public boolean isFirstBoot() { |
| // allow instant applications |
| return mFirstBoot; |
| } |
| |
| 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 */); |
| } |
| |
| @NonNull |
| private String[] getRequiredButNotReallyRequiredVerifiersLPr(@NonNull Computer computer) { |
| final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); |
| |
| final List<ResolveInfo> matches = |
| mResolveIntentHelper.queryIntentReceiversInternal(computer, intent, |
| PACKAGE_MIME_TYPE, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, |
| UserHandle.USER_SYSTEM, Binder.getCallingUid()); |
| final int size = matches.size(); |
| if (size == 0) { |
| Log.w(TAG, "There should probably be a verifier, but, none were found"); |
| return EmptyArray.STRING; |
| } else if (size <= REQUIRED_VERIFIERS_MAX_COUNT) { |
| String[] verifiers = new String[size]; |
| for (int i = 0; i < size; ++i) { |
| verifiers[i] = matches.get(i).getComponentInfo().packageName; |
| if (TextUtils.isEmpty(verifiers[i])) { |
| throw new RuntimeException("Invalid verifier: " + matches); |
| } |
| } |
| return verifiers; |
| } |
| throw new RuntimeException( |
| "There must be no more than " + REQUIRED_VERIFIERS_MAX_COUNT + " verifiers; found " |
| + matches); |
| } |
| |
| @NonNull |
| private String getRequiredSharedLibrary(@NonNull Computer snapshot, @NonNull String name, |
| int version) { |
| SharedLibraryInfo libraryInfo = snapshot.getSharedLibraryInfo(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(@NonNull Computer computer) { |
| String configServicesExtensionPackage = mContext.getString( |
| R.string.config_servicesExtensionPackage); |
| if (TextUtils.isEmpty(configServicesExtensionPackage)) { |
| throw new RuntimeException( |
| "Required services extension package failed due to " |
| + "config_servicesExtensionPackage is empty."); |
| } |
| String servicesExtensionPackage = ensureSystemPackageName(computer, |
| configServicesExtensionPackage); |
| if (TextUtils.isEmpty(servicesExtensionPackage)) { |
| throw new RuntimeException( |
| "Required services extension package is missing, " |
| + "config_servicesExtensionPackage had defined with " |
| + configServicesExtensionPackage |
| + ", but can not find the package info on the system image, check if " |
| + "the package has a problem."); |
| } |
| return servicesExtensionPackage; |
| } |
| |
| private @NonNull String getRequiredInstallerLPr(@NonNull Computer computer) { |
| 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<ResolveInfo> matches = computer.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(@NonNull Computer computer) { |
| 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 = mResolveIntentHelper.resolveIntentInternal(computer, intent, |
| null, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, |
| 0 /*privateResolveFlags*/, UserHandle.USER_SYSTEM, false, Binder.getCallingUid()); |
| 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(@NonNull Computer computer) { |
| final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS); |
| intent.addCategory(Intent.CATEGORY_DEFAULT); |
| |
| final List<ResolveInfo> matches = computer.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); |
| } |
| } |
| |
| @NonNull |
| private ComponentName getIntentFilterVerifierComponentNameLPr(@NonNull Computer computer) { |
| final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); |
| |
| final List<ResolveInfo> matches = |
| mResolveIntentHelper.queryIntentReceiversInternal(computer, intent, |
| PACKAGE_MIME_TYPE, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, |
| UserHandle.USER_SYSTEM, Binder.getCallingUid()); |
| 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(@NonNull Computer computer) { |
| Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION); |
| List<ResolveInfo> matches = |
| mResolveIntentHelper.queryIntentReceiversInternal(computer, intent, null, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, |
| UserHandle.USER_SYSTEM, Binder.getCallingUid()); |
| 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 (computer.isComponentEffectivelyEnabled(cur.getComponentInfo(), |
| UserHandle.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; |
| } |
| |
| @Nullable ComponentName getInstantAppResolver(@NonNull Computer snapshot) { |
| 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<ResolveInfo> resolvers = snapshot.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<String> 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 Computer computer = snapshotComputer(); |
| final Intent intent = new Intent(); |
| intent.addCategory(Intent.CATEGORY_DEFAULT); |
| intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); |
| List<ResolveInfo> matches = null; |
| for (String action : orderedActions) { |
| intent.setAction(action); |
| matches = computer.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<ResolveInfo> 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 Computer computer, |
| @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<ResolveInfo> matches = computer.queryIntentActivitiesInternal(intent, null, |
| resolveFlags, UserHandle.USER_SYSTEM); |
| if (matches.isEmpty()) { |
| return null; |
| } |
| return matches.get(0).getComponentInfo().getComponentName(); |
| } |
| |
| 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); |
| } |
| |
| /** |
| * Blocking call to clear all cached app data above quota. |
| */ |
| public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException { |
| synchronized (mInstallLock) { |
| // To avoid refactoring Installer.freeCache() and InstalldNativeService.freeCache(), |
| // Long.MAX_VALUE is passed as an argument which is used in neither of two methods |
| // when FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES is set |
| try { |
| mInstaller.freeCache(volumeUuid, Long.MAX_VALUE, Installer.FLAG_FREE_CACHE_V2 |
| | Installer.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES); |
| } catch (InstallerException ignored) { |
| } |
| } |
| return; |
| } |
| |
| /** |
| * 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, |
| @StorageManager.AllocateFlags int flags) throws IOException { |
| mFreeStorageHelper.freeStorage(volumeUuid, bytes, flags); |
| } |
| |
| int freeCacheForInstallation(int recommendedInstallLocation, PackageLite pkgLite, |
| String resolvedPath, String mPackageAbiOverride, int installFlags) { |
| return mFreeStorageHelper.freeCacheForInstallation(recommendedInstallLocation, pkgLite, |
| resolvedPath, mPackageAbiOverride, installFlags); |
| } |
| |
| public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) { |
| return mModuleInfoProvider.getModuleInfo(packageName, flags); |
| } |
| |
| void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) { |
| mChangedPackagesTracker.updateSequenceNumber(pkgSetting.getPackageName(), userList); |
| } |
| |
| public boolean hasSystemFeature(String name, int version) { |
| // allow instant applications |
| synchronized (mAvailableFeatures) { |
| final FeatureInfo feat = mAvailableFeatures.get(name); |
| if (feat == null) { |
| return false; |
| } else { |
| return feat.version >= version; |
| } |
| } |
| } |
| |
| // NOTE: Can't remove due to unsupported app usage |
| public int checkPermission(String permName, String pkgName, int userId) { |
| return mPermissionManager.checkPermission(pkgName, permName, Context.DEVICE_ID_DEFAULT, |
| userId); |
| } |
| |
| public String getSdkSandboxPackageName() { |
| return mRequiredSdkSandboxPackage; |
| } |
| |
| String getPackageInstallerPackageName() { |
| return mRequiredInstallerPackage; |
| } |
| |
| void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, |
| Intent origIntent, String resolvedType, String callingPackage, |
| @Nullable String callingFeatureId, boolean isRequesterInstantApp, |
| Bundle verificationBundle, int userId) { |
| final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO, |
| new InstantAppRequest(responseObj, origIntent, resolvedType, |
| callingPackage, callingFeatureId, isRequesterInstantApp, userId, |
| verificationBundle, false /*resolveForStart*/, |
| responseObj.hostDigestPrefixSecure, responseObj.token)); |
| mHandler.sendMessage(msg); |
| } |
| |
| // findPreferredActivityBody returns two items: a "things changed" flag and a |
| // ResolveInfo, which is the preferred activity itself. |
| static class FindPreferredActivityBodyResult { |
| boolean mChanged; |
| ResolveInfo mPreferredResolveInfo; |
| } |
| |
| public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(@NonNull Computer snapshot, |
| Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, |
| @UserIdInt int userId) { |
| return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal( |
| snapshot, intent, resolvedType, flags, userId, Binder.getCallingUid())); |
| } |
| |
| public static void reportSettingsProblem(int priority, String msg) { |
| logCriticalInfo(priority, msg); |
| } |
| |
| // TODO:(b/135203078): Move to parsing |
| static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { |
| // Derive the new package synthetic package name |
| parsedPackage.setPackageName(toStaticSharedLibraryPackageName( |
| parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibraryVersion())); |
| } |
| |
| private static String toStaticSharedLibraryPackageName( |
| String packageName, long libraryVersion) { |
| return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion; |
| } |
| |
| public void performFstrimIfNeeded() { |
| mFreeStorageHelper.performFstrimIfNeeded(); |
| } |
| |
| public void updatePackagesIfNeeded() { |
| mDexOptHelper.performPackageDexOptUpgradeIfNeeded(); |
| } |
| |
| private void notifyPackageUseInternal(String packageName, int reason) { |
| long time = System.currentTimeMillis(); |
| synchronized (mLock) { |
| final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); |
| if (pkgSetting == null) { |
| return; |
| } |
| pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, time); |
| } |
| } |
| |
| /*package*/ DexManager getDexManager() { |
| return mDexManager; |
| } |
| |
| /*package*/ DexOptHelper getDexOptHelper() { |
| return mDexOptHelper; |
| } |
| |
| /*package*/ DynamicCodeLogger getDynamicCodeLogger() { |
| return mDynamicCodeLogger; |
| } |
| |
| public void shutdown() { |
| mCompilerStats.writeNow(); |
| mDexManager.writePackageDexUsageNow(); |
| mDynamicCodeLogger.writeNow(); |
| PackageWatchdog.getInstance(mContext).writeNow(); |
| |
| synchronized (mLock) { |
| mPackageUsage.writeNow(mSettings.getPackagesLocked()); |
| |
| if (mHandler.hasMessages(WRITE_SETTINGS) |
| || mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS) |
| || mHandler.hasMessages(WRITE_PACKAGE_LIST)) { |
| writeSettings(/*sync=*/true); |
| } |
| } |
| } |
| |
| @NonNull |
| int[] resolveUserIds(int userId) { |
| return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; |
| } |
| |
| private void setUpInstantAppInstallerActivityLP(ActivityInfo installerActivity) { |
| if (installerActivity == null) { |
| if (DEBUG_INSTANT) { |
| Slog.d(TAG, "Clear ephemeral installer activity"); |
| } |
| mInstantAppInstallerActivity = null; |
| onChanged(); |
| return; |
| } |
| |
| if (DEBUG_INSTANT) { |
| Slog.d(TAG, "Set ephemeral installer activity: " |
| + installerActivity.getComponentName()); |
| } |
| // Set up information for ephemeral installer activity |
| mInstantAppInstallerActivity = installerActivity; |
| mInstantAppInstallerActivity.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
| | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; |
| mInstantAppInstallerActivity.exported = true; |
| mInstantAppInstallerActivity.enabled = true; |
| mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity; |
| mInstantAppInstallerInfo.priority = 1; |
| mInstantAppInstallerInfo.preferredOrder = 1; |
| mInstantAppInstallerInfo.isDefault = true; |
| mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART |
| | IntentFilter.MATCH_ADJUSTMENT_NORMAL; |
| onChanged(); |
| } |
| |
| void killApplication(String pkgName, @AppIdInt int appId, String reason, int exitInfoReason) { |
| killApplication(pkgName, appId, UserHandle.USER_ALL, reason, exitInfoReason); |
| } |
| |
| void killApplication(String pkgName, @AppIdInt int appId, |
| @UserIdInt int userId, String reason, int exitInfoReason) { |
| // Request the ActivityManager to kill the process(only for existing packages) |
| // so that we do not end up in a confused state while the user is still using the older |
| // version of the application while the new one gets installed. |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| IActivityManager am = ActivityManager.getService(); |
| if (am != null) { |
| try { |
| am.killApplication(pkgName, appId, userId, reason, exitInfoReason); |
| } catch (RemoteException e) { |
| } |
| } |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| @Override |
| public void notifyPackageAdded(String packageName, int uid) { |
| mPackageObserverHelper.notifyAdded(packageName, uid); |
| } |
| |
| @Override |
| public void notifyPackageChanged(String packageName, int uid) { |
| mPackageObserverHelper.notifyChanged(packageName, uid); |
| } |
| |
| @Override |
| public void notifyPackageRemoved(String packageName, int uid) { |
| mPackageObserverHelper.notifyRemoved(packageName, uid); |
| UserPackage.removeFromCache(UserHandle.getUserId(uid), packageName); |
| } |
| |
| boolean isUserRestricted(int userId, String restrictionKey) { |
| Bundle restrictions = mUserManager.getUserRestrictions(userId); |
| if (restrictions.getBoolean(restrictionKey, false)) { |
| Log.w(TAG, "User is restricted: " + restrictionKey); |
| return true; |
| } |
| return false; |
| } |
| |
| private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot, |
| boolean quarantined, UserPackage suspender, int callingUid, int targetUserId, |
| String callingMethod) { |
| if (callingUid == Process.ROOT_UID |
| // Need to compare app-id to allow system dialogs access on secondary users |
| || UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { |
| return; |
| } |
| |
| final String ownerPackage = |
| mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId); |
| if (ownerPackage != null) { |
| final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, targetUserId); |
| if (ownerUid == callingUid) { |
| return; |
| } |
| } |
| |
| if (quarantined) { |
| final boolean hasQuarantineAppsPerm = mContext.checkCallingOrSelfPermission( |
| android.Manifest.permission.QUARANTINE_APPS) == PERMISSION_GRANTED; |
| // TODO: b/305256093 - In order to facilitate testing, temporarily allowing apps |
| // with SUSPEND_APPS permission to quarantine apps. Remove this once the testing |
| // is done and this is no longer needed. |
| if (!hasQuarantineAppsPerm) { |
| mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, |
| callingMethod); |
| } |
| } else { |
| mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, |
| callingMethod); |
| } |
| |
| final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId); |
| final boolean allowedPackageUid = packageUid == callingUid; |
| // TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL |
| final boolean allowedShell = callingUid == SHELL_UID |
| && UserHandle.isSameApp(packageUid, callingUid); |
| |
| if (!allowedShell && !allowedPackageUid) { |
| throw new SecurityException("Suspending package " + suspender.packageName |
| + " in user " + targetUserId + " does not belong to calling uid " + callingUid); |
| } |
| } |
| |
| void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage, |
| @UserIdInt int suspendingUserId) { |
| // TODO: This can be replaced by a special parameter to iterate all packages, rather than |
| // this weird pre-collect of all packages. |
| final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]); |
| final Predicate<UserPackage> suspenderPredicate = |
| UserPackage.of(suspendingUserId, suspendingPackage)::equals; |
| mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, |
| allPackages, suspenderPredicate, suspendingUserId); |
| } |
| |
| void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) { |
| final String[] allPackages = snapshot.getAllAvailablePackageNames(); |
| mDistractingPackageHelper.removeDistractingPackageRestrictions(snapshot, allPackages, |
| userId); |
| } |
| |
| private void enforceCanSetDistractingPackageRestrictionsAsUser(int callingUid, int userId, |
| String callingMethod) { |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, |
| callingMethod); |
| |
| if (!PackageManagerServiceUtils.isSystemOrRoot(callingUid) |
| && UserHandle.getUserId(callingUid) != userId) { |
| throw new SecurityException("Calling uid " + callingUid + " cannot call for user " |
| + userId); |
| } |
| } |
| |
| void setEnableRollbackCode(int token, int enableRollbackCode) { |
| final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS); |
| msg.arg1 = token; |
| msg.arg2 = enableRollbackCode; |
| mHandler.sendMessage(msg); |
| } |
| |
| /** |
| * Callback from PackageSettings whenever an app is first transitioned out of the |
| * 'stopped' state. Normally we just issue the broadcast, but we can't do that if |
| * the app was "launched" for a restoreAtInstall operation. Therefore we check |
| * here whether the app is the target of an ongoing install, and only send the |
| * broadcast immediately if it is not in that state. If it *is* undergoing a restore, |
| * the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL |
| * handling. |
| */ |
| void notifyFirstLaunch(final String packageName, final String installerPackage, |
| final int userId) { |
| // Serialize this with the rest of the install-process message chain. In the |
| // restore-at-install case, this Runnable will necessarily run before the |
| // POST_INSTALL message is processed, so the contents of mRunningInstalls |
| // are coherent. In the non-restore case, the app has already completed install |
| // and been launched through some other means, so it is not in a problematic |
| // state for observers to see the FIRST_LAUNCH signal. |
| mHandler.post(() -> { |
| for (int i = 0; i < mRunningInstalls.size(); i++) { |
| final InstallRequest installRequest = mRunningInstalls.valueAt(i); |
| if (installRequest.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) { |
| continue; |
| } |
| if (packageName.equals(installRequest.getPkg().getPackageName())) { |
| // right package; but is it for the right user? |
| for (int uIndex = 0; uIndex < installRequest.getNewUsers().length; uIndex++) { |
| if (userId == installRequest.getNewUsers()[uIndex]) { |
| if (DEBUG_BACKUP) { |
| Slog.i(TAG, "Package " + packageName |
| + " being restored so deferring FIRST_LAUNCH"); |
| } |
| return; |
| } |
| } |
| } |
| } |
| // didn't find it, so not being restored |
| if (DEBUG_BACKUP) { |
| Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH"); |
| } |
| final boolean isInstantApp = snapshotComputer().isInstantAppInternal( |
| packageName, userId, Process.SYSTEM_UID); |
| final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId }; |
| final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; |
| mBroadcastHelper.sendFirstLaunchBroadcast( |
| packageName, installerPackage, userIds, instantUserIds); |
| }); |
| } |
| |
| @SuppressWarnings("GuardedBy") |
| VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { |
| if (pkg.isExternalStorage()) { |
| if (TextUtils.isEmpty(pkg.getVolumeUuid())) { |
| return mSettings.getExternalVersion(); |
| } else { |
| return mSettings.findOrCreateVersion(pkg.getVolumeUuid()); |
| } |
| } else { |
| return mSettings.getInternalVersion(); |
| } |
| } |
| |
| public void deleteExistingPackageAsUser(VersionedPackage versionedPackage, |
| final IPackageDeleteObserver2 observer, final int userId) { |
| mDeletePackageHelper.deleteExistingPackageAsUser( |
| versionedPackage, observer, userId); |
| } |
| |
| public void deletePackageVersioned(VersionedPackage versionedPackage, |
| final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) { |
| mDeletePackageHelper.deletePackageVersionedInternal( |
| versionedPackage, observer, userId, deleteFlags, false); |
| } |
| |
| boolean isCallerVerifier(@NonNull Computer snapshot, int callingUid) { |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| for (String requiredVerifierPackage : mRequiredVerifierPackages) { |
| if (callingUid == snapshot.getPackageUid(requiredVerifierPackage, 0, callingUserId)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean isPackageDeviceAdminOnAnyUser(@NonNull Computer snapshot, String packageName) { |
| final int callingUid = Binder.getCallingUid(); |
| if (snapshot.checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid) |
| != PERMISSION_GRANTED) { |
| EventLog.writeEvent(0x534e4554, "128599183", -1, ""); |
| throw new SecurityException(android.Manifest.permission.MANAGE_USERS |
| + " permission is required to call this API"); |
| } |
| if (snapshot.getInstantAppPackageName(callingUid) != null |
| && !snapshot.isCallerSameApp(packageName, callingUid)) { |
| return false; |
| } |
| return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL); |
| } |
| |
| // TODO(b/261957226): centralise this logic in DPM |
| boolean isPackageDeviceAdmin(String packageName, int userId) { |
| final IDevicePolicyManager dpm = getDevicePolicyManager(); |
| try { |
| if (dpm != null) { |
| final ComponentName deviceOwnerComponentName = dpm.getDeviceOwnerComponent( |
| /* callingUserOnly =*/ false); |
| final String deviceOwnerPackageName = deviceOwnerComponentName == null ? null |
| : deviceOwnerComponentName.getPackageName(); |
| // Does the package contains the device owner? |
| // TODO Do we have to do it even if userId != UserHandle.USER_ALL? Otherwise, |
| // this check is probably not needed, since DO should be registered as a device |
| // admin on some user too. (Original bug for this: b/17657954) |
| if (packageName.equals(deviceOwnerPackageName)) { |
| return true; |
| } |
| // Does it contain a device admin for any user? |
| int[] users; |
| if (userId == UserHandle.USER_ALL) { |
| users = mUserManager.getUserIds(); |
| } else { |
| users = new int[]{userId}; |
| } |
| for (int i = 0; i < users.length; ++i) { |
| if (dpm.packageHasActiveAdmins(packageName, users[i])) { |
| return true; |
| } |
| if (isDeviceManagementRoleHolder(packageName, users[i])) { |
| return true; |
| } |
| } |
| } |
| } catch (RemoteException e) { |
| } |
| return false; |
| } |
| |
| private boolean isDeviceManagementRoleHolder(String packageName, int userId) { |
| return Objects.equals(packageName, getDevicePolicyManagementRoleHolderPackageName(userId)); |
| } |
| |
| @Nullable |
| public String getDevicePolicyManagementRoleHolderPackageName(int userId) { |
| return Binder.withCleanCallingIdentity(() -> { |
| RoleManager roleManager = mContext.getSystemService(RoleManager.class); |
| List<String> roleHolders = |
| roleManager.getRoleHoldersAsUser( |
| RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, UserHandle.of(userId)); |
| if (roleHolders.isEmpty()) { |
| return null; |
| } |
| return roleHolders.get(0); |
| }); |
| } |
| |
| /** Returns the device policy manager interface. */ |
| private IDevicePolicyManager getDevicePolicyManager() { |
| if (mDevicePolicyManager == null) { |
| // No need to synchronize; worst-case scenario it will be fetched twice. |
| mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface( |
| ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); |
| } |
| return mDevicePolicyManager; |
| } |
| |
| private boolean clearApplicationUserDataLIF(@NonNull Computer snapshot, String packageName, |
| int userId) { |
| if (packageName == null) { |
| Slog.w(TAG, "Attempt to delete null packageName."); |
| return false; |
| } |
| |
| // Try finding details about the requested package |
| AndroidPackage pkg = snapshot.getPackage(packageName); |
| if (pkg == null) { |
| Slog.w(TAG, "Package named '" + packageName + "' doesn't exist."); |
| return false; |
| } |
| mPermissionManager.resetRuntimePermissions(pkg, userId); |
| |
| mAppDataHelper.clearAppDataLIF(pkg, userId, |
| FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); |
| |
| final int appId = UserHandle.getAppId(pkg.getUid()); |
| mAppDataHelper.clearKeystoreData(userId, appId); |
| |
| UserManagerInternal umInternal = mInjector.getUserManagerInternal(); |
| StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); |
| final int flags; |
| if (StorageManager.isCeStorageUnlocked(userId) && smInternal.isCeStoragePrepared(userId)) { |
| flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; |
| } else if (umInternal.isUserRunning(userId)) { |
| flags = StorageManager.FLAG_STORAGE_DE; |
| } else { |
| flags = 0; |
| } |
| mAppDataHelper.prepareAppDataContentsLIF(pkg, snapshot.getPackageStateInternal(packageName), |
| userId, flags); |
| |
| return true; |
| } |
| |
| /** |
| * Update component enabled settings to {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT} |
| * if the resetEnabledSettingsOnAppDataCleared is {@code true}. |
| */ |
| @GuardedBy("mLock") |
| private void resetComponentEnabledSettingsIfNeededLPw(String packageName, int userId) { |
| final AndroidPackage pkg = packageName != null ? mPackages.get(packageName) : null; |
| if (pkg == null || !pkg.isResetEnabledSettingsOnAppDataCleared()) { |
| return; |
| } |
| final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); |
| if (pkgSetting == null) { |
| return; |
| } |
| final ArrayList<String> updatedComponents = new ArrayList<>(); |
| final Consumer<? super ParsedMainComponent> resetSettings = (component) -> { |
| if (pkgSetting.restoreComponentLPw(component.getClassName(), userId)) { |
| updatedComponents.add(component.getClassName()); |
| } |
| }; |
| for (int i = 0; i < pkg.getActivities().size(); i++) { |
| resetSettings.accept(pkg.getActivities().get(i)); |
| } |
| for (int i = 0; i < pkg.getReceivers().size(); i++) { |
| resetSettings.accept(pkg.getReceivers().get(i)); |
| } |
| for (int i = 0; i < pkg.getServices().size(); i++) { |
| resetSettings.accept(pkg.getServices().get(i)); |
| } |
| for (int i = 0; i < pkg.getProviders().size(); i++) { |
| resetSettings.accept(pkg.getProviders().get(i)); |
| } |
| if (ArrayUtils.isEmpty(updatedComponents)) { |
| // nothing changed |
| return; |
| } |
| |
| updateSequenceNumberLP(pkgSetting, new int[] { userId }); |
| updateInstantAppInstallerLocked(packageName); |
| scheduleWritePackageRestrictions(userId); |
| |
| mPendingBroadcasts.addComponents(userId, packageName, updatedComponents); |
| if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { |
| mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); |
| } |
| } |
| |
| /** This method takes a specific user id as well as UserHandle.USER_ALL. */ |
| @GuardedBy("mLock") |
| void clearPackagePreferredActivitiesLPw(String packageName, |
| @NonNull SparseBooleanArray outUserChanged, int userId) { |
| mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId); |
| } |
| |
| void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName, |
| @UserIdInt int userId) { |
| // We may also need to apply pending (restored) runtime permission grants |
| // within these users. |
| mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId); |
| |
| // Restore default browser setting if it is now installed. |
| String defaultBrowser; |
| synchronized (mLock) { |
| defaultBrowser = mSettings.getPendingDefaultBrowserLPr(userId); |
| } |
| if (Objects.equals(packageName, defaultBrowser)) { |
| mDefaultAppProvider.setDefaultBrowser(packageName, userId); |
| synchronized (mLock) { |
| mSettings.removePendingDefaultBrowserLPw(userId); |
| } |
| } |
| |
| // Persistent preferred activity might have came into effect due to this |
| // install. |
| mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId); |
| } |
| |
| /** |
| * Variant that takes a {@link WatchedIntentFilter} |
| */ |
| public void addCrossProfileIntentFilter(@NonNull Computer snapshot, |
| WatchedIntentFilter intentFilter, String ownerPackage, int sourceUserId, |
| int targetUserId, int flags) { |
| mContext.enforceCallingOrSelfPermission( |
| android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); |
| int callingUid = Binder.getCallingUid(); |
| enforceOwnerRights(snapshot, ownerPackage, callingUid); |
| |
| // Verifying that current calling uid should be able to add {@link CrossProfileIntentFilter} |
| // for source and target user |
| mUserManager.enforceCrossProfileIntentFilterAccess(sourceUserId, targetUserId, callingUid, |
| /* addCrossProfileIntentFilter */ true); |
| |
| PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), |
| UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); |
| if (!intentFilter.checkDataPathAndSchemeSpecificParts()) { |
| EventLog.writeEvent(0x534e4554, "246749936", callingUid); |
| throw new IllegalArgumentException("Invalid intent data paths or scheme specific parts" |
| + " in the filter."); |
| } |
| if (intentFilter.countActions() == 0) { |
| Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions"); |
| return; |
| } |
| synchronized (mLock) { |
| CrossProfileIntentFilter newFilter = new CrossProfileIntentFilter(intentFilter, |
| ownerPackage, targetUserId, flags, mUserManager |
| .getCrossProfileIntentFilterAccessControl(sourceUserId, targetUserId)); |
| CrossProfileIntentResolver resolver = |
| mSettings.editCrossProfileIntentResolverLPw(sourceUserId); |
| ArrayList<CrossProfileIntentFilter> existing = resolver.findFilters(intentFilter); |
| // We have all those whose filter is equal. Now checking if the rest is equal as well. |
| if (existing != null) { |
| int size = existing.size(); |
| for (int i = 0; i < size; i++) { |
| if (newFilter.equalsIgnoreFilter(existing.get(i))) { |
| return; |
| } |
| } |
| } |
| resolver.addFilter(snapshotComputer(), newFilter); |
| } |
| scheduleWritePackageRestrictions(sourceUserId); |
| } |
| |
| |
| // Enforcing that callingUid is owning pkg on userId |
| private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) { |
| // The system owns everything. |
| if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { |
| return; |
| } |
| final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid); |
| if (!ArrayUtils.contains(callerPackageNames, pkg)) { |
| throw new SecurityException("Calling uid " + callingUid |
| + " does not own package " + pkg); |
| } |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| PackageInfo pi = snapshot.getPackageInfo(pkg, 0, callingUserId); |
| if (pi == null) { |
| throw new IllegalArgumentException("Unknown package " + pkg + " on user " |
| + callingUserId); |
| } |
| } |
| |
| public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) { |
| mBroadcastHelper.sendSessionCommitBroadcast(snapshotComputer(), sessionInfo, userId, |
| mAppPredictionServicePackage); |
| } |
| |
| private @Nullable String getSetupWizardPackageNameImpl(@NonNull Computer computer) { |
| final Intent intent = new Intent(Intent.ACTION_MAIN); |
| intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); |
| |
| final List<ResolveInfo> matches = computer.queryIntentActivitiesInternal(intent, null, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE |
| | MATCH_DISABLED_COMPONENTS, |
| UserHandle.myUserId()); |
| if (matches.size() == 1) { |
| return matches.get(0).getComponentInfo().packageName; |
| } else { |
| Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size() |
| + ": matches=" + matches); |
| return null; |
| } |
| } |
| |
| private @Nullable String getStorageManagerPackageName(@NonNull Computer computer) { |
| final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); |
| |
| final List<ResolveInfo> matches = computer.queryIntentActivitiesInternal(intent, null, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE |
| | MATCH_DISABLED_COMPONENTS, |
| UserHandle.myUserId()); |
| if (matches.size() == 1) { |
| return matches.get(0).getComponentInfo().packageName; |
| } else { |
| Slog.w(TAG, "There should probably be exactly one storage manager; found " |
| + matches.size() + ": matches=" + matches); |
| return null; |
| } |
| } |
| |
| @NonNull |
| private static String getRequiredSdkSandboxPackageName(@NonNull Computer computer) { |
| final Intent intent = new Intent(SdkSandboxManagerLocal.SERVICE_INTERFACE); |
| |
| final List<ResolveInfo> matches = computer.queryIntentServicesInternal( |
| intent, |
| /* resolvedType= */ null, |
| MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, |
| UserHandle.USER_SYSTEM, |
| /* callingUid= */ Process.myUid(), |
| /* includeInstantApps= */ false); |
| if (matches.size() == 1) { |
| return matches.get(0).getComponentInfo().packageName; |
| } else { |
| throw new RuntimeException("There should exactly one sdk sandbox package; found " |
| + matches.size() + ": matches=" + matches); |
| } |
| } |
| |
| @Nullable |
| private String getRetailDemoPackageName() { |
| final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage); |
| final String predefinedSignature = mContext.getString( |
| R.string.config_retailDemoPackageSignature); |
| |
| if (TextUtils.isEmpty(predefinedPkgName) || TextUtils.isEmpty(predefinedSignature)) { |
| return null; |
| } |
| |
| final AndroidPackage androidPkg = mPackages.get(predefinedPkgName); |
| if (androidPkg != null) { |
| final SigningDetails signingDetail = androidPkg.getSigningDetails(); |
| if (signingDetail != null && signingDetail.getSignatures() != null) { |
| try { |
| final MessageDigest msgDigest = MessageDigest.getInstance("SHA-256"); |
| for (Signature signature : signingDetail.getSignatures()) { |
| if (TextUtils.equals(predefinedSignature, |
| HexEncoding.encodeToString(msgDigest.digest( |
| signature.toByteArray()), false))) { |
| return predefinedPkgName; |
| } |
| } |
| } catch (NoSuchAlgorithmException e) { |
| Slog.e( |
| TAG, |
| "Unable to verify signatures as getting the retail demo package name", |
| e); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| @Nullable |
| String getPackageFromComponentString(@StringRes int stringResId) { |
| final String componentString = mContext.getString(stringResId); |
| if (TextUtils.isEmpty(componentString)) { |
| return null; |
| } |
| final ComponentName component = ComponentName.unflattenFromString(componentString); |
| if (component == null) { |
| return null; |
| } |
| return component.getPackageName(); |
| } |
| |
| @Nullable |
| String ensureSystemPackageName(@NonNull Computer snapshot, |
| @Nullable String packageName) { |
| if (packageName == null) { |
| return null; |
| } |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| if (snapshot.getPackageInfo(packageName, MATCH_FACTORY_ONLY, |
| UserHandle.USER_SYSTEM) == null) { |
| PackageInfo packageInfo = |
| snapshot.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM); |
| if (packageInfo != null) { |
| EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid, |
| ""); |
| } |
| Log.w(TAG, "Missing required system package: " + packageName + (packageInfo != null |
| ? ", but found with extended search." : ".")); |
| return null; |
| } |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| return packageName; |
| } |
| |
| @VisibleForTesting(visibility = Visibility.PRIVATE) |
| public void updateComponentLabelIcon(/*@NonNull*/ ComponentName componentName, |
| @Nullable String nonLocalizedLabel, @Nullable Integer icon, int userId) { |
| if (componentName == null) { |
| throw new IllegalArgumentException("Must specify a component"); |
| } |
| |
| int callingUid = Binder.getCallingUid(); |
| String componentPkgName = componentName.getPackageName(); |
| |
| Computer computer = snapshotComputer(); |
| |
| int componentUid = computer.getPackageUid(componentPkgName, 0, userId); |
| if (!UserHandle.isSameApp(callingUid, componentUid)) { |
| throw new SecurityException("The calling UID (" + callingUid + ")" |
| + " does not match the target UID"); |
| } |
| |
| String allowedCallerPkg = |
| mContext.getString(R.string.config_overrideComponentUiPackage); |
| if (TextUtils.isEmpty(allowedCallerPkg)) { |
| throw new SecurityException( "There is no package defined as allowed to change a " |
| + "component's label or icon"); |
| } |
| |
| int allowedCallerUid = computer.getPackageUid(allowedCallerPkg, |
| PackageManager.MATCH_SYSTEM_ONLY, userId); |
| if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) { |
| throw new SecurityException("The calling UID (" + callingUid + ")" |
| + " is not allowed to change a component's label or icon"); |
| } |
| PackageStateInternal packageState = computer.getPackageStateInternal(componentPkgName); |
| if (packageState == null || packageState.getPkg() == null |
| || (!packageState.isSystem() |
| && !packageState.isUpdatedSystemApp())) { |
| throw new SecurityException( |
| "Changing the label is not allowed for " + componentName); |
| } |
| |
| if (!computer.getComponentResolver().componentExists(componentName)) { |
| throw new IllegalArgumentException("Component " + componentName + " not found"); |
| } |
| |
| Pair<String, Integer> overrideLabelIcon = packageState.getUserStateOrDefault(userId) |
| .getOverrideLabelIconForComponent(componentName); |
| |
| String existingLabel = overrideLabelIcon == null ? null : overrideLabelIcon.first; |
| Integer existingIcon = overrideLabelIcon == null ? null : overrideLabelIcon.second; |
| |
| if (TextUtils.equals(existingLabel, nonLocalizedLabel) |
| && Objects.equals(existingIcon, icon)) { |
| // Nothing changed |
| return; |
| } |
| |
| commitPackageStateMutation(null, componentPkgName, |
| state -> state.userState(userId) |
| .setComponentLabelIcon(componentName, nonLocalizedLabel, icon)); |
| |
| mPendingBroadcasts.addComponent(userId, componentPkgName, componentName.getClassName()); |
| |
| if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { |
| mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); |
| } |
| } |
| |
| private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId, |
| @NonNull String callingPackage) { |
| final int callingUid = Binder.getCallingUid(); |
| // TODO: This method is not properly snapshotified beyond this call |
| final Computer preLockSnapshot = snapshotComputer(); |
| preLockSnapshot.enforceCrossUserPermission(callingUid, userId, |
| false /* requireFullPermission */, true /* checkShell */, "set enabled"); |
| |
| final int targetSize = settings.size(); |
| for (int i = 0; i < targetSize; i++) { |
| final int newState = settings.get(i).getEnabledState(); |
| if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT |
| || newState == COMPONENT_ENABLED_STATE_ENABLED |
| || newState == COMPONENT_ENABLED_STATE_DISABLED |
| || newState == COMPONENT_ENABLED_STATE_DISABLED_USER |
| || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { |
| throw new IllegalArgumentException("Invalid new component state: " + newState); |
| } |
| } |
| if (targetSize > 1) { |
| final ArraySet<String> checkDuplicatedPackage = new ArraySet<>(); |
| final ArraySet<ComponentName> checkDuplicatedComponent = new ArraySet<>(); |
| final ArrayMap<String, Integer> checkConflictFlag = new ArrayMap<>(); |
| for (int i = 0; i < targetSize; i++) { |
| final ComponentEnabledSetting setting = settings.get(i); |
| final String packageName = setting.getPackageName(); |
| if (setting.isComponent()) { |
| final ComponentName componentName = setting.getComponentName(); |
| if (checkDuplicatedComponent.contains(componentName)) { |
| throw new IllegalArgumentException("The component " + componentName |
| + " is duplicated"); |
| } |
| checkDuplicatedComponent.add(componentName); |
| |
| // check if there is a conflict of the DONT_KILL_APP flag between components |
| // in the package |
| final Integer enabledFlags = checkConflictFlag.get(packageName); |
| if (enabledFlags == null) { |
| checkConflictFlag.put(packageName, setting.getEnabledFlags()); |
| } else if ((enabledFlags & PackageManager.DONT_KILL_APP) |
| != (setting.getEnabledFlags() & PackageManager.DONT_KILL_APP)) { |
| throw new IllegalArgumentException("A conflict of the DONT_KILL_APP flag " |
| + "between components in the package " + packageName); |
| } |
| } else { |
| if (checkDuplicatedPackage.contains(packageName)) { |
| throw new IllegalArgumentException("The package " + packageName |
| + " is duplicated"); |
| } |
| checkDuplicatedPackage.add(packageName); |
| } |
| } |
| } |
| |
| final boolean allowedByPermission = mContext.checkCallingOrSelfPermission( |
| android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE) == PERMISSION_GRANTED; |
| final boolean[] updateAllowed = new boolean[targetSize]; |
| Arrays.fill(updateAllowed, true); |
| |
| final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize); |
| // reader |
| synchronized (mLock) { |
| final Computer snapshot = snapshotComputer(); |
| // Checks for target packages |
| for (int i = 0; i < targetSize; i++) { |
| final ComponentEnabledSetting setting = settings.get(i); |
| final String packageName = setting.getPackageName(); |
| if (pkgSettings.containsKey(packageName)) { |
| // this package has verified |
| continue; |
| } |
| final boolean isCallerTargetApp = ArrayUtils.contains( |
| snapshot.getPackagesForUid(callingUid), packageName); |
| final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); |
| // Limit who can change which apps |
| if (!isCallerTargetApp && !allowedByPermission) { |
| // Don't allow apps that don't have permission to modify other apps |
| throw new SecurityException("Attempt to change component state; " |
| + "pid=" + Binder.getCallingPid() |
| + ", uid=" + callingUid |
| + (!setting.isComponent() ? ", package=" + packageName |
| : ", component=" + setting.getComponentName())); |
| } |
| if (pkgSetting == null || snapshot.shouldFilterApplicationIncludingUninstalled( |
| pkgSetting, callingUid, userId)) { |
| throw new IllegalArgumentException(setting.isComponent() |
| ? "Unknown component: " + setting.getComponentName() |
| : "Unknown package: " + packageName); |
| } |
| // Don't allow changing protected packages. |
| if (!isCallerTargetApp |
| && mProtectedPackages.isPackageStateProtected(userId, packageName)) { |
| throw new SecurityException( |
| "Cannot disable a protected package: " + packageName); |
| } |
| if (callingUid == Process.SHELL_UID |
| && (pkgSetting.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) == 0) { |
| // Shell can only change whole packages between ENABLED and DISABLED_USER states |
| // unless it is a test package. |
| final int oldState = pkgSetting.getEnabled(userId); |
| final int newState = setting.getEnabledState(); |
| if (!setting.isComponent() |
| && |
| (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER |
| || oldState == COMPONENT_ENABLED_STATE_DEFAULT |
| || oldState == COMPONENT_ENABLED_STATE_ENABLED) |
| && |
| (newState == COMPONENT_ENABLED_STATE_DISABLED_USER |
| || newState == COMPONENT_ENABLED_STATE_DEFAULT |
| || newState == COMPONENT_ENABLED_STATE_ENABLED)) { |
| // ok |
| } else { |
| throw new SecurityException( |
| "Shell cannot change component state for " |
| + setting.getComponentName() + " to " + newState); |
| } |
| } |
| pkgSettings.put(packageName, pkgSetting); |
| } |
| // Checks for target components |
| for (int i = 0; i < targetSize; i++) { |
| final ComponentEnabledSetting setting = settings.get(i); |
| // skip if it's application |
| if (!setting.isComponent()) continue; |
| |
| // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden |
| // app details activity |
| final String packageName = setting.getPackageName(); |
| final String className = setting.getClassName(); |
| if (!allowedByPermission |
| && PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { |
| throw new SecurityException("Cannot disable a system-generated component"); |
| } |
| // Verify that this is a valid class name. |
| final AndroidPackage pkg = pkgSettings.get(packageName).getPkg(); |
| if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) { |
| if (pkg != null |
| && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) { |
| throw new IllegalArgumentException("Component class " + className |
| + " does not exist in " + packageName); |
| } else { |
| Slog.w(TAG, "Failed setComponentEnabledSetting: component class " |
| + className + " does not exist in " + packageName); |
| updateAllowed[i] = false; |
| } |
| } |
| } |
| } |
| |
| // More work for application enabled setting updates |
| for (int i = 0; i < targetSize; i++) { |
| final ComponentEnabledSetting setting = settings.get(i); |
| // skip if it's component |
| if (setting.isComponent()) continue; |
| |
| final PackageSetting pkgSetting = pkgSettings.get(setting.getPackageName()); |
| final int newState = setting.getEnabledState(); |
| synchronized (mLock) { |
| if (pkgSetting.getEnabled(userId) == newState) { |
| // Nothing to do |
| updateAllowed[i] = false; |
| continue; |
| } |
| } |
| // If we're enabling a system stub, there's a little more work to do. |
| // Prior to enabling the package, we need to decompress the APK(s) to the |
| // data partition and then replace the version on the system partition. |
| final AndroidPackage deletedPkg = pkgSetting.getPkg(); |
| final boolean isSystemStub = (deletedPkg != null) |
| && deletedPkg.isStub() |
| && pkgSetting.isSystem(); |
| if (isSystemStub |
| && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT |
| || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { |
| if (!enableCompressedPackage(deletedPkg, pkgSetting)) { |
| Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable " |
| + "commpressed package " + setting.getPackageName()); |
| updateAllowed[i] = false; |
| } |
| } |
| } |
| |
| // packageName -> list of components to send broadcasts now |
| final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize); |
| synchronized (mLock) { |
| Computer computer = snapshotComputer(); |
| boolean scheduleBroadcastMessage = false; |
| boolean isSynchronous = false; |
| boolean anyChanged = false; |
| |
| for (int i = 0; i < targetSize; i++) { |
| if (!updateAllowed[i]) { |
| continue; |
| } |
| // update enabled settings |
| final ComponentEnabledSetting setting = settings.get(i); |
| final String packageName = setting.getPackageName(); |
| if (!setEnabledSettingInternalLocked(computer, pkgSettings.get(packageName), |
| setting, userId, callingPackage)) { |
| continue; |
| } |
| anyChanged = true; |
| |
| if ((setting.getEnabledFlags() & PackageManager.SYNCHRONOUS) != 0) { |
| isSynchronous = true; |
| } |
| // collect broadcast list for the package |
| final String componentName = setting.isComponent() |
| ? setting.getClassName() : packageName; |
| if ((setting.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) { |
| ArrayList<String> componentList = sendNowBroadcasts.get(packageName); |
| componentList = componentList == null ? new ArrayList<>() : componentList; |
| if (!componentList.contains(componentName)) { |
| componentList.add(componentName); |
| } |
| sendNowBroadcasts.put(packageName, componentList); |
| // Purge entry from pending broadcast list if another one exists already |
| // since we are sending one right away. |
| mPendingBroadcasts.remove(userId, packageName); |
| } else { |
| mPendingBroadcasts.addComponent(userId, packageName, componentName); |
| scheduleBroadcastMessage = true; |
| } |
| } |
| if (!anyChanged) { |
| // nothing changed, return immediately |
| return; |
| } |
| |
| if (isSynchronous) { |
| flushPackageRestrictionsAsUserInternalLocked(userId); |
| } else { |
| scheduleWritePackageRestrictions(userId); |
| } |
| if (scheduleBroadcastMessage) { |
| if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { |
| // Schedule a message - if it has been a "reasonably long time" since the |
| // service started, send the broadcast with a delay of one second to avoid |
| // delayed reactions from the receiver, else keep the default ten second delay |
| // to avoid extreme thrashing on service startup. |
| final long broadcastDelay = SystemClock.uptimeMillis() > mServiceStartWithDelay |
| ? BROADCAST_DELAY |
| : BROADCAST_DELAY_DURING_STARTUP; |
| mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, broadcastDelay); |
| } |
| } |
| } |
| |
| final long callingId = Binder.clearCallingIdentity(); |
| try { |
| final Computer newSnapshot = snapshotComputer(); |
| for (int i = 0; i < sendNowBroadcasts.size(); i++) { |
| final String packageName = sendNowBroadcasts.keyAt(i); |
| final ArrayList<String> components = sendNowBroadcasts.valueAt(i); |
| final int packageUid = UserHandle.getUid( |
| userId, pkgSettings.get(packageName).getAppId()); |
| mBroadcastHelper.sendPackageChangedBroadcast(newSnapshot, packageName, |
| false /* dontKillApp */, components, packageUid, null /* reason */); |
| } |
| } finally { |
| Binder.restoreCallingIdentity(callingId); |
| } |
| } |
| |
| @GuardedBy("mLock") |
| private boolean setEnabledSettingInternalLocked(@NonNull Computer computer, |
| PackageSetting pkgSetting, ComponentEnabledSetting setting, @UserIdInt int userId, |
| String callingPackage) { |
| final int newState = setting.getEnabledState(); |
| final String packageName = setting.getPackageName(); |
| boolean success = false; |
| if (!setting.isComponent()) { |
| // We're dealing with an application/package level state change |
| pkgSetting.setEnabled(newState, userId, callingPackage); |
| if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER |
| || newState == COMPONENT_ENABLED_STATE_DISABLED) |
| && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId) |
| == PERMISSION_GRANTED) { |
| // This app should not generally be allowed to get disabled by the UI, but |
| // if it ever does, we don't want to end up with some of the user's apps |
| // permanently suspended. |
| unsuspendForSuspendingPackage(computer, packageName, userId); |
| removeAllDistractingPackageRestrictions(computer, userId); |
| } |
| success = true; |
| } else { |
| // We're dealing with a component level state change |
| final String className = setting.getClassName(); |
| switch (newState) { |
| case COMPONENT_ENABLED_STATE_ENABLED: |
| success = pkgSetting.enableComponentLPw(className, userId); |
| break; |
| case COMPONENT_ENABLED_STATE_DISABLED: |
| success = pkgSetting.disableComponentLPw(className, userId); |
| break; |
| case COMPONENT_ENABLED_STATE_DEFAULT: |
| success = pkgSetting.restoreComponentLPw(className, userId); |
| break; |
| default: |
| Slog.e(TAG, "Failed setComponentEnabledSetting: component " |
| + packageName + "/" + className |
| + " requested an invalid new component state: " + newState); |
| break; |
| } |
| } |
| if (!success) { |
| return false; |
| } |
| |
| updateSequenceNumberLP(pkgSetting, new int[] { userId }); |
| final long callingId = Binder.clearCallingIdentity(); |
| try { |
| updateInstantAppInstallerLocked(packageName); |
| } finally { |
| Binder.restoreCallingIdentity(callingId); |
| } |
| |
| return true; |
| } |
| |
| @GuardedBy("mLock") |
| private void flushPackageRestrictionsAsUserInternalLocked(int userId) { |
| // NOTE: this invokes synchronous disk access, so callers using this |
| // method should consider running on a background thread |
| mSettings.writePackageRestrictionsLPr(userId); |
| synchronized (mDirtyUsers) { |
| mDirtyUsers.remove(userId); |
| if (mDirtyUsers.isEmpty()) { |
| mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS); |
| } |
| } |
| } |
| |
| /** |
| * Used by SystemServer |
| */ |
| public void waitForAppDataPrepared() { |
| if (mPrepareAppDataFuture == null) { |
| return; |
| } |
| ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData"); |
| mPrepareAppDataFuture = null; |
| } |
| |
| public void systemReady() { |
| PackageManagerServiceUtils.enforceSystemOrRoot( |
| "Only the system can claim the system is ready"); |
| |
| final ContentResolver resolver = mContext.getContentResolver(); |
| if (mReleaseOnSystemReady != null) { |
| for (int i = mReleaseOnSystemReady.size() - 1; i >= 0; --i) { |
| final File dstCodePath = mReleaseOnSystemReady.get(i); |
| F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath); |
| } |
| mReleaseOnSystemReady = null; |
| } |
| mSystemReady = true; |
| ContentObserver co = new ContentObserver(mHandler) { |
| @Override |
| public void onChange(boolean selfChange) { |
| final boolean ephemeralFeatureDisabled = |
| Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0; |
| for (int userId : UserManagerService.getInstance().getUserIds()) { |
| final boolean instantAppsDisabledForUser = |
| ephemeralFeatureDisabled || Secure.getIntForUser(resolver, |
| Secure.INSTANT_APPS_ENABLED, 1, userId) == 0; |
| mWebInstantAppsDisabled.put(userId, instantAppsDisabledForUser); |
| } |
| } |
| }; |
| mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global |
| .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE), |
| false, co, UserHandle.USER_ALL); |
| mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure |
| .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL); |
| co.onChange(true); |
| |
| mAppsFilter.onSystemReady(LocalServices.getService(PackageManagerInternal.class)); |
| |
| // Disable any carrier apps. We do this very early in boot to prevent the apps from being |
| // disabled after already being started. |
| CarrierAppUtils.disableCarrierAppsUntilPrivileged( |
| mContext.getOpPackageName(), UserHandle.USER_SYSTEM, mContext); |
| |
| disableSkuSpecificApps(); |
| |
| // Read the compatibilty setting when the system is ready. |
| boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt( |
| mContext.getContentResolver(), |
| android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1; |
| ParsingPackageUtils.setCompatibilityModeEnabled(compatibilityModeEnabled); |
| |
| if (DEBUG_SETTINGS) { |
| Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled); |
| } |
| |
| synchronized (mLock) { |
| ArrayList<Integer> changed = mSettings.systemReady(mComponentResolver); |
| for (int i = 0; i < changed.size(); i++) { |
| mSettings.writePackageRestrictionsLPr(changed.get(i)); |
| } |
| } |
| |
| mUserManager.systemReady(); |
| |
| // Watch for external volumes that come and go over time |
| final StorageManager storage = mInjector.getSystemService(StorageManager.class); |
| storage.registerListener(mStorageEventHelper); |
| |
| mInstallerService.systemReady(); |
| mPackageDexOptimizer.systemReady(); |
| |
| // Now that we're mostly running, clean up stale users and apps |
| mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); |
| mStorageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL); |
| |
| mPermissionManager.onSystemReady(); |
| |
| int[] grantPermissionsUserIds = EMPTY_INT_ARRAY; |
| final List<UserInfo> livingUsers = mInjector.getUserManagerInternal().getUsers( |
| /* excludePartial= */ true, |
| /* excludeDying= */ true, |
| /* excludePreCreated= */ false); |
| final int livingUserCount = livingUsers.size(); |
| for (int i = 0; i < livingUserCount; i++) { |
| final int userId = livingUsers.get(i).id; |
| final boolean isPermissionUpgradeNeeded = !Objects.equals( |
| mPermissionManager.getDefaultPermissionGrantFingerprint(userId), |
| Build.FINGERPRINT); |
| if (isPermissionUpgradeNeeded) { |
| grantPermissionsUserIds = ArrayUtils.appendInt( |
| grantPermissionsUserIds, userId); |
| } |
| } |
| // If we upgraded grant all default permissions before kicking off. |
| for (int userId : grantPermissionsUserIds) { |
| mLegacyPermissionManager.grantDefaultPermissions(userId); |
| mPermissionManager.setDefaultPermissionGrantFingerprint(Build.FINGERPRINT, userId); |
| } |
| if (grantPermissionsUserIds == EMPTY_INT_ARRAY) { |
| // If we did not grant default permissions, we preload from this the |
| // default permission exceptions lazily to ensure we don't hit the |
| // disk on a new user creation. |
| mLegacyPermissionManager.scheduleReadDefaultPermissionExceptions(); |
| } |
| |
| if (mInstantAppResolverConnection != null) { |
| mContext.registerReceiver(new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| mInstantAppResolverConnection.optimisticBind(); |
| mContext.unregisterReceiver(this); |
| } |
| }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); |
| } |
| |
| IntentFilter overlayFilter = new IntentFilter(Intent.ACTION_OVERLAY_CHANGED); |
| overlayFilter.addDataScheme("package"); |
| mContext.registerReceiver(new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (intent == null) { |
| return; |
| } |
| Uri data = intent.getData(); |
| if (data == null) { |
| return; |
| } |
| String packageName = data.getSchemeSpecificPart(); |
| if (packageName == null) { |
| return; |
| } |
| final Computer snapshot = snapshotComputer(); |
| AndroidPackage pkg = snapshot.getPackage(packageName); |
| if (pkg == null) { |
| return; |
| } |
| mBroadcastHelper.sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), |
| true /* dontKillApp */, |
| new ArrayList<>(Collections.singletonList(pkg.getPackageName())), |
| pkg.getUid(), |
| Intent.ACTION_OVERLAY_CHANGED); |
| } |
| }, overlayFilter); |
| |
| mModuleInfoProvider.systemReady(); |
| |
| // Installer service might attempt to install some packages that have been staged for |
| // installation on reboot. Make sure this is the last component to be call since the |
| // installation might require other components to be ready. |
| mInstallerService.restoreAndApplyStagedSessionIfNeeded(); |
| |
| mExistingPackages = null; |
| |
| // Clear cache on flags changes. |
| DeviceConfig.addOnPropertiesChangedListener( |
| NAMESPACE_PACKAGE_MANAGER_SERVICE, mInjector.getBackgroundExecutor(), |
| properties -> { |
| final Set<String> keyset = properties.getKeyset(); |
| if (keyset.contains(PROPERTY_INCFS_DEFAULT_TIMEOUTS) || keyset.contains( |
| PROPERTY_KNOWN_DIGESTERS_LIST)) { |
| mPerUidReadTimeoutsCache = null; |
| } |
| }); |
| |
| if (!useArtService()) { |
| // The background dexopt job is scheduled in DexOptHelper.initializeArtManagerLocal when |
| // ART Service is in use. |
| try { |
| mBackgroundDexOptService.systemReady(); |
| } catch (LegacyDexoptDisabledException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| // Prune unused static shared libraries which have been cached a period of time |
| schedulePruneUnusedStaticSharedLibraries(false /* delay */); |
| |
| DexUseManagerLocal dexUseManager = DexOptHelper.getDexUseManagerLocal(); |
| if (dexUseManager != null) { |
| dexUseManager.systemReady(); |
| } |
| } |
| |
| //TODO: b/111402650 |
| private void disableSkuSpecificApps() { |
| String[] apkList = mContext.getResources().getStringArray( |
| R.array.config_disableApksUnlessMatchedSku_apk_list); |
| String[] skuArray = mContext.getResources().getStringArray( |
| R.array.config_disableApkUnlessMatchedSku_skus_list); |
| if (ArrayUtils.isEmpty(apkList)) { |
| return; |
| } |
| String sku = SystemProperties.get("ro.boot.hardware.sku"); |
| if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) { |
| return; |
| } |
| final Computer snapshot = snapshotComputer(); |
| for (String packageName : apkList) { |
| setSystemAppHiddenUntilInstalled(snapshot, packageName, true); |
| final List<UserInfo> users = mInjector.getUserManagerInternal().getUsers(false); |
| for (int i = 0; i < users.size(); i++) { |
| setSystemAppInstallState(snapshot, packageName, false, users.get(i).id); |
| } |
| } |
| } |
| |
| public PackageFreezer freezePackage(String packageName, int userId, String killReason, |
| int exitInfoReason, InstallRequest request) { |
| return new PackageFreezer(packageName, userId, killReason, this, exitInfoReason, request); |
| } |
| |
| public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags, |
| String killReason, int exitInfoReason) { |
| if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) { |
| return new PackageFreezer(this, null /* request */); |
| } else { |
| return freezePackage(packageName, userId, killReason, exitInfoReason, |
| null /* request */); |
| } |
| } |
| |
| /** Called by UserManagerService */ |
| void cleanUpUser(UserManagerService userManager, @UserIdInt int userId) { |
| synchronized (mLock) { |
| synchronized (mDirtyUsers) { |
| mDirtyUsers.remove(userId); |
| } |
| mUserNeedsBadging.delete(userId); |
| mPermissionManager.onUserRemoved(userId); |
| mSettings.removeUserLPw(userId); |
| mPendingBroadcasts.remove(userId); |
| mDeletePackageHelper.removeUnusedPackagesLPw(userManager, userId); |
| mAppsFilter.onUserDeleted(snapshotComputer(), userId); |
| } |
| mInstantAppRegistry.onUserRemoved(userId); |
| mPackageMonitorCallbackHelper.onUserRemoved(userId); |
| } |
| |
| /** |
| * Called by UserManagerService. |
| * |
| * @param userTypeInstallablePackages system packages that should be initially installed for |
| * this type of user, or {@code null} if all system packages |
| * should be installed |
| * @param disallowedPackages packages that should not be initially installed. Takes precedence |
| * over installablePackages. |
| */ |
| void createNewUser(int userId, @Nullable Set<String> userTypeInstallablePackages, |
| String[] disallowedPackages) { |
| synchronized (mInstallLock) { |
| mSettings.createNewUserLI(this, mInstaller, userId, |
| userTypeInstallablePackages, disallowedPackages); |
| } |
| synchronized (mLock) { |
| scheduleWritePackageRestrictions(userId); |
| scheduleWritePackageListLocked(userId); |
| mAppsFilter.onUserCreated(snapshotComputer(), userId); |
| } |
| } |
| |
| void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) { |
| if (DEBUG_PERMISSIONS) { |
| Slog.d(TAG, "onNewUserCreated(id=" + userId |
| + ", convertedFromPreCreated=" + convertedFromPreCreated + ")"); |
| } |
| if (!convertedFromPreCreated || !readPermissionStateForUser(userId)) { |
| mPermissionManager.onUserCreated(userId); |
| mLegacyPermissionManager.grantDefaultPermissions(userId); |
| mPermissionManager.setDefaultPermissionGrantFingerprint(Build.FINGERPRINT, userId); |
| mDomainVerificationManager.clearUser(userId); |
| } |
| } |
| |
| private boolean readPermissionStateForUser(@UserIdInt int userId) { |
| synchronized (mLock) { |
| mPermissionManager.writeLegacyPermissionStateTEMP(); |
| mSettings.readPermissionStateForUserSyncLPr(userId); |
| mPermissionManager.readLegacyPermissionStateTEMP(); |
| final boolean isPermissionUpgradeNeeded = !Objects.equals( |
| mPermissionManager.getDefaultPermissionGrantFingerprint(userId), |
| Build.FINGERPRINT); |
| return isPermissionUpgradeNeeded; |
| } |
| } |
| |
| public boolean isStorageLow() { |
| // allow instant applications |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| final DeviceStorageMonitorInternal |
| dsm = mInjector.getLocalService(DeviceStorageMonitorInternal.class); |
| if (dsm != null) { |
| return dsm.isMemoryLow(); |
| } else { |
| return false; |
| } |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| private void deletePackageIfUnused(@NonNull Computer snapshot, final String packageName) { |
| PackageStateInternal ps = snapshot.getPackageStateInternal(packageName); |
| if (ps == null) { |
| return; |
| } |
| final SparseArray<? extends PackageUserStateInternal> userStates = ps.getUserStates(); |
| for (int index = 0; index < userStates.size(); index++) { |
| if (userStates.valueAt(index).isInstalled()) { |
| return; |
| } |
| } |
| // TODO Implement atomic delete if package is unused |
| // It is currently possible that the package will be deleted even if it is installed |
| // after this method returns. |
| mHandler.post(() -> mDeletePackageHelper.deletePackageX( |
| packageName, PackageManager.VERSION_CODE_HIGHEST, |
| 0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/)); |
| } |
| |
| void deletePreloadsFileCache() { |
| mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE, |
| "deletePreloadsFileCache"); |
| File dir = Environment.getDataPreloadsFileCacheDirectory(); |
| Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir); |
| FileUtils.deleteContents(dir); |
| } |
| |
| void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName, |
| boolean hidden) { |
| final int callingUid = Binder.getCallingUid(); |
| final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID |
| || callingUid == Process.SYSTEM_UID; |
| if (!calledFromSystemOrPhone) { |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, |
| "setSystemAppHiddenUntilInstalled"); |
| } |
| |
| final PackageStateInternal stateRead = snapshot.getPackageStateInternal(packageName); |
| if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) { |
| return; |
| } |
| if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) { |
| throw new SecurityException("Only system or phone callers can modify core apps"); |
| } |
| |
| commitPackageStateMutation(null, mutator -> { |
| mutator.forPackage(packageName) |
| .setHiddenUntilInstalled(hidden); |
| mutator.forDisabledSystemPackage(packageName) |
| .setHiddenUntilInstalled(hidden); |
| }); |
| } |
| |
| boolean setSystemAppInstallState(@NonNull Computer snapshot, String packageName, |
| boolean installed, int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID |
| || callingUid == Process.SYSTEM_UID; |
| if (!calledFromSystemOrPhone) { |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, |
| "setSystemAppHiddenUntilInstalled"); |
| } |
| |
| final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| // The target app should always be in system |
| if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) { |
| return false; |
| } |
| if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) { |
| throw new SecurityException("Only system or phone callers can modify core apps"); |
| } |
| // Check if the install state is the same |
| if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) { |
| return false; |
| } |
| |
| final long callingId = Binder.clearCallingIdentity(); |
| try { |
| if (installed) { |
| // install the app from uninstalled state |
| mInstallPackageHelper.installExistingPackageAsUser( |
| packageName, |
| userId, |
| PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, |
| PackageManager.INSTALL_REASON_DEVICE_SETUP, |
| null, |
| null); |
| return true; |
| } |
| |
| // uninstall the app from installed state |
| deletePackageVersioned( |
| new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), |
| new PackageManager.LegacyPackageDeleteObserver(null).getBinder(), |
| userId, |
| PackageManager.DELETE_SYSTEM_APP); |
| return true; |
| } finally { |
| Binder.restoreCallingIdentity(callingId); |
| } |
| } |
| |
| void finishPackageInstall(int token, boolean didLaunch) { |
| PackageManagerServiceUtils.enforceSystemOrRoot( |
| "Only the system is allowed to finish installs"); |
| |
| if (PackageManagerService.DEBUG_INSTALL) { |
| Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token); |
| } |
| Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token); |
| |
| final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token, |
| didLaunch ? 1 : 0); |
| mHandler.sendMessage(msg); |
| } |
| |
| void checkPackageStartable(@NonNull Computer snapshot, @NonNull String packageName, |
| @UserIdInt int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| if (snapshot.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"); |
| } |
| snapshot.enforceCrossUserPermission(callingUid, userId, false, false, |
| "checkPackageStartable"); |
| switch (snapshot.getPackageStartability(mSafeMode, 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: |
| } |
| } |
| |
| void setPackageStoppedState(@NonNull Computer snapshot, @NonNull String packageName, |
| boolean stopped, @UserIdInt int userId) { |
| if (!mUserManager.exists(userId)) return; |
| final int callingUid = Binder.getCallingUid(); |
| boolean wasStopped = false; |
| if (snapshot.getInstantAppPackageName(callingUid) == null) { |
| final int permission = mContext.checkCallingOrSelfPermission( |
| Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); |
| final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); |
| if (!allowedByPermission |
| && !ArrayUtils.contains(snapshot.getPackagesForUid(callingUid), packageName)) { |
| throw new SecurityException( |
| "Permission Denial: attempt to change stopped state from pid=" |
| + Binder.getCallingPid() |
| + ", uid=" + callingUid + ", package=" + packageName); |
| } |
| snapshot.enforceCrossUserPermission(callingUid, userId, |
| true /* requireFullPermission */, true /* checkShell */, "stop package"); |
| |
| final PackageStateInternal packageState = |
| snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, userId); |
| final PackageUserState packageUserState = packageState == null |
| ? null : packageState.getUserStateOrDefault(userId); |
| if (packageState != null && packageUserState.isStopped() != stopped) { |
| boolean wasNotLaunched = packageUserState.isNotLaunched(); |
| wasStopped = packageUserState.isStopped(); |
| commitPackageStateMutation(null, packageName, state -> { |
| PackageUserStateWrite userState = state.userState(userId); |
| userState.setStopped(stopped); |
| if (wasNotLaunched) { |
| userState.setNotLaunched(false); |
| } |
| }); |
| |
| if (wasNotLaunched) { |
| final String installerPackageName = |
| packageState.getInstallSource().mInstallerPackageName; |
| if (installerPackageName != null) { |
| notifyFirstLaunch(packageName, installerPackageName, userId); |
| } |
| } |
| |
| scheduleWritePackageRestrictions(userId); |
| } |
| } |
| |
| // If this would cause the app to leave force-stop, then also make sure to unhibernate the |
| // app if needed. |
| if (!stopped) { |
| mHandler.post(() -> { |
| AppHibernationManagerInternal ah = |
| mInjector.getLocalService(AppHibernationManagerInternal.class); |
| if (ah != null && ah.isHibernatingForUser(packageName, userId)) { |
| ah.setHibernatingForUser(packageName, userId, false); |
| ah.setHibernatingGlobally(packageName, false); |
| } |
| }); |
| // Send UNSTOPPED broadcast if necessary |
| if (wasStopped && Flags.stayStopped()) { |
| final PackageManagerInternal pmi = |
| mInjector.getLocalService(PackageManagerInternal.class); |
| final int [] userIds = resolveUserIds(userId); |
| final SparseArray<int[]> broadcastAllowList = |
| snapshotComputer().getVisibilityAllowLists(packageName, userIds); |
| final Bundle extras = new Bundle(); |
| extras.putInt(Intent.EXTRA_UID, pmi.getPackageUid(packageName, 0, userId)); |
| extras.putInt(Intent.EXTRA_USER_HANDLE, userId); |
| extras.putLong(Intent.EXTRA_TIME, SystemClock.elapsedRealtime()); |
| mHandler.post(() -> { |
| mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTOPPED, |
| packageName, extras, |
| Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, |
| userIds, null, broadcastAllowList, null, |
| null); |
| }); |
| mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_UNSTOPPED, |
| packageName, extras, userIds, null /* instantUserIds */, |
| broadcastAllowList, mHandler); |
| } |
| } |
| } |
| |
| void notifyComponentUsed(@NonNull Computer snapshot, @NonNull String packageName, |
| @UserIdInt int userId, @Nullable String recentCallingPackage, |
| @NonNull String debugInfo) { |
| synchronized (mLock) { |
| final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); |
| // If the package doesn't exist, don't need to proceed to setPackageStoppedState. |
| if (pkgSetting == null) { |
| return; |
| } |
| if (pkgSetting.getUserStateOrDefault(userId).isQuarantined()) { |
| Slog.i(TAG, |
| "Component is quarantined+suspended but being used: " |
| + packageName + " by " + recentCallingPackage + ", debugInfo: " |
| + debugInfo); |
| } |
| } |
| PackageManagerService.this |
| .setPackageStoppedState(snapshot, packageName, false /* stopped */, |
| userId); |
| } |
| |
| public class IPackageManagerImpl extends IPackageManagerBase { |
| |
| public IPackageManagerImpl() { |
| super(PackageManagerService.this, mContext, mDexOptHelper, mModuleInfoProvider, |
| mPreferredActivityHelper, mResolveIntentHelper, mDomainVerificationManager, |
| mDomainVerificationConnection, mInstallerService, mPackageProperty, |
| mResolveComponentName, mInstantAppResolverSettingsComponent, |
| mRequiredSdkSandboxPackage, mServicesExtensionPackageName, |
| mSharedSystemSharedLibraryPackageName); |
| } |
| |
| @Override |
| public void checkPackageStartable(String packageName, int userId) { |
| PackageManagerService.this |
| .checkPackageStartable(snapshotComputer(), packageName, userId); |
| } |
| |
| @Override |
| public void clearApplicationProfileData(String packageName) { |
| PackageManagerServiceUtils.enforceSystemOrRootOrShell( |
| "Only the system or shell can clear all profile data"); |
| |
| final Computer snapshot = snapshotComputer(); |
| final AndroidPackage pkg = snapshot.getPackage(packageName); |
| try (PackageFreezer ignored = |
| freezePackage(packageName, UserHandle.USER_ALL, |
| "clearApplicationProfileData", |
| ApplicationExitInfo.REASON_OTHER, null /* request */)) { |
| synchronized (mInstallLock) { |
| mAppDataHelper.clearAppProfilesLIF(pkg); |
| } |
| } |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.CLEAR_APP_USER_DATA) |
| @Override |
| public void clearApplicationUserData(final String packageName, |
| final IPackageDataObserver observer, final int userId) { |
| clearApplicationUserData_enforcePermission(); |
| |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, |
| false /* checkShell */, "clear application data"); |
| |
| if (snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, userId) == null) { |
| if (observer != null) { |
| mHandler.post(() -> { |
| try { |
| observer.onRemoveCompleted(packageName, false); |
| } catch (RemoteException e) { |
| Log.i(TAG, "Observer no longer exists."); |
| } |
| }); |
| } |
| return; |
| } |
| if (mProtectedPackages.isPackageDataProtected(userId, packageName)) { |
| throw new SecurityException("Cannot clear data for a protected package: " |
| + packageName); |
| } |
| final int callingPid = Binder.getCallingPid(); |
| EventLog.writeEvent(EventLogTags.PM_CLEAR_APP_DATA_CALLER, callingPid, callingUid, |
| packageName); |
| |
| // Queue up an async operation since the package deletion may take a little while. |
| mHandler.post(new Runnable() { |
| public void run() { |
| mHandler.removeCallbacks(this); |
| final boolean succeeded; |
| try (PackageFreezer freezer = freezePackage(packageName, UserHandle.USER_ALL, |
| "clearApplicationUserData", |
| ApplicationExitInfo.REASON_USER_REQUESTED, null /* request */)) { |
| synchronized (mInstallLock) { |
| succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName, |
| userId); |
| } |
| mInstantAppRegistry.deleteInstantApplicationMetadata(packageName, userId); |
| synchronized (mLock) { |
| if (succeeded) { |
| resetComponentEnabledSettingsIfNeededLPw(packageName, userId); |
| } |
| } |
| } |
| if (succeeded) { |
| // invoke DeviceStorageMonitor's update method to clear any notifications |
| DeviceStorageMonitorInternal dsm = LocalServices |
| .getService(DeviceStorageMonitorInternal.class); |
| if (dsm != null) { |
| dsm.checkMemory(); |
| } |
| if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId) |
| == PERMISSION_GRANTED) { |
| final Computer snapshot = snapshotComputer(); |
| unsuspendForSuspendingPackage(snapshot, packageName, userId); |
| removeAllDistractingPackageRestrictions(snapshot, userId); |
| synchronized (mLock) { |
| flushPackageRestrictionsAsUserInternalLocked(userId); |
| } |
| } |
| } |
| if (observer != null) { |
| try { |
| observer.onRemoveCompleted(packageName, succeeded); |
| } catch (RemoteException e) { |
| Log.i(TAG, "Observer no longer exists."); |
| } |
| } //end if observer |
| } //end run |
| }); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) |
| @Override |
| public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) { |
| clearCrossProfileIntentFilters_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| enforceOwnerRights(snapshot, ownerPackage, callingUid); |
| PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), |
| UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); |
| PackageManagerService.this.mInjector.getCrossProfileIntentFilterHelper() |
| .clearCrossProfileIntentFilters(sourceUserId, ownerPackage, |
| null); |
| scheduleWritePackageRestrictions(sourceUserId); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) |
| @Override |
| public boolean removeCrossProfileIntentFilter(IntentFilter intentFilter, |
| String ownerPackage, |
| int sourceUserId, |
| int targetUserId, int flags) { |
| removeCrossProfileIntentFilter_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| enforceOwnerRights(snapshotComputer(), ownerPackage, callingUid); |
| mUserManager.enforceCrossProfileIntentFilterAccess(sourceUserId, targetUserId, |
| callingUid, /* addCrossProfileIntentFilter */ false); |
| PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), |
| UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); |
| |
| boolean removedMatchingFilter = false; |
| synchronized (mLock) { |
| CrossProfileIntentResolver resolver = |
| mSettings.editCrossProfileIntentResolverLPw(sourceUserId); |
| |
| ArraySet<CrossProfileIntentFilter> set = |
| new ArraySet<>(resolver.filterSet()); |
| for (int i = 0; i < set.size(); i++) { |
| final CrossProfileIntentFilter filter = set.valueAt(i); |
| if (IntentFilter.filterEquals(filter.mFilter, intentFilter) |
| && filter.getOwnerPackage().equals(ownerPackage) |
| && filter.getTargetUserId() == targetUserId |
| && filter.getFlags() == flags) { |
| resolver.removeFilter(filter); |
| removedMatchingFilter = true; |
| break; |
| } |
| } |
| } |
| if (removedMatchingFilter) { |
| scheduleWritePackageRestrictions(sourceUserId); |
| } |
| return removedMatchingFilter; |
| } |
| |
| @Override |
| public final void deleteApplicationCacheFiles(final String packageName, |
| final IPackageDataObserver observer) { |
| final int userId = UserHandle.getCallingUserId(); |
| deleteApplicationCacheFilesAsUser(packageName, userId, observer); |
| } |
| |
| @Override |
| public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId, |
| final IPackageDataObserver observer) { |
| final int callingUid = Binder.getCallingUid(); |
| if (mContext.checkCallingOrSelfPermission( |
| android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES) |
| != PackageManager.PERMISSION_GRANTED) { |
| // If the caller has the old delete cache permission, silently ignore. Else throw. |
| if (mContext.checkCallingOrSelfPermission( |
| android.Manifest.permission.DELETE_CACHE_FILES) |
| == PackageManager.PERMISSION_GRANTED) { |
| Slog.w(TAG, "Calling uid " + callingUid + " does not have " + |
| android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES + |
| ", silently ignoring"); |
| return; |
| } |
| mContext.enforceCallingOrSelfPermission( |
| android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null); |
| } |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true, |
| /* checkShell= */ false, "delete application cache files"); |
| final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission( |
| android.Manifest.permission.ACCESS_INSTANT_APPS); |
| final int callingPid = Binder.getCallingPid(); |
| EventLog.writeEvent(EventLogTags.PM_CLEAR_APP_DATA_CALLER, callingPid, callingUid, |
| packageName); |
| |
| // Queue up an async operation since the package deletion may take a little while. |
| mHandler.post(() -> { |
| // Snapshot in the Handler Runnable since this may be deferred quite a bit |
| // TODO: Is this and the later mInstallLock re-snapshot necessary? |
| final Computer newSnapshot = snapshotComputer(); |
| final PackageStateInternal ps = newSnapshot.getPackageStateInternal(packageName); |
| boolean doClearData = true; |
| if (ps != null) { |
| final boolean targetIsInstantApp = |
| ps.getUserStateOrDefault(UserHandle.getUserId(callingUid)).isInstantApp(); |
| doClearData = !targetIsInstantApp |
| || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED; |
| } |
| if (doClearData) { |
| synchronized (mInstallLock) { |
| final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL; |
| // Snapshot again after mInstallLock? |
| final AndroidPackage pkg = snapshotComputer().getPackage(packageName); |
| // We're only clearing cache files, so we don't care if the |
| // app is unfrozen and still able to run |
| mAppDataHelper.clearAppDataLIF(pkg, userId, |
| flags | Installer.FLAG_CLEAR_CACHE_ONLY); |
| mAppDataHelper.clearAppDataLIF(pkg, userId, |
| flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); |
| } |
| } |
| if (observer != null) { |
| try { |
| observer.onRemoveCompleted(packageName, true); |
| } catch (RemoteException e) { |
| Log.i(TAG, "Observer no longer exists."); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public void enterSafeMode() { |
| PackageManagerServiceUtils.enforceSystemOrRoot( |
| "Only the system can request entering safe mode"); |
| |
| if (!mSystemReady) { |
| mSafeMode = true; |
| } |
| } |
| |
| @Override |
| public void extendVerificationTimeout(int verificationId, int verificationCodeAtTimeout, |
| long millisecondsToDelay) { |
| // Negative ids correspond to testing verifiers and will be silently enforced in |
| // the handler thread. |
| if (verificationId >= 0) { |
| mContext.enforceCallingOrSelfPermission( |
| Manifest.permission.PACKAGE_VERIFICATION_AGENT, |
| "Only package verification agents can extend verification timeouts"); |
| } |
| final int callingUid = Binder.getCallingUid(); |
| |
| mHandler.post(() -> { |
| final int id = verificationId >= 0 ? verificationId : -verificationId; |
| final PackageVerificationState state = mPendingVerification.get(id); |
| if (state == null || !state.extendTimeout(callingUid)) { |
| // Invalid uid or already extended. |
| return; |
| } |
| |
| final PackageVerificationResponse response = new PackageVerificationResponse( |
| verificationCodeAtTimeout, callingUid); |
| |
| long delay = millisecondsToDelay; |
| if (delay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) { |
| delay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT; |
| } |
| if (delay < 0) { |
| delay = 0; |
| } |
| |
| final Message msg = mHandler.obtainMessage(PackageManagerService.PACKAGE_VERIFIED); |
| msg.arg1 = id; |
| msg.obj = response; |
| mHandler.sendMessageDelayed(msg, delay); |
| }); |
| } |
| |
| @WorkerThread |
| @Override |
| public void flushPackageRestrictionsAsUser(int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final int callingUid = Binder.getCallingUid(); |
| if (snapshot.getInstantAppPackageName(callingUid) != null) { |
| return; |
| } |
| if (!mUserManager.exists(userId)) { |
| return; |
| } |
| snapshot.enforceCrossUserPermission(callingUid, userId, |
| false /* requireFullPermission*/, false /* checkShell */, |
| "flushPackageRestrictions"); |
| synchronized (mLock) { |
| flushPackageRestrictionsAsUserInternalLocked(userId); |
| } |
| } |
| |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.CLEAR_APP_CACHE) |
| @Override |
| public void freeStorage(final String volumeUuid, final long freeStorageSize, |
| final @StorageManager.AllocateFlags int flags, final IntentSender pi) { |
| freeStorage_enforcePermission(); |
| mHandler.post(() -> { |
| boolean success = false; |
| try { |
| PackageManagerService.this.freeStorage(volumeUuid, freeStorageSize, flags); |
| success = true; |
| } catch (IOException e) { |
| Slog.w(TAG, e); |
| } |
| if (pi != null) { |
| try { |
| final BroadcastOptions options = BroadcastOptions.makeBasic(); |
| options.setPendingIntentBackgroundActivityLaunchAllowed(false); |
| pi.sendIntent(null, success ? 1 : 0, null /* intent */, |
| null /* onFinished*/, null /* handler */, |
| null /* requiredPermission */, options.toBundle()); |
| } catch (SendIntentException e) { |
| Slog.w(TAG, e); |
| } |
| } |
| }); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.CLEAR_APP_CACHE) |
| @Override |
| public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize, |
| final @StorageManager.AllocateFlags int flags, final IPackageDataObserver observer) { |
| freeStorageAndNotify_enforcePermission(); |
| mHandler.post(() -> { |
| boolean success = false; |
| try { |
| PackageManagerService.this.freeStorage(volumeUuid, freeStorageSize, flags); |
| success = true; |
| } catch (IOException e) { |
| Slog.w(PackageManagerService.TAG, e); |
| } |
| if (observer != null) { |
| try { |
| observer.onRemoveCompleted(null, success); |
| } catch (RemoteException e) { |
| Slog.w(PackageManagerService.TAG, e); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public ChangedPackages getChangedPackages(int sequenceNumber, int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| if (snapshot.getInstantAppPackageName(callingUid) != null) { |
| return null; |
| } |
| if (!mUserManager.exists(userId)) { |
| return null; |
| } |
| snapshot.enforceCrossUserPermission(callingUid, userId, false, false, |
| "getChangedPackages"); |
| final ChangedPackages changedPackages = mChangedPackagesTracker.getChangedPackages( |
| sequenceNumber, userId); |
| |
| if (changedPackages != null) { |
| final List<String> packageNames = changedPackages.getPackageNames(); |
| for (int index = packageNames.size() - 1; index >= 0; index--) { |
| // Filter out the changes if the calling package should not be able to see it. |
| final PackageStateInternal packageState = |
| snapshot.getPackageStateInternal(packageNames.get(index)); |
| if (snapshot.shouldFilterApplication(packageState, callingUid, userId)) { |
| packageNames.remove(index); |
| } |
| } |
| } |
| |
| return changedPackages; |
| } |
| |
| @Override |
| public byte[] getDomainVerificationBackup(int userId) { |
| if (Binder.getCallingUid() != Process.SYSTEM_UID) { |
| throw new SecurityException("Only the system may call getDomainVerificationBackup()"); |
| } |
| |
| try { |
| try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { |
| TypedXmlSerializer serializer = Xml.resolveSerializer(output); |
| mDomainVerificationManager.writeSettings(snapshotComputer(), serializer, true, |
| userId); |
| return output.toByteArray(); |
| } |
| } catch (Exception e) { |
| if (PackageManagerService.DEBUG_BACKUP) { |
| Slog.e(PackageManagerService.TAG, "Unable to write domain verification for backup", e); |
| } |
| return null; |
| } |
| } |
| |
| @Override |
| public IBinder getHoldLockToken() { |
| if (!Build.IS_DEBUGGABLE) { |
| throw new SecurityException("getHoldLockToken requires a debuggable build"); |
| } |
| |
| mContext.enforceCallingPermission( |
| Manifest.permission.INJECT_EVENTS, |
| "getHoldLockToken requires INJECT_EVENTS permission"); |
| |
| final Binder token = new Binder(); |
| token.attachInterface(this, "holdLock:" + Binder.getCallingUid()); |
| return token; |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_INSTANT_APPS) |
| @Override |
| public String getInstantAppAndroidId(String packageName, int userId) { |
| getInstantAppAndroidId_enforcePermission(); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, |
| true /* requireFullPermission */, false /* checkShell */, |
| "getInstantAppAndroidId"); |
| // Make sure the target is an Instant App. |
| if (!snapshot.isInstantApp(packageName, userId)) { |
| return null; |
| } |
| return mInstantAppRegistry.getInstantAppAndroidId(packageName, userId); |
| } |
| |
| @Override |
| public byte[] getInstantAppCookie(String packageName, int userId) { |
| if (HIDE_EPHEMERAL_APIS) { |
| return null; |
| } |
| |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, |
| true /* requireFullPermission */, false /* checkShell */, |
| "getInstantAppCookie"); |
| if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) { |
| return null; |
| } |
| PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState == null || packageState.getPkg() == null) { |
| return null; |
| } |
| return mInstantAppRegistry.getInstantAppCookie(packageState.getPkg(), userId); |
| } |
| |
| @Override |
| public Bitmap getInstantAppIcon(String packageName, int userId) { |
| if (HIDE_EPHEMERAL_APIS) { |
| return null; |
| } |
| |
| final Computer snapshot = snapshotComputer(); |
| if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) { |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS, |
| "getInstantAppIcon"); |
| } |
| snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, |
| true /* requireFullPermission */, false /* checkShell */, |
| "getInstantAppIcon"); |
| |
| return mInstantAppRegistry.getInstantAppIcon(packageName, userId); |
| } |
| |
| @Override |
| public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) { |
| if (HIDE_EPHEMERAL_APIS) { |
| return null; |
| } |
| |
| final Computer snapshot = snapshotComputer(); |
| if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) { |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS, |
| "getEphemeralApplications"); |
| } |
| snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, |
| true /* requireFullPermission */, false /* checkShell */, |
| "getEphemeralApplications"); |
| |
| List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(snapshot, userId); |
| if (instantApps != null) { |
| return new ParceledListSlice<>(instantApps); |
| } |
| return null; |
| } |
| |
| @Override |
| public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) { |
| return mPreferredActivityHelper.getLastChosenActivity(snapshotComputer(), intent, |
| resolvedType, flags); |
| } |
| |
| @Override |
| public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage, |
| String featureId, int userId) throws RemoteException { |
| return mResolveIntentHelper.getLaunchIntentSenderForPackage(snapshotComputer(), |
| packageName, callingPackage, featureId, userId); |
| } |
| |
| @Override |
| public List<String> getMimeGroup(String packageName, String mimeGroup) { |
| final Computer snapshot = snapshotComputer(); |
| enforceOwnerRights(snapshot, packageName, Binder.getCallingUid()); |
| return getMimeGroupInternal(snapshot, packageName, mimeGroup); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) |
| @Override |
| public int getMoveStatus(int moveId) { |
| getMoveStatus_enforcePermission(); |
| return mMoveCallbacks.mLastStatus.get(moveId); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA) |
| @Override |
| public ParcelFileDescriptor getAppMetadataFd(String packageName, int userId) { |
| getAppMetadataFd_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, userId); |
| if (ps == null) { |
| throw new ParcelableException( |
| new PackageManager.NameNotFoundException(packageName)); |
| } |
| String filePath = ps.getAppMetadataFilePath(); |
| if (filePath != null) { |
| File file = new File(filePath); |
| try { |
| return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); |
| } catch (FileNotFoundException e) { |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public String getPermissionControllerPackageName() { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| final Computer snapshot = snapshotComputer(); |
| if (snapshot.getPackageStateForInstalledAndFiltered( |
| mRequiredPermissionControllerPackage, callingUid, callingUserId) != null) { |
| return mRequiredPermissionControllerPackage; |
| } |
| |
| throw new IllegalStateException("PermissionController is not found"); |
| } |
| |
| @Override |
| @SuppressWarnings("GuardedBy") |
| public int getRuntimePermissionsVersion(@UserIdInt int userId) { |
| Preconditions.checkArgumentNonnegative(userId); |
| enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( |
| "getRuntimePermissionVersion"); |
| return mSettings.getDefaultRuntimePermissionsVersion(userId); |
| } |
| |
| @Override |
| public String getSplashScreenTheme(@NonNull String packageName, int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final int callingUid = Binder.getCallingUid(); |
| snapshot.enforceCrossUserPermission( |
| callingUid, userId, false /* requireFullPermission */, |
| false /* checkShell */, "getSplashScreenTheme"); |
| PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, userId); |
| return packageState == null ? null |
| : packageState.getUserStateOrDefault(userId).getSplashScreenTheme(); |
| } |
| |
| @Override |
| @PackageManager.UserMinAspectRatio |
| public int getUserMinAspectRatio(@NonNull String packageName, int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final int callingUid = Binder.getCallingUid(); |
| final PackageStateInternal packageState = snapshot |
| .getPackageStateForInstalledAndFiltered(packageName, callingUid, userId); |
| return packageState == null ? USER_MIN_ASPECT_RATIO_UNSET |
| : packageState.getUserStateOrDefault(userId).getMinAspectRatio(); |
| } |
| |
| @Override |
| public Bundle getSuspendedPackageAppExtras(String packageName, int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshot(); |
| if (snapshot.getPackageUid(packageName, 0, userId) != callingUid) { |
| throw new SecurityException("Calling package " + packageName |
| + " does not belong to calling uid " + callingUid); |
| } |
| return SuspendPackageHelper |
| .getSuspendedPackageAppExtras(snapshot, packageName, userId, callingUid); |
| } |
| |
| @Override |
| public String getSuspendingPackage(String packageName, int userId) { |
| try { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshot(); |
| // This will do visibility checks as well. |
| if (!snapshot.isPackageSuspendedForUser(packageName, userId)) { |
| return null; |
| } |
| final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage( |
| snapshot, packageName, userId, callingUid); |
| return suspender != null ? suspender.packageName : null; |
| } catch (PackageManager.NameNotFoundException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() { |
| // allow instant applications |
| ArrayList<FeatureInfo> res; |
| synchronized (mAvailableFeatures) { |
| res = new ArrayList<>(mAvailableFeatures.size() + 1); |
| res.addAll(mAvailableFeatures.values()); |
| } |
| final FeatureInfo fi = new FeatureInfo(); |
| fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version", |
| FeatureInfo.GL_ES_VERSION_UNDEFINED); |
| res.add(fi); |
| |
| return new ParceledListSlice<>(res); |
| } |
| |
| @Override |
| public @NonNull List<String> getInitialNonStoppedSystemPackages() { |
| return mInitialNonStoppedSystemPackages != null |
| ? new ArrayList<>(mInitialNonStoppedSystemPackages) : new ArrayList<>(); |
| } |
| |
| @Override |
| public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) { |
| Objects.requireNonNull(packageNames, "packageNames cannot be null"); |
| mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, |
| "getUnsuspendablePackagesForUser"); |
| final int callingUid = Binder.getCallingUid(); |
| if (UserHandle.getUserId(callingUid) != userId) { |
| mContext.enforceCallingOrSelfPermission( |
| Manifest.permission.INTERACT_ACROSS_USERS_FULL, |
| "Calling uid " + callingUid |
| + " cannot query getUnsuspendablePackagesForUser for user " |
| + userId); |
| } |
| return mSuspendPackageHelper.getUnsuspendablePackagesForUser(snapshotComputer(), |
| packageNames, userId, callingUid); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT) |
| @Override |
| public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { |
| getVerifierDeviceIdentity_enforcePermission(); |
| |
| synchronized (mLock) { |
| return mSettings.getVerifierDeviceIdentityLPw(mLiveComputer); |
| } |
| } |
| |
| @Override |
| public void makeProviderVisible(int recipientUid, @NonNull String visibleAuthority) { |
| final Computer snapshot = snapshotComputer(); |
| final int recipientUserId = UserHandle.getUserId(recipientUid); |
| final ProviderInfo providerInfo = |
| snapshot.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority); |
| if (providerInfo == null) { |
| return; |
| } |
| int visibleUid = providerInfo.applicationInfo.uid; |
| PackageManagerService.this.grantImplicitAccess(snapshot, recipientUserId, |
| null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid, |
| false /*direct*/, false /* retainOnUpdate */); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MAKE_UID_VISIBLE) |
| @Override |
| public void makeUidVisible(int recipientUid, int visibleUid) { |
| makeUidVisible_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| final int recipientUserId = UserHandle.getUserId(recipientUid); |
| final int visibleUserId = UserHandle.getUserId(visibleUid); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, recipientUserId, |
| false /* requireFullPermission */, false /* checkShell */, "makeUidVisible"); |
| snapshot.enforceCrossUserPermission(callingUid, visibleUserId, |
| false /* requireFullPermission */, false /* checkShell */, "makeUidVisible"); |
| snapshot.enforceCrossUserPermission(recipientUid, visibleUserId, |
| false /* requireFullPermission */, false /* checkShell */, "makeUidVisible"); |
| |
| PackageManagerService.this.grantImplicitAccess(snapshot, recipientUserId, |
| null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid, |
| false /*direct*/, false /* retainOnUpdate */); |
| } |
| |
| @Override |
| public void holdLock(IBinder token, int durationMs) { |
| mTestUtilityService.verifyHoldLockToken(token); |
| |
| synchronized (mLock) { |
| SystemClock.sleep(durationMs); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @Override |
| public int installExistingPackageAsUser(String packageName, int userId, int installFlags, |
| int installReason, List<String> whiteListedPermissions) { |
| return mInstallPackageHelper.installExistingPackageAsUser(packageName, userId, installFlags, |
| installReason, whiteListedPermissions, null).first; |
| } |
| |
| @Override |
| public boolean isAutoRevokeWhitelisted(String packageName) { |
| int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow( |
| AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, |
| Binder.getCallingUid(), packageName); |
| return mode == MODE_IGNORED; |
| } |
| |
| @Override |
| public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingAppId = UserHandle.getAppId(callingUid); |
| |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, |
| true /*checkShell*/, "isPackageStateProtected"); |
| |
| if (!PackageManagerServiceUtils.isSystemOrRoot(callingAppId) |
| && snapshot.checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) |
| != PERMISSION_GRANTED) { |
| throw new SecurityException("Caller must have the " |
| + MANAGE_DEVICE_ADMINS + " permission."); |
| } |
| |
| return mProtectedPackages.isPackageStateProtected(userId, packageName); |
| } |
| |
| @Override |
| public boolean isProtectedBroadcast(String actionName) { |
| if (actionName != null) { |
| // TODO: remove these terrible hacks |
| if (actionName.startsWith("android.net.netmon.lingerExpired") |
| || actionName.startsWith("com.android.server.sip.SipWakeupTimer") |
| || actionName.startsWith("com.android.internal.telephony.data-reconnect") |
| || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) { |
| return true; |
| } |
| } |
| // allow instant applications |
| synchronized (mProtectedBroadcasts) { |
| return mProtectedBroadcasts.contains(actionName); |
| } |
| } |
| |
| /** |
| * Logs process start information (including base APK hash) to the security log. |
| * @hide |
| */ |
| @Override |
| public void logAppProcessStartIfNeeded(String packageName, String processName, int uid, |
| String seinfo, String apkFile, int pid) { |
| final Computer snapshot = snapshotComputer(); |
| if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) { |
| return; |
| } |
| if (!SecurityLog.isLoggingEnabled()) { |
| return; |
| } |
| mProcessLoggingHandler.logAppProcessStart(mContext, |
| LocalServices.getService(PackageManagerInternal.class), apkFile, packageName, |
| processName, uid, seinfo, pid); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MOVE_PACKAGE) |
| @Override |
| public int movePackage(final String packageName, final String volumeUuid) { |
| movePackage_enforcePermission(); |
| |
| final int callingUid = Binder.getCallingUid(); |
| final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid)); |
| final int moveId = mNextMoveId.getAndIncrement(); |
| mHandler.post(() -> { |
| try { |
| MovePackageHelper movePackageHelper = |
| new MovePackageHelper(PackageManagerService.this); |
| movePackageHelper.movePackageInternal( |
| packageName, volumeUuid, moveId, callingUid, user); |
| } catch (PackageManagerException e) { |
| Slog.w(PackageManagerService.TAG, "Failed to move " + packageName, e); |
| mMoveCallbacks.notifyStatusChanged(moveId, e.error); |
| } |
| }); |
| return moveId; |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MOVE_PACKAGE) |
| @Override |
| public int movePrimaryStorage(String volumeUuid) throws RemoteException { |
| movePrimaryStorage_enforcePermission(); |
| |
| final int realMoveId = mNextMoveId.getAndIncrement(); |
| final Bundle extras = new Bundle(); |
| extras.putString(VolumeRecord.EXTRA_FS_UUID, volumeUuid); |
| mMoveCallbacks.notifyCreated(realMoveId, extras); |
| |
| final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() { |
| @Override |
| public void onCreated(int moveId, Bundle extras) { |
| // Ignored |
| } |
| |
| @Override |
| public void onStatusChanged(int moveId, int status, long estMillis) { |
| mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis); |
| } |
| }; |
| |
| final StorageManager storage = mInjector.getSystemService(StorageManager.class); |
| storage.setPrimaryStorageUuid(volumeUuid, callback); |
| return realMoveId; |
| } |
| |
| @Override |
| public void notifyDexLoad(String loadingPackageName, |
| Map<String, String> classLoaderContextMap, |
| String loaderIsa) { |
| int callingUid = Binder.getCallingUid(); |
| Computer snapshot = snapshot(); |
| |
| // System server should be able to report dex load on behalf of other apps. E.g., it |
| // could potentially resend the notifications in order to migrate the existing dex load |
| // info to ART Service. |
| if (!PackageManagerServiceUtils.isSystemOrRoot() |
| && !snapshot.isCallerSameApp( |
| loadingPackageName, callingUid, true /* resolveIsolatedUid */)) { |
| Slog.w(PackageManagerService.TAG, |
| TextUtils.formatSimple( |
| "Invalid dex load report. loadingPackageName=%s, uid=%d", |
| loadingPackageName, callingUid)); |
| return; |
| } |
| |
| UserHandle user = Binder.getCallingUserHandle(); |
| int userId = user.getIdentifier(); |
| |
| // Proxy the call to either ART Service or the legacy implementation. If the |
| // implementation is switched with the system property, the dex usage info will be |
| // incomplete, with these effects: |
| // |
| // - Shared dex files may temporarily get compiled for private use. |
| // - Secondary dex files may not get compiled at all. |
| // - Stale compiled artifacts for secondary dex files may not get cleaned up. |
| // |
| // This recovers in the first background dexopt after the depending apps have been |
| // loaded for the first time. |
| |
| DexUseManagerLocal dexUseManager = DexOptHelper.getDexUseManagerLocal(); |
| if (dexUseManager != null) { |
| // TODO(chiuwinson): Retrieve filtered snapshot from Computer instance instead. |
| try (PackageManagerLocal.FilteredSnapshot filteredSnapshot = |
| LocalManagerRegistry.getManager(PackageManagerLocal.class) |
| .withFilteredSnapshot(callingUid, user)) { |
| if (loaderIsa != null) { |
| // Check that loaderIsa agrees with the ISA that dexUseManager will |
| // determine. |
| PackageState loadingPkgState = |
| filteredSnapshot.getPackageState(loadingPackageName); |
| // If we don't find the loading package just pass it through and let |
| // dexUseManager throw on it. |
| if (loadingPkgState != null) { |
| String loadingPkgAbi = loadingPkgState.getPrimaryCpuAbi(); |
| if (loadingPkgAbi == null) { |
| loadingPkgAbi = Build.SUPPORTED_ABIS[0]; |
| } |
| String loadingPkgDexCodeIsa = InstructionSets.getDexCodeInstructionSet( |
| VMRuntime.getInstructionSet(loadingPkgAbi)); |
| if (!loaderIsa.equals(loadingPkgDexCodeIsa)) { |
| // TODO(b/251903639): We make this a wtf to surface any situations |
| // where this argument doesn't correspond to our expectations. Later |
| // it should be turned into an IllegalArgumentException, when we can |
| // assume it's the caller that's wrong rather than us. |
| Log.wtf(TAG, |
| "Invalid loaderIsa in notifyDexLoad call from " |
| + loadingPackageName + ", uid " + callingUid |
| + ": expected " + loadingPkgDexCodeIsa + ", got " |
| + loaderIsa); |
| return; |
| } |
| } |
| } |
| |
| // This is called from binder, so exceptions thrown here are caught and handled |
| // by it. |
| dexUseManager.notifyDexContainersLoaded( |
| filteredSnapshot, loadingPackageName, classLoaderContextMap); |
| } |
| } else { |
| ApplicationInfo ai = |
| snapshot.getApplicationInfo(loadingPackageName, /*flags*/ 0, userId); |
| if (ai == null) { |
| Slog.w(PackageManagerService.TAG, |
| "Loading a package that does not exist for the calling user. package=" |
| + loadingPackageName + ", user=" + userId); |
| return; |
| } |
| mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId, |
| Process.isIsolated(callingUid)); |
| } |
| } |
| |
| @Override |
| public void notifyPackageUse(String packageName, int reason) { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| Computer snapshot = snapshotComputer(); |
| final boolean notify; |
| if (snapshot.getInstantAppPackageName(callingUid) != null) { |
| notify = snapshot.isCallerSameApp(packageName, callingUid); |
| } else { |
| notify = !snapshot.isInstantAppInternal(packageName, callingUserId, |
| Process.SYSTEM_UID); |
| } |
| if (!notify) { |
| return; |
| } |
| |
| notifyPackageUseInternal(packageName, reason); |
| } |
| |
| @Override |
| public void overrideLabelAndIcon(@NonNull ComponentName componentName, |
| @NonNull String nonLocalizedLabel, int icon, int userId) { |
| if (TextUtils.isEmpty(nonLocalizedLabel)) { |
| throw new IllegalArgumentException("Override label should be a valid String"); |
| } |
| updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId); |
| } |
| |
| @Override |
| public ParceledListSlice<PackageManager.Property> queryProperty( |
| String propertyName, @PackageManager.PropertyLocation int componentType) { |
| Objects.requireNonNull(propertyName); |
| final int callingUid = Binder.getCallingUid(); |
| final int callingUserId = UserHandle.getCallingUserId(); |
| final Computer snapshot = snapshotComputer(); |
| final List<PackageManager.Property> result = |
| mPackageProperty.queryProperty(propertyName, componentType, |
| packageName -> snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, callingUserId) == null |
| ); |
| if (result == null) { |
| return ParceledListSlice.emptyList(); |
| } |
| return new ParceledListSlice<>(result); |
| } |
| |
| @Override |
| public void registerDexModule(String packageName, String dexModulePath, |
| boolean isSharedModule, |
| IDexModuleRegisterCallback callback) { |
| // ART Service doesn't support this explicit dexopting and instead relies on background |
| // dexopt for secondary dex files. For compat parity between ART Service and the legacy |
| // code it's disabled for both. |
| // |
| // Also, this API is problematic anyway since it doesn't provide the correct classloader |
| // context, so it is hard to produce dexopt artifacts that the runtime can load |
| // successfully. |
| Slog.i(TAG, |
| "Ignored unsupported registerDexModule call for " + dexModulePath + " in " |
| + packageName); |
| DexManager.RegisterDexModuleResult result = new DexManager.RegisterDexModuleResult( |
| false, "registerDexModule call not supported since Android U"); |
| |
| if (callback != null) { |
| mHandler.post(() -> { |
| try { |
| callback.onDexModuleRegistered(dexModulePath, result.success, |
| result.message); |
| } catch (RemoteException e) { |
| Slog.w(PackageManagerService.TAG, |
| "Failed to callback after module registration " + dexModulePath, e); |
| } |
| }); |
| } |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) |
| @Override |
| public void registerMoveCallback(IPackageMoveObserver callback) { |
| registerMoveCallback_enforcePermission(); |
| mMoveCallbacks.register(callback); |
| } |
| |
| @Override |
| public void restoreDomainVerification(byte[] backup, int userId) { |
| if (Binder.getCallingUid() != Process.SYSTEM_UID) { |
| throw new SecurityException("Only the system may call restorePreferredActivities()"); |
| } |
| |
| try { |
| ByteArrayInputStream input = new ByteArrayInputStream(backup); |
| TypedXmlPullParser parser = Xml.resolvePullParser(input); |
| |
| // User ID input isn't necessary here as it assumes the user integers match and that |
| // the only states inside the backup XML are for the target user. |
| mDomainVerificationManager.restoreSettings(snapshotComputer(), parser); |
| input.close(); |
| } catch (Exception e) { |
| if (PackageManagerService.DEBUG_BACKUP) { |
| Slog.e(PackageManagerService.TAG, "Exception restoring domain verification: " + e.getMessage()); |
| } |
| } |
| } |
| |
| @Override |
| public void restoreLabelAndIcon(@NonNull ComponentName componentName, int userId) { |
| updateComponentLabelIcon(componentName, null, null, userId); |
| } |
| |
| @Override |
| public void sendDeviceCustomizationReadyBroadcast() { |
| mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY, |
| "sendDeviceCustomizationReadyBroadcast"); |
| |
| final long ident = Binder.clearCallingIdentity(); |
| try { |
| BroadcastHelper.sendDeviceCustomizationReadyBroadcast(); |
| } finally { |
| Binder.restoreCallingIdentity(ident); |
| } |
| } |
| |
| @Override |
| public void setApplicationCategoryHint(String packageName, int categoryHint, |
| String callerPackageName) { |
| final FunctionalUtils.ThrowingBiFunction<PackageStateMutator.InitialState, Computer, |
| PackageStateMutator.Result> implementation = (initialState, computer) -> { |
| if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) { |
| throw new SecurityException( |
| "Instant applications don't have access to this method"); |
| } |
| mInjector.getSystemService(AppOpsManager.class) |
| .checkPackage(Binder.getCallingUid(), callerPackageName); |
| |
| PackageStateInternal packageState = computer.getPackageStateForInstalledAndFiltered( |
| packageName, Binder.getCallingUid(), UserHandle.getCallingUserId()); |
| if (packageState == null) { |
| throw new IllegalArgumentException("Unknown target package " + packageName); |
| } |
| |
| if (!Objects.equals(callerPackageName, |
| packageState.getInstallSource().mInstallerPackageName)) { |
| throw new IllegalArgumentException("Calling package " + callerPackageName |
| + " is not installer for " + packageName); |
| } |
| |
| if (packageState.getCategoryOverride() != categoryHint) { |
| return commitPackageStateMutation(initialState, |
| packageName, state -> state.setCategoryOverride(categoryHint)); |
| } else { |
| return null; |
| } |
| }; |
| |
| PackageStateMutator.Result result = |
| implementation.apply(recordInitialState(), snapshotComputer()); |
| if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) { |
| // TODO: Specific return value of what state changed? |
| // The installer on record might have changed, retry with lock |
| synchronized (mPackageStateWriteLock) { |
| result = implementation.apply(recordInitialState(), snapshotComputer()); |
| } |
| } |
| |
| if (result != null && result.isCommitted()) { |
| scheduleWriteSettings(); |
| } |
| } |
| |
| @Override |
| public void setApplicationEnabledSetting(String appPackageName, |
| int newState, int flags, int userId, String callingPackage) { |
| if (!mUserManager.exists(userId)) return; |
| if (callingPackage == null) { |
| callingPackage = Integer.toString(Binder.getCallingUid()); |
| } |
| |
| setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(appPackageName, newState, flags)), |
| userId, callingPackage); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_USERS) |
| @Override |
| public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, |
| int userId) { |
| setApplicationHiddenSettingAsUser_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, |
| true /* checkShell */, "setApplicationHiddenSetting for user " + userId); |
| |
| if (hidden && isPackageDeviceAdmin(packageName, userId)) { |
| Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin"); |
| return false; |
| } |
| |
| // Do not allow "android" is being disabled |
| if ("android".equals(packageName)) { |
| Slog.w(TAG, "Cannot hide package: android"); |
| return false; |
| } |
| |
| final long callingId = Binder.clearCallingIdentity(); |
| try { |
| final PackageStateInternal packageState = snapshot.getPackageStateInternal( |
| packageName); |
| if (packageState == null) { |
| return false; |
| } |
| |
| final PackageUserStateInternal userState = packageState.getUserStateOrDefault( |
| userId); |
| if (userState.isHidden() == hidden || !userState.isInstalled() |
| || snapshot.shouldFilterApplication(packageState, callingUid, userId)) { |
| return false; |
| } |
| |
| // Cannot hide static shared libs as they are considered |
| // a part of the using app (emulating static linking). Also |
| // static libs are installed always on internal storage. |
| AndroidPackage pkg = packageState.getPkg(); |
| if (pkg != null) { |
| // Cannot hide SDK libs as they are controlled by SDK manager. |
| if (pkg.getSdkLibraryName() != null) { |
| Slog.w(TAG, "Cannot hide package: " + packageName |
| + " providing SDK library: " |
| + pkg.getSdkLibraryName()); |
| return false; |
| } |
| // Cannot hide static shared libs as they are considered |
| // a part of the using app (emulating static linking). Also |
| // static libs are installed always on internal storage. |
| if (pkg.getStaticSharedLibraryName() != null) { |
| Slog.w(TAG, "Cannot hide package: " + packageName |
| + " providing static shared library: " |
| + pkg.getStaticSharedLibraryName()); |
| return false; |
| } |
| } |
| // Only allow protected packages to hide themselves. |
| if (hidden && !UserHandle.isSameApp(callingUid, packageState.getAppId()) |
| && mProtectedPackages.isPackageStateProtected(userId, packageName)) { |
| Slog.w(TAG, "Not hiding protected package: " + packageName); |
| return false; |
| } |
| |
| commitPackageStateMutation(null, packageName, packageState1 -> |
| packageState1.userState(userId).setHidden(hidden)); |
| |
| final Computer newSnapshot = snapshotComputer(); |
| final PackageStateInternal newPackageState = |
| newSnapshot.getPackageStateInternal(packageName); |
| |
| if (hidden) { |
| killApplication(packageName, newPackageState.getAppId(), userId, "hiding pkg", |
| ApplicationExitInfo.REASON_OTHER); |
| mBroadcastHelper.sendApplicationHiddenForUser( |
| packageName, newPackageState, userId, |
| /* packageSender= */ PackageManagerService.this); |
| } else { |
| mBroadcastHelper.sendPackageAddedForUser( |
| newSnapshot, packageName, newPackageState, userId, |
| false /* isArchived */, DataLoaderType.NONE, |
| mAppPredictionServicePackage); |
| } |
| |
| scheduleWritePackageRestrictions(userId); |
| return true; |
| } finally { |
| Binder.restoreCallingIdentity(callingId); |
| } |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.DELETE_PACKAGES) |
| @Override |
| public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, |
| int userId) { |
| setBlockUninstallForUser_enforcePermission(); |
| final Computer snapshot = snapshotComputer(); |
| PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState != null && packageState.getPkg() != null) { |
| AndroidPackage pkg = packageState.getPkg(); |
| // Cannot block uninstall SDK libs as they are controlled by SDK manager. |
| if (pkg.getSdkLibraryName() != null) { |
| Slog.w(PackageManagerService.TAG, "Cannot block uninstall of package: " + packageName |
| + " providing SDK library: " + pkg.getSdkLibraryName()); |
| return false; |
| } |
| // Cannot block uninstall of static shared libs as they are |
| // considered a part of the using app (emulating static linking). |
| // Also static libs are installed always on internal storage. |
| if (pkg.getStaticSharedLibraryName() != null) { |
| Slog.w(PackageManagerService.TAG, "Cannot block uninstall of package: " + packageName |
| + " providing static shared library: " + pkg.getStaticSharedLibraryName()); |
| return false; |
| } |
| } |
| synchronized (mLock) { |
| mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall); |
| } |
| |
| scheduleWritePackageRestrictions(userId); |
| return true; |
| } |
| |
| @Override |
| public void setComponentEnabledSetting(ComponentName componentName, |
| int newState, int flags, int userId, String callingPackage) { |
| if (!mUserManager.exists(userId)) return; |
| if (callingPackage == null) { |
| callingPackage = Integer.toString(Binder.getCallingUid()); |
| } |
| |
| setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(componentName, newState, flags)), |
| userId, callingPackage); |
| } |
| |
| @Override |
| public void setComponentEnabledSettings( |
| List<PackageManager.ComponentEnabledSetting> settings, int userId, |
| String callingPackage) { |
| if (!mUserManager.exists(userId)) return; |
| if (settings == null || settings.isEmpty()) { |
| throw new IllegalArgumentException("The list of enabled settings is empty"); |
| } |
| if (callingPackage == null) { |
| callingPackage = Integer.toString(Binder.getCallingUid()); |
| } |
| setEnabledSettings(settings, userId, callingPackage); |
| } |
| |
| @Override |
| public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames, |
| int restrictionFlags, int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| enforceCanSetDistractingPackageRestrictionsAsUser(callingUid, userId, |
| "setDistractingPackageRestrictionsAsUser"); |
| Objects.requireNonNull(packageNames, "packageNames cannot be null"); |
| return mDistractingPackageHelper.setDistractingPackageRestrictionsAsUser(snapshot, |
| packageNames, restrictionFlags, userId, callingUid); |
| } |
| |
| @Override |
| public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning, |
| int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingAppId = UserHandle.getAppId(callingUid); |
| |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/, |
| true /*checkShell*/, "setHarmfulAppInfo"); |
| |
| if (!PackageManagerServiceUtils.isSystemOrRoot(callingAppId) |
| && snapshot.checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) |
| != PERMISSION_GRANTED) { |
| throw new SecurityException("Caller must have the " |
| + SET_HARMFUL_APP_WARNINGS + " permission."); |
| } |
| |
| PackageStateMutator.Result result = commitPackageStateMutation(null, packageName, |
| packageState -> packageState.userState(userId) |
| .setHarmfulAppWarning(warning == null ? null : warning.toString())); |
| if (result.isSpecificPackageNull()) { |
| throw new IllegalArgumentException("Unknown package: " + packageName); |
| } |
| scheduleWritePackageRestrictions(userId); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) |
| @Override |
| public boolean setInstallLocation(int loc) { |
| setInstallLocation_enforcePermission(); |
| if (getInstallLocation() == loc) { |
| return true; |
| } |
| if (loc == InstallLocationUtils.APP_INSTALL_AUTO |
| || loc == InstallLocationUtils.APP_INSTALL_INTERNAL |
| || loc == InstallLocationUtils.APP_INSTALL_EXTERNAL) { |
| android.provider.Settings.Global.putInt(mContext.getContentResolver(), |
| android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION, loc); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public void setInstallerPackageName(String targetPackage, |
| @Nullable String installerPackageName) { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| final FunctionalUtils.ThrowingCheckedFunction<Computer, Boolean, RuntimeException> |
| implementation = snapshot -> { |
| if (snapshot.getInstantAppPackageName(callingUid) != null) { |
| return false; |
| } |
| |
| PackageStateInternal targetPackageState = |
| snapshot.getPackageStateForInstalledAndFiltered( |
| targetPackage, callingUid, callingUserId); |
| if (targetPackageState == null) { |
| throw new IllegalArgumentException("Unknown target package: " + targetPackage); |
| } |
| |
| PackageStateInternal installerPackageState = null; |
| if (installerPackageName != null) { |
| installerPackageState = snapshot.getPackageStateForInstalledAndFiltered( |
| installerPackageName, callingUid, callingUserId); |
| if (installerPackageState == null) { |
| throw new IllegalArgumentException("Unknown installer package: " |
| + installerPackageName); |
| } |
| } |
| |
| SigningDetails callerSigningDetails; |
| final int appId = UserHandle.getAppId(callingUid); |
| Pair<PackageStateInternal, SharedUserApi> either = |
| snapshot.getPackageOrSharedUser(appId); |
| if (either != null) { |
| if (either.first != null) { |
| callerSigningDetails = either.first.getSigningDetails(); |
| } else { |
| callerSigningDetails = either.second.getSigningDetails(); |
| } |
| } else { |
| throw new SecurityException("Unknown calling UID: " + callingUid); |
| } |
| |
| // Verify: can't set installerPackageName to a package that is |
| // not signed with the same cert as the caller. |
| if (installerPackageState != null) { |
| if (compareSignatures(callerSigningDetails, |
| installerPackageState.getSigningDetails()) |
| != PackageManager.SIGNATURE_MATCH) { |
| throw new SecurityException( |
| "Caller does not have same cert as new installer package " |
| + installerPackageName); |
| } |
| } |
| |
| // Verify: if target already has an installer package, it must |
| // be signed with the same cert as the caller. |
| String targetInstallerPackageName = |
| targetPackageState.getInstallSource().mInstallerPackageName; |
| PackageStateInternal targetInstallerPkgSetting = targetInstallerPackageName == null |
| ? null : snapshot.getPackageStateInternal(targetInstallerPackageName); |
| |
| if (targetInstallerPkgSetting != null) { |
| if (compareSignatures(callerSigningDetails, |
| targetInstallerPkgSetting.getSigningDetails()) |
| != PackageManager.SIGNATURE_MATCH) { |
| throw new SecurityException( |
| "Caller does not have same cert as old installer package " |
| + targetInstallerPackageName); |
| } |
| } else if (mContext.checkCallingOrSelfPermission( |
| Manifest.permission.INSTALL_PACKAGES) != PERMISSION_GRANTED) { |
| // This is probably an attempt to exploit vulnerability b/150857253 of taking |
| // privileged installer permissions when the installer has been uninstalled or |
| // was never set. |
| EventLog.writeEvent(0x534e4554, "150857253", callingUid, ""); |
| |
| final long binderToken = Binder.clearCallingIdentity(); |
| try { |
| if (mInjector.getCompatibility().isChangeEnabledByUid( |
| PackageManagerService.THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE, |
| callingUid)) { |
| throw new SecurityException("Neither user " + callingUid |
| + " nor current process has " |
| + Manifest.permission.INSTALL_PACKAGES); |
| } else { |
| // If change disabled, fail silently for backwards compatibility |
| return false; |
| } |
| } finally { |
| Binder.restoreCallingIdentity(binderToken); |
| } |
| } |
| |
| return true; |
| }; |
| PackageStateMutator.InitialState initialState = recordInitialState(); |
| boolean allowed = implementation.apply(snapshotComputer()); |
| if (allowed) { |
| // TODO: Need to lock around here to handle mSettings.addInstallerPackageNames, |
| // should find an alternative which avoids any race conditions |
| final int installerPackageUid = installerPackageName == null |
| ? INVALID_UID : snapshotComputer().getPackageUid(installerPackageName, |
| 0 /* flags */, callingUserId); |
| PackageStateInternal targetPackageState; |
| synchronized (mLock) { |
| PackageStateMutator.Result result = commitPackageStateMutation(initialState, |
| targetPackage, state -> state.setInstaller(installerPackageName, |
| installerPackageUid)); |
| if (result.isPackagesChanged() || result.isStateChanged()) { |
| synchronized (mPackageStateWriteLock) { |
| allowed = implementation.apply(snapshotComputer()); |
| if (allowed) { |
| commitPackageStateMutation(null, targetPackage, |
| state -> state.setInstaller(installerPackageName, |
| installerPackageUid)); |
| } else { |
| return; |
| } |
| } |
| } |
| targetPackageState = snapshotComputer().getPackageStateInternal(targetPackage); |
| mSettings.addInstallerPackageNames(targetPackageState.getInstallSource()); |
| } |
| mAppsFilter.addPackage(snapshotComputer(), targetPackageState); |
| scheduleWriteSettings(); |
| } |
| } |
| |
| @Override |
| public void relinquishUpdateOwnership(String targetPackage) { |
| final int callingUid = Binder.getCallingUid(); |
| final int callingUserId = UserHandle.getUserId(callingUid); |
| final Computer snapshot = snapshotComputer(); |
| |
| final PackageStateInternal targetPackageState = |
| snapshot.getPackageStateForInstalledAndFiltered(targetPackage, callingUid, |
| callingUserId); |
| if (targetPackageState == null) { |
| throw new IllegalArgumentException("Unknown target package: " + targetPackage); |
| } |
| |
| final String targetUpdateOwnerPackageName = |
| targetPackageState.getInstallSource().mUpdateOwnerPackageName; |
| final PackageStateInternal targetUpdateOwnerPkgSetting = |
| targetUpdateOwnerPackageName == null ? null |
| : snapshot.getPackageStateInternal(targetUpdateOwnerPackageName); |
| |
| if (targetUpdateOwnerPkgSetting == null) { |
| return; |
| } |
| |
| final int callingAppId = UserHandle.getAppId(callingUid); |
| final int targetUpdateOwnerAppId = targetUpdateOwnerPkgSetting.getAppId(); |
| if (callingAppId != Process.SYSTEM_UID |
| && callingAppId != Process.SHELL_UID |
| && callingAppId != targetUpdateOwnerAppId) { |
| throw new SecurityException("Caller is not the current update owner."); |
| } |
| |
| commitPackageStateMutation(null /* initialState */, targetPackage, |
| state -> state.setUpdateOwner(null /* updateOwnerPackageName */)); |
| scheduleWriteSettings(); |
| } |
| |
| @Override |
| public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) { |
| if (HIDE_EPHEMERAL_APIS) { |
| return true; |
| } |
| |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, |
| true /* requireFullPermission */, true /* checkShell */, |
| "setInstantAppCookie"); |
| if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) { |
| return false; |
| } |
| |
| PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState == null || packageState.getPkg() == null) { |
| return false; |
| } |
| return mInstantAppRegistry.setInstantAppCookie(packageState.getPkg(), cookie, |
| mContext.getPackageManager().getInstantAppCookieMaxBytes(), userId); |
| } |
| |
| @Override |
| public void setKeepUninstalledPackages(List<String> packageList) { |
| mContext.enforceCallingPermission( |
| Manifest.permission.KEEP_UNINSTALLED_PACKAGES, |
| "setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission"); |
| Objects.requireNonNull(packageList); |
| |
| setKeepUninstalledPackagesInternal(snapshot(), packageList); |
| } |
| |
| @Override |
| public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) { |
| final Computer snapshot = snapshotComputer(); |
| enforceOwnerRights(snapshot, packageName, Binder.getCallingUid()); |
| mimeTypes = CollectionUtils.emptyIfNull(mimeTypes); |
| for (int i = 0; i < mimeTypes.size(); i++) { |
| if (mimeTypes.get(i).length() > 255) { |
| throw new IllegalArgumentException("MIME type length exceeds 255 characters"); |
| } |
| } |
| final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup); |
| if (existingMimeTypes == null) { |
| throw new IllegalArgumentException("Unknown MIME group " + mimeGroup |
| + " for package " + packageName); |
| } |
| if (existingMimeTypes.size() == mimeTypes.size() |
| && existingMimeTypes.containsAll(mimeTypes)) { |
| return; |
| } |
| if (mimeTypes.size() > 500) { |
| throw new IllegalStateException("Max limit on MIME types for MIME group " |
| + mimeGroup + " exceeded for package " + packageName); |
| } |
| |
| ArraySet<String> mimeTypesSet = new ArraySet<>(mimeTypes); |
| commitPackageStateMutation(null, packageName, packageStateWrite -> { |
| packageStateWrite.setMimeGroup(mimeGroup, mimeTypesSet); |
| }); |
| if (mComponentResolver.updateMimeGroup(snapshotComputer(), packageName, mimeGroup)) { |
| Binder.withCleanCallingIdentity(() -> |
| mPreferredActivityHelper.clearPackagePreferredActivities(packageName, |
| UserHandle.USER_ALL)); |
| } |
| |
| scheduleWriteSettings(); |
| } |
| |
| @Override |
| public void setPackageStoppedState(String packageName, boolean stopped, int userId) { |
| PackageManagerService.this |
| .setPackageStoppedState(snapshotComputer(), packageName, stopped, userId); |
| } |
| |
| @Override |
| public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended, |
| PersistableBundle appExtras, PersistableBundle launcherExtras, |
| SuspendDialogInfo dialogInfo, int flags, String suspendingPackage, |
| int suspendingUserId, int targetUserId) { |
| final int callingUid = Binder.getCallingUid(); |
| boolean quarantined = false; |
| if (Flags.quarantinedEnabled()) { |
| if ((flags & PackageManager.FLAG_SUSPEND_QUARANTINED) != 0) { |
| quarantined = true; |
| } else if (FeatureFlagUtils.isEnabled(mContext, |
| SETTINGS_TREAT_PAUSE_AS_QUARANTINE)) { |
| final String wellbeingPkg = mContext.getString(R.string.config_systemWellbeing); |
| quarantined = suspendingPackage.equals(wellbeingPkg); |
| } |
| } |
| final Computer snapshot = snapshotComputer(); |
| final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage); |
| enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid, |
| targetUserId, "setPackagesSuspendedAsUser"); |
| return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended, |
| appExtras, launcherExtras, dialogInfo, suspender, targetUserId, callingUid, |
| quarantined); |
| } |
| |
| @Override |
| public boolean setRequiredForSystemUser(String packageName, boolean requiredForSystemUser) { |
| PackageManagerServiceUtils.enforceSystemOrRoot( |
| "setRequiredForSystemUser can only be run by the system or root"); |
| |
| PackageStateMutator.Result result = commitPackageStateMutation(null, packageName, |
| packageState -> packageState.setRequiredForSystemUser(requiredForSystemUser)); |
| if (!result.isCommitted()) { |
| return false; |
| } |
| |
| scheduleWriteSettings(); |
| return true; |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.INSTALL_PACKAGES) |
| @Override |
| public void setUserMinAspectRatio(@NonNull String packageName, int userId, |
| @PackageManager.UserMinAspectRatio int aspectRatio) { |
| setUserMinAspectRatio_enforcePermission(); |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, |
| false /* requireFullPermission */, false /* checkShell */, |
| "setUserMinAspectRatio"); |
| enforceOwnerRights(snapshot, packageName, callingUid); |
| |
| final PackageStateInternal packageState = snapshot |
| .getPackageStateForInstalledAndFiltered(packageName, callingUid, userId); |
| if (packageState == null) { |
| return; |
| } |
| |
| if (packageState.getUserStateOrDefault(userId).getMinAspectRatio() == aspectRatio) { |
| return; |
| } |
| |
| commitPackageStateMutation(null, packageName, state -> |
| state.userState(userId).setMinAspectRatio(aspectRatio)); |
| } |
| |
| @Override |
| @SuppressWarnings("GuardedBy") |
| public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) { |
| Preconditions.checkArgumentNonnegative(version); |
| Preconditions.checkArgumentNonnegative(userId); |
| enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( |
| "setRuntimePermissionVersion"); |
| mSettings.setDefaultRuntimePermissionsVersion(version, userId); |
| } |
| |
| @Override |
| public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId, |
| int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| snapshot.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, |
| false /* checkShell */, "setSplashScreenTheme"); |
| enforceOwnerRights(snapshot, packageName, callingUid); |
| |
| PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, callingUid, userId); |
| if (packageState == null) { |
| return; |
| } |
| |
| commitPackageStateMutation(null, packageName, state -> |
| state.userState(userId).setSplashScreenTheme(themeId)); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.INSTALL_PACKAGES) |
| @Override |
| public void setUpdateAvailable(String packageName, boolean updateAvailable) { |
| setUpdateAvailable_enforcePermission(); |
| commitPackageStateMutation(null, packageName, state -> |
| state.setUpdateAvailable(updateAvailable)); |
| } |
| |
| @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) |
| @Override |
| public void unregisterMoveCallback(IPackageMoveObserver callback) { |
| unregisterMoveCallback_enforcePermission(); |
| mMoveCallbacks.unregister(callback); |
| } |
| |
| @Override |
| public void verifyPendingInstall(int verificationId, int verificationCode) |
| throws RemoteException { |
| // Negative ids correspond to testing verifiers and will be silently enforced in |
| // the handler thread. |
| if (verificationId >= 0) { |
| mContext.enforceCallingOrSelfPermission( |
| Manifest.permission.PACKAGE_VERIFICATION_AGENT, |
| "Only package verification agents can verify applications"); |
| } |
| final int callingUid = Binder.getCallingUid(); |
| |
| mHandler.post(() -> { |
| final int id = verificationId >= 0 ? verificationId : -verificationId; |
| final PackageVerificationState state = mPendingVerification.get(id); |
| if (state == null) { |
| return; |
| } |
| if (!state.checkRequiredVerifierUid(callingUid) |
| && !state.checkSufficientVerifierUid(callingUid)) { |
| // Only allow calls from verifiers. |
| return; |
| } |
| |
| final Message msg = mHandler.obtainMessage(PackageManagerService.PACKAGE_VERIFIED); |
| final PackageVerificationResponse response = new PackageVerificationResponse( |
| verificationCode, callingUid); |
| msg.arg1 = id; |
| msg.obj = response; |
| mHandler.sendMessage(msg); |
| }); |
| } |
| |
| @Override |
| public void registerPackageMonitorCallback(@NonNull IRemoteCallback callback, int userId) { |
| int uid = Binder.getCallingUid(); |
| int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), uid, |
| userId, true, true, "registerPackageMonitorCallback", |
| mContext.getPackageName()); |
| mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, targetUserId, |
| uid); |
| } |
| |
| @Override |
| public void unregisterPackageMonitorCallback(@NonNull IRemoteCallback callback) { |
| mPackageMonitorCallbackHelper.unregisterPackageMonitorCallback(callback); |
| } |
| |
| @Override |
| public void requestPackageChecksums(@NonNull String packageName, boolean includeSplits, |
| @Checksum.TypeMask int optional, @Checksum.TypeMask int required, |
| @Nullable List trustedInstallers, |
| @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) { |
| requestChecksumsInternal(snapshotComputer(), packageName, includeSplits, optional, |
| required, trustedInstallers, onChecksumsReadyListener, userId, |
| mInjector.getBackgroundExecutor(), mInjector.getBackgroundHandler()); |
| } |
| |
| @Override |
| public void notifyPackagesReplacedReceived(String[] packages) { |
| Computer computer = snapshotComputer(); |
| ArraySet<String> packagesToNotify = computer.getNotifyPackagesForReplacedReceived(packages); |
| for (int index = 0; index < packagesToNotify.size(); index++) { |
| notifyInstallObserver(packagesToNotify.valueAt(index), false /* killApp */); |
| } |
| } |
| |
| @Override |
| public ArchivedPackageParcel getArchivedPackage(@NonNull String packageName, int userId) { |
| return getArchivedPackageInternal(packageName, userId); |
| } |
| |
| @Override |
| public Bitmap getArchivedAppIcon(@NonNull String packageName, @NonNull UserHandle user) { |
| return mInstallerService.mPackageArchiver.getArchivedAppIcon(packageName, user); |
| } |
| |
| @Override |
| public boolean isAppArchivable(@NonNull String packageName, @NonNull UserHandle user) { |
| return mInstallerService.mPackageArchiver.isAppArchivable(packageName, user); |
| } |
| |
| /** |
| * Wait for the handler to finish handling all pending messages. |
| * @param timeoutMillis Maximum time in milliseconds to wait. |
| * @param forBackgroundHandler Whether to wait for the background handler instead. |
| * @return True if all the waiting messages in the handler has been handled. |
| * False if timeout. |
| */ |
| @Override |
| public boolean waitForHandler(long timeoutMillis, boolean forBackgroundHandler) { |
| final CountDownLatch latch = new CountDownLatch(1); |
| if (forBackgroundHandler) { |
| mBackgroundHandler.post(latch::countDown); |
| } else { |
| mHandler.post(latch::countDown); |
| } |
| final long endTimeMillis = System.currentTimeMillis() + timeoutMillis; |
| while (latch.getCount() > 0) { |
| try { |
| final long remainingTimeMillis = endTimeMillis - System.currentTimeMillis(); |
| if (remainingTimeMillis <= 0) { |
| return false; |
| } |
| return latch.await(remainingTimeMillis, TimeUnit.MILLISECONDS); |
| } catch (InterruptedException e) { |
| // ignore and retry |
| } |
| } |
| return true; |
| } |
| |
| @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) |
| && !(e instanceof ParcelableException)) { |
| Slog.wtf(TAG, "Package Manager Unexpected Exception", e); |
| } |
| throw e; |
| } |
| } |
| |
| @Override |
| public void onShellCommand(FileDescriptor in, FileDescriptor out, |
| FileDescriptor err, String[] args, ShellCallback callback, |
| ResultReceiver resultReceiver) { |
| (new PackageManagerShellCommand(this, mContext, |
| mDomainVerificationManager.getShell())) |
| .exec(this, in, out, err, args, callback, resultReceiver); |
| } |
| |
| @SuppressWarnings("resource") |
| @Override |
| protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; |
| final Computer snapshot = snapshotComputer(); |
| final KnownPackages knownPackages = new KnownPackages( |
| mDefaultAppProvider, |
| mRequiredInstallerPackage, |
| mRequiredUninstallerPackage, |
| mSetupWizardPackage, |
| mRequiredVerifierPackages, |
| mDefaultTextClassifierPackage, |
| mSystemTextClassifierPackageName, |
| mRequiredPermissionControllerPackage, |
| mConfiguratorPackage, |
| mIncidentReportApproverPackage, |
| mAmbientContextDetectionPackage, |
| mWearableSensingPackage, |
| mAppPredictionServicePackage, |
| COMPANION_PACKAGE_NAME, |
| mRetailDemoPackage, |
| mOverlayConfigSignaturePackage, |
| mRecentsPackage); |
| final ArrayMap<String, FeatureInfo> availableFeatures; |
| synchronized (mAvailableFeatures) { |
| availableFeatures = new ArrayMap<>(mAvailableFeatures); |
| } |
| final ArraySet<String> protectedBroadcasts; |
| synchronized (mProtectedBroadcasts) { |
| protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts); |
| } |
| new DumpHelper(mPermissionManager, mStorageEventHelper, |
| mDomainVerificationManager, mInstallerService, mRequiredVerifierPackages, |
| knownPackages, mChangedPackagesTracker, availableFeatures, protectedBroadcasts, |
| getPerUidReadTimeouts(snapshot), mSnapshotStatistics |
| ).doDump(snapshot, fd, pw, args); |
| } |
| } |
| |
| private class PackageManagerInternalImpl extends PackageManagerInternalBase { |
| |
| public PackageManagerInternalImpl() { |
| super(PackageManagerService.this); |
| } |
| |
| @NonNull |
| @Override |
| protected Context getContext() { |
| return mContext; |
| } |
| |
| @NonNull |
| @Override |
| protected PermissionManagerServiceInternal getPermissionManager() { |
| return mPermissionManager; |
| } |
| |
| @NonNull |
| @Override |
| protected AppDataHelper getAppDataHelper() { |
| return mAppDataHelper; |
| } |
| |
| @NonNull |
| @Override |
| protected PackageObserverHelper getPackageObserverHelper() { |
| return mPackageObserverHelper; |
| } |
| |
| @NonNull |
| @Override |
| protected ResolveIntentHelper getResolveIntentHelper() { |
| return mResolveIntentHelper; |
| } |
| |
| @NonNull |
| @Override |
| protected SuspendPackageHelper getSuspendPackageHelper() { |
| return mSuspendPackageHelper; |
| } |
| |
| @NonNull |
| @Override |
| protected DistractingPackageHelper getDistractingPackageHelper() { |
| return mDistractingPackageHelper; |
| } |
| |
| @NonNull |
| @Override |
| protected ProtectedPackages getProtectedPackages() { |
| return mProtectedPackages; |
| } |
| |
| @NonNull |
| @Override |
| protected UserNeedsBadgingCache getUserNeedsBadging() { |
| return mUserNeedsBadging; |
| } |
| |
| @NonNull |
| @Override |
| protected InstantAppRegistry getInstantAppRegistry() { |
| return mInstantAppRegistry; |
| } |
| |
| @NonNull |
| @Override |
| protected ApexManager getApexManager() { |
| return mApexManager; |
| } |
| |
| @NonNull |
| @Override |
| protected DexManager getDexManager() { |
| return mDexManager; |
| } |
| |
| @NonNull |
| @Override |
| public DynamicCodeLogger getDynamicCodeLogger() { |
| return mDynamicCodeLogger; |
| } |
| |
| @Override |
| public boolean isPlatformSigned(String packageName) { |
| PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName); |
| if (packageState == null) { |
| return false; |
| } |
| SigningDetails signingDetails = packageState.getSigningDetails(); |
| return signingDetails.hasAncestorOrSelf(mPlatformPackage.getSigningDetails()) |
| || mPlatformPackage.getSigningDetails().checkCapability(signingDetails, |
| SigningDetails.CertCapabilities.PERMISSION); |
| } |
| |
| @Override |
| public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) { |
| final Computer snapshot = snapshot(); |
| SigningDetails sd = snapshot.getSigningDetails(packageName); |
| if (sd == null) { |
| return false; |
| } |
| return sd.hasSha256Certificate(restoringFromSigHash, |
| SigningDetails.CertCapabilities.INSTALLED_DATA); |
| } |
| |
| @Override |
| public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) { |
| final Computer snapshot = snapshot(); |
| SigningDetails sd = snapshot.getSigningDetails(packageName); |
| if (sd == null) { |
| return false; |
| } |
| return sd.hasCertificate(restoringFromSig, |
| SigningDetails.CertCapabilities.INSTALLED_DATA); |
| } |
| |
| @Override |
| public boolean hasSignatureCapability(int serverUid, int clientUid, |
| @SigningDetails.CertCapabilities int capability) { |
| final Computer snapshot = snapshot(); |
| SigningDetails serverSigningDetails = snapshot.getSigningDetails(serverUid); |
| SigningDetails clientSigningDetails = snapshot.getSigningDetails(clientUid); |
| return serverSigningDetails.checkCapability(clientSigningDetails, capability) |
| || clientSigningDetails.hasAncestorOrSelf(serverSigningDetails); |
| } |
| |
| @Override |
| public PackageList getPackageList(@Nullable PackageListObserver observer) { |
| final ArrayList<String> list = new ArrayList<>(); |
| PackageManagerService.this.forEachPackageState(snapshot(), packageState -> { |
| AndroidPackage pkg = packageState.getPkg(); |
| if (pkg != null) { |
| list.add(pkg.getPackageName()); |
| } |
| }); |
| final PackageList packageList = new PackageList(list, observer); |
| if (observer != null) { |
| mPackageObserverHelper.addObserver(packageList); |
| } |
| return packageList; |
| } |
| |
| @Override |
| public @Nullable |
| String getDisabledSystemPackageName(@NonNull String packageName) { |
| PackageStateInternal disabledPkgSetting = snapshot().getDisabledSystemPackage( |
| packageName); |
| AndroidPackage disabledPkg = disabledPkgSetting == null |
| ? null : disabledPkgSetting.getPkg(); |
| return disabledPkg == null ? null : disabledPkg.getPackageName(); |
| } |
| |
| @Override |
| public boolean isResolveActivityComponent(ComponentInfo component) { |
| return mResolveActivity.packageName.equals(component.packageName) |
| && mResolveActivity.name.equals(component.name); |
| } |
| |
| @Override |
| public long getCeDataInode(String packageName, int userId) { |
| final PackageStateInternal packageState = |
| snapshot().getPackageStateInternal(packageName); |
| if (packageState == null) { |
| return 0; |
| } else { |
| return packageState.getUserStateOrDefault(userId).getCeDataInode(); |
| } |
| } |
| |
| @Override |
| public void removeAllNonSystemPackageSuspensions(int userId) { |
| final Computer computer = snapshotComputer(); |
| final String[] allPackages = computer.getAllAvailablePackageNames(); |
| mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages, |
| (suspender) -> !PLATFORM_PACKAGE_NAME.equals(suspender.packageName), |
| userId); |
| } |
| |
| @Override |
| public void flushPackageRestrictions(int userId) { |
| synchronized (mLock) { |
| PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId); |
| } |
| } |
| |
| @Override |
| public String[] setPackagesSuspendedByAdmin( |
| @UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) { |
| final int suspendingUserId = userId; |
| final UserPackage suspender = UserPackage.of( |
| suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME); |
| return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames, |
| suspended, null /* appExtras */, null /* launcherExtras */, |
| null /* dialogInfo */, suspender, userId, Process.SYSTEM_UID, |
| false /* quarantined */); |
| } |
| |
| @Override |
| public void setDeviceAndProfileOwnerPackages( |
| int deviceOwnerUserId, String deviceOwnerPackage, |
| SparseArray<String> profileOwnerPackages) { |
| mProtectedPackages.setDeviceAndProfileOwnerPackages( |
| deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages); |
| final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>(); |
| if (deviceOwnerPackage != null) { |
| usersWithPoOrDo.add(deviceOwnerUserId); |
| } |
| final int sz = profileOwnerPackages.size(); |
| for (int i = 0; i < sz; i++) { |
| if (profileOwnerPackages.valueAt(i) != null) { |
| removeAllNonSystemPackageSuspensions(profileOwnerPackages.keyAt(i)); |
| } |
| } |
| } |
| |
| @Override |
| public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) { |
| if (policy != null) { |
| mExternalSourcesPolicy = policy; |
| } |
| } |
| |
| @Override |
| public boolean isPackagePersistent(String packageName) { |
| final PackageStateInternal packageState = |
| snapshot().getPackageStateInternal(packageName); |
| if (packageState == null) { |
| return false; |
| } |
| |
| AndroidPackage pkg = packageState.getPkg(); |
| return pkg != null && packageState.isSystem() && pkg.isPersistent(); |
| } |
| |
| @Override |
| public List<PackageInfo> getOverlayPackages(int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final ArrayList<PackageInfo> overlayPackages = new ArrayList<>(); |
| final ArrayMap<String, ? extends PackageStateInternal> packageStates = |
| snapshot.getPackageStates(); |
| for (int index = 0; index < packageStates.size(); index++) { |
| final PackageStateInternal packageState = packageStates.valueAt(index); |
| final AndroidPackage pkg = packageState.getPkg(); |
| if (pkg != null && pkg.getOverlayTarget() != null) { |
| PackageInfo pkgInfo = snapshot.generatePackageInfo(packageState, 0, userId); |
| if (pkgInfo != null) { |
| overlayPackages.add(pkgInfo); |
| } |
| } |
| } |
| |
| return overlayPackages; |
| } |
| |
| @Override |
| public List<String> getTargetPackageNames(int userId) { |
| List<String> targetPackages = new ArrayList<>(); |
| PackageManagerService.this.forEachPackageState(snapshot(), packageState -> { |
| final AndroidPackage pkg = packageState.getPkg(); |
| if (pkg != null && !pkg.isResourceOverlay()) { |
| targetPackages.add(pkg.getPackageName()); |
| } |
| }); |
| return targetPackages; |
| } |
| |
| @Override |
| public void setEnabledOverlayPackages(int userId, |
| @NonNull ArrayMap<String, OverlayPaths> pendingChanges, |
| @NonNull Set<String> outUpdatedPackageNames, |
| @NonNull Set<String> outInvalidPackageNames) { |
| PackageManagerService.this.setEnabledOverlayPackages(userId, |
| pendingChanges, outUpdatedPackageNames, outInvalidPackageNames); |
| } |
| |
| @Override |
| public void addIsolatedUid(int isolatedUid, int ownerUid) { |
| synchronized (mLock) { |
| mIsolatedOwners.put(isolatedUid, ownerUid); |
| } |
| } |
| |
| @Override |
| public void removeIsolatedUid(int isolatedUid) { |
| synchronized (mLock) { |
| mIsolatedOwners.delete(isolatedUid); |
| } |
| } |
| |
| @Override |
| public void notifyPackageUse(String packageName, int reason) { |
| PackageManagerService.this.notifyPackageUseInternal(packageName, reason); |
| } |
| |
| @Nullable |
| @Override |
| public String removeLegacyDefaultBrowserPackageName(int userId) { |
| synchronized (mLock) { |
| return mSettings.removePendingDefaultBrowserLPw(userId); |
| } |
| } |
| |
| @Override |
| public void uninstallApex(String packageName, long versionCode, int userId, |
| IntentSender intentSender, int flags) { |
| final int callerUid = Binder.getCallingUid(); |
| if (!PackageManagerServiceUtils.isRootOrShell(callerUid)) { |
| throw new SecurityException("Not allowed to uninstall apexes"); |
| } |
| PackageInstallerService.PackageDeleteObserverAdapter adapter = |
| new PackageInstallerService.PackageDeleteObserverAdapter( |
| PackageManagerService.this.mContext, intentSender, packageName, |
| false, userId); |
| if ((flags & PackageManager.DELETE_ALL_USERS) == 0) { |
| adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, |
| "Can't uninstall an apex for a single user"); |
| return; |
| } |
| final ApexManager am = PackageManagerService.this.mApexManager; |
| PackageInfo activePackage = snapshot().getPackageInfo( |
| packageName, PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM); |
| if (activePackage == null) { |
| adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, |
| packageName + " is not an apex package"); |
| return; |
| } |
| if (versionCode != PackageManager.VERSION_CODE_HIGHEST |
| && activePackage.getLongVersionCode() != versionCode) { |
| adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, |
| "Active version " + activePackage.getLongVersionCode() |
| + " is not equal to " + versionCode + "]"); |
| return; |
| } |
| if (!am.uninstallApex(activePackage.applicationInfo.sourceDir)) { |
| adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, |
| "Failed to uninstall apex " + packageName); |
| } else { |
| adapter.onPackageDeleted(packageName, PackageManager.DELETE_SUCCEEDED, |
| null); |
| } |
| } |
| |
| /** @deprecated For legacy shell command only. */ |
| @Override |
| @Deprecated |
| public void legacyDumpProfiles(String packageName, boolean dumpClassesAndMethods) |
| throws LegacyDexoptDisabledException { |
| final Computer snapshot = snapshotComputer(); |
| AndroidPackage pkg = snapshot.getPackage(packageName); |
| if (pkg == null) { |
| throw new IllegalArgumentException("Unknown package: " + packageName); |
| } |
| |
| synchronized (mInstallLock) { |
| Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "dump profiles"); |
| mArtManagerService.dumpProfiles(pkg, dumpClassesAndMethods); |
| Trace.traceEnd(Trace.TRACE_TAG_DALVIK); |
| } |
| } |
| |
| /** @deprecated For legacy shell command only. */ |
| @Override |
| @Deprecated |
| public void legacyForceDexOpt(String packageName) throws LegacyDexoptDisabledException { |
| mDexOptHelper.forceDexOpt(snapshotComputer(), packageName); |
| } |
| |
| /** @deprecated For legacy shell command only. */ |
| @Override |
| @Deprecated |
| public void legacyReconcileSecondaryDexFiles(String packageName) |
| throws LegacyDexoptDisabledException { |
| final Computer snapshot = snapshotComputer(); |
| if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) { |
| return; |
| } else if (snapshot.isInstantAppInternal( |
| packageName, UserHandle.getCallingUserId(), Process.SYSTEM_UID)) { |
| return; |
| } |
| mDexManager.reconcileSecondaryDexFiles(packageName); |
| } |
| |
| @Override |
| @SuppressWarnings("GuardedBy") |
| public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) { |
| mSettings.updateRuntimePermissionsFingerprint(userId); |
| } |
| |
| @Override |
| public void migrateLegacyObbData() { |
| try { |
| mInstaller.migrateLegacyObbData(); |
| } catch (Exception e) { |
| Slog.wtf(TAG, e); |
| } |
| } |
| |
| @Override |
| public void writeSettings(boolean async) { |
| synchronized (mLock) { |
| if (async) { |
| scheduleWriteSettings(); |
| } else { |
| writeSettingsLPrTEMP(); |
| } |
| } |
| } |
| |
| @Override |
| public void writePermissionSettings(int[] userIds, boolean async) { |
| synchronized (mLock) { |
| for (int userId : userIds) { |
| mSettings.writePermissionStateForUserLPr(userId, !async); |
| } |
| } |
| } |
| |
| @Override |
| public LegacyPermissionSettings getLegacyPermissions() { |
| synchronized (mLock) { |
| return mSettings.mPermissions; |
| } |
| } |
| |
| /** |
| * Read legacy permission states for permissions migration to new permission subsystem. |
| */ |
| @Override |
| public RuntimePermissionsState getLegacyPermissionsState(int userId) { |
| synchronized (mLock) { |
| return mSettings.getLegacyPermissionsState(userId); |
| } |
| } |
| |
| @Override |
| public int getLegacyPermissionsVersion(@UserIdInt int userId) { |
| synchronized (mLock) { |
| return mSettings.getDefaultRuntimePermissionsVersion(userId); |
| } |
| } |
| |
| @Override |
| @SuppressWarnings("GuardedBy") |
| public boolean isPermissionUpgradeNeeded(int userId) { |
| return mSettings.isPermissionUpgradeNeeded(userId); |
| } |
| |
| @Override |
| public void setIntegrityVerificationResult(int verificationId, int verificationResult) { |
| final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE); |
| msg.arg1 = verificationId; |
| msg.obj = verificationResult; |
| mHandler.sendMessage(msg); |
| } |
| |
| @Override |
| public void setVisibilityLogging(String packageName, boolean enable) { |
| PackageManagerServiceUtils.enforceSystemOrRootOrShell( |
| "Only the system or shell can set visibility logging."); |
| final PackageStateInternal packageState = |
| snapshot().getPackageStateInternal(packageName); |
| if (packageState == null) { |
| throw new IllegalStateException("No package found for " + packageName); |
| } |
| mAppsFilter.getFeatureConfig().enableLogging(packageState.getAppId(), enable); |
| } |
| |
| @Override |
| public void clearBlockUninstallForUser(@UserIdInt int userId) { |
| synchronized (mLock) { |
| mSettings.clearBlockUninstallLPw(userId); |
| mSettings.writePackageRestrictionsLPr(userId); |
| } |
| } |
| |
| @Override |
| public boolean registerInstalledLoadingProgressCallback(String packageName, |
| PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, Binder.getCallingUid(), userId); |
| if (ps == null) { |
| return false; |
| } |
| if (!ps.isLoading()) { |
| Slog.w(TAG, |
| "Failed registering loading progress callback. Package is fully loaded."); |
| return false; |
| } |
| if (mIncrementalManager == null) { |
| Slog.w(TAG, |
| "Failed registering loading progress callback. Incremental is not enabled"); |
| return false; |
| } |
| return mIncrementalManager.registerLoadingProgressCallback(ps.getPathString(), |
| (IPackageLoadingProgressCallback) callback.getBinder()); |
| } |
| |
| @Override |
| public IncrementalStatesInfo getIncrementalStatesInfo( |
| @NonNull String packageName, int filterCallingUid, int userId) { |
| final Computer snapshot = snapshotComputer(); |
| final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered( |
| packageName, filterCallingUid, userId); |
| if (ps == null) { |
| return null; |
| } |
| return new IncrementalStatesInfo(ps.isLoading(), ps.getLoadingProgress(), |
| ps.getLoadingCompletedTime()); |
| } |
| |
| @Override |
| public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) { |
| return isSameApp(packageName, /*flags=*/0, callingUid, userId); |
| } |
| |
| @Override |
| public boolean isSameApp(@Nullable String packageName, |
| @PackageManager.PackageInfoFlagsBits long flags, int callingUid, int userId) { |
| if (packageName == null) { |
| return false; |
| } |
| |
| if (Process.isSdkSandboxUid(callingUid)) { |
| return packageName.equals(mRequiredSdkSandboxPackage); |
| } |
| Computer snapshot = snapshot(); |
| int uid = snapshot.getPackageUid(packageName, flags, userId); |
| return UserHandle.isSameApp(uid, callingUid); |
| } |
| |
| @Override |
| public void onPackageProcessKilledForUninstall(String packageName) { |
| mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName, |
| true /* killApp */)); |
| } |
| |
| @Override |
| public int[] getDistractingPackageRestrictionsAsUser( |
| @NonNull String[] packageNames, int userId) { |
| final int callingUid = Binder.getCallingUid(); |
| final Computer snapshot = snapshotComputer(); |
| Objects.requireNonNull(packageNames, "packageNames cannot be null"); |
| return mDistractingPackageHelper.getDistractingPackageRestrictionsAsUser(snapshot, |
| packageNames, userId, callingUid); |
| } |
| |
| @Override |
| public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) { |
| return mInstallerService.getHistoricalSessions(userId); |
| } |
| |
| @Override |
| public PackageArchiver getPackageArchiver() { |
| return mInstallerService.mPackageArchiver; |
| } |
| |
| @Override |
| public void sendPackageRestartedBroadcast(@NonNull String packageName, |
| int uid, @Intent.Flags int flags) { |
| final int userId = UserHandle.getUserId(uid); |
| final int [] userIds = resolveUserIds(userId); |
| final SparseArray<int[]> broadcastAllowList = |
| snapshotComputer().getVisibilityAllowLists(packageName, userIds); |
| final Bundle extras = new Bundle(); |
| extras.putInt(Intent.EXTRA_UID, uid); |
| extras.putInt(Intent.EXTRA_USER_HANDLE, userId); |
| if (android.content.pm.Flags.stayStopped()) { |
| extras.putLong(Intent.EXTRA_TIME, SystemClock.elapsedRealtime()); |
| // Sent async using the PM handler, to maintain ordering with PACKAGE_UNSTOPPED |
| mHandler.post(() -> { |
| mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED, |
| packageName, extras, |
| flags, null, null, |
| userIds, null, broadcastAllowList, null, |
| null); |
| }); |
| } else { |
| mBroadcastHelper.sendPackageBroadcast(Intent.ACTION_PACKAGE_RESTARTED, |
| packageName, extras, |
| flags, null, null, |
| userIds, null, broadcastAllowList, null, |
| null); |
| } |
| mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_RESTARTED, |
| packageName, extras, userIds, null /* instantUserIds */, |
| broadcastAllowList, mHandler); |
| } |
| |
| @Override |
| public void sendPackageDataClearedBroadcast(@NonNull String packageName, |
| int uid, int userId, boolean isRestore, boolean isInstantApp) { |
| int[] visibilityAllowList = |
| snapshotComputer().getVisibilityAllowList(packageName, userId); |
| final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, |
| Uri.fromParts("package", packageName, null /* fragment */)); |
| intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND |
| | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); |
| intent.putExtra(Intent.EXTRA_UID, uid); |
| intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); |
| if (isRestore) { |
| intent.putExtra(Intent.EXTRA_IS_RESTORE, true); |
| } |
| if (isInstantApp) { |
| intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); |
| } |
| mBroadcastHelper.sendPackageBroadcastWithIntent(intent, userId, isInstantApp, |
| 0 /* flags */, visibilityAllowList, null /* finishedReceiver */, |
| null /* filterExtrasForReceiver */, null /* bOptions */); |
| mPackageMonitorCallbackHelper.notifyPackageMonitorWithIntent(intent, userId, |
| visibilityAllowList, mHandler); |
| } |
| } |
| |
| private void setEnabledOverlayPackages(@UserIdInt int userId, |
| @NonNull ArrayMap<String, OverlayPaths> pendingChanges, |
| @NonNull Set<String> outUpdatedPackageNames, |
| @NonNull Set<String> outInvalidPackageNames) { |
| final ArrayMap<String, ArrayMap<String, ArraySet<String>>> |
| targetPkgToLibNameToModifiedDependents = new ArrayMap<>(); |
| final int numberOfPendingChanges = pendingChanges.size(); |
| |
| synchronized (mOverlayPathsLock) { |
| Computer computer = snapshotComputer(); |
| for (int i = 0; i < numberOfPendingChanges; i++) { |
| final String targetPackageName = pendingChanges.keyAt(i); |
| final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); |
| final PackageStateInternal packageState = computer.getPackageStateInternal( |
| targetPackageName); |
| final AndroidPackage targetPkg = |
| packageState == null ? null : packageState.getPkg(); |
| if (targetPackageName == null || targetPkg == null) { |
| Slog.e(TAG, "failed to find package " + targetPackageName); |
| outInvalidPackageNames.add(targetPackageName); |
| continue; |
| } |
| |
| if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(), |
| newOverlayPaths)) { |
| continue; |
| } |
| |
| if (targetPkg.getLibraryNames() != null) { |
| // Set the overlay paths for dependencies of the shared library. |
| List<String> libraryNames = targetPkg.getLibraryNames(); |
| for (int j = 0; j < libraryNames.size(); j++) { |
| final String libName = libraryNames.get(j); |
| ArraySet<String> modifiedDependents = null; |
| |
| final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName, |
| SharedLibraryInfo.VERSION_UNDEFINED); |
| if (info == null) { |
| continue; |
| } |
| var usingSharedLibraryPair = computer.getPackagesUsingSharedLibrary(info, 0, |
| Process.SYSTEM_UID, userId); |
| final List<VersionedPackage> dependents = usingSharedLibraryPair.first; |
| if (dependents == null) { |
| continue; |
| } |
| for (int k = 0; k < dependents.size(); k++) { |
| final VersionedPackage dependent = dependents.get(k); |
| final PackageStateInternal dependentState = |
| computer.getPackageStateInternal(dependent.getPackageName()); |
| if (dependentState == null) { |
| continue; |
| } |
| if (canSetOverlayPaths(dependentState.getUserStateOrDefault(userId) |
| .getSharedLibraryOverlayPaths() |
| .get(libName), newOverlayPaths)) { |
| String dependentPackageName = dependent.getPackageName(); |
| modifiedDependents = ArrayUtils.add(modifiedDependents, |
| dependentPackageName); |
| outUpdatedPackageNames.add(dependentPackageName); |
| } |
| } |
| |
| if (modifiedDependents != null) { |
| ArrayMap<String, ArraySet<String>> libNameToModifiedDependents = |
| targetPkgToLibNameToModifiedDependents.get( |
| targetPackageName); |
| if (libNameToModifiedDependents == null) { |
| libNameToModifiedDependents = new ArrayMap<>(); |
| targetPkgToLibNameToModifiedDependents.put(targetPackageName, |
| libNameToModifiedDependents); |
| } |
| libNameToModifiedDependents.put(libName, modifiedDependents); |
| } |
| } |
| } |
| |
| if (canSetOverlayPaths(packageState.getUserStateOrDefault(userId).getOverlayPaths(), |
| newOverlayPaths)) { |
| outUpdatedPackageNames.add(targetPackageName); |
| } |
| } |
| |
| commitPackageStateMutation(null, mutator -> { |
| for (int i = 0; i < numberOfPendingChanges; i++) { |
| final String targetPackageName = pendingChanges.keyAt(i); |
| final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); |
| |
| if (!outUpdatedPackageNames.contains(targetPackageName)) { |
| continue; |
| } |
| |
| mutator.forPackage(targetPackageName) |
| .userState(userId) |
| .setOverlayPaths(newOverlayPaths); |
| |
| final ArrayMap<String, ArraySet<String>> libNameToModifiedDependents = |
| targetPkgToLibNameToModifiedDependents.get( |
| targetPackageName); |
| if (libNameToModifiedDependents == null) { |
| continue; |
| } |
| |
| for (int mapIndex = 0; mapIndex < libNameToModifiedDependents.size(); |
| mapIndex++) { |
| String libName = libNameToModifiedDependents.keyAt(mapIndex); |
| ArraySet<String> modifiedDependents = |
| libNameToModifiedDependents.valueAt(mapIndex); |
| for (int setIndex = 0; setIndex < modifiedDependents.size(); setIndex++) { |
| mutator.forPackage(modifiedDependents.valueAt(setIndex)) |
| .userState(userId) |
| .setOverlayPathsForLibrary(libName, newOverlayPaths); |
| } |
| } |
| } |
| }); |
| } |
| |
| if (userId == UserHandle.USER_SYSTEM) { |
| // Keep the overlays in the system application info (and anything special cased as well) |
| // up to date to make sure system ui is themed correctly. |
| for (int i = 0; i < numberOfPendingChanges; i++) { |
| final String targetPackageName = pendingChanges.keyAt(i); |
| final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); |
| maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths); |
| } |
| } |
| |
| invalidatePackageInfoCache(); |
| } |
| |
| private boolean canSetOverlayPaths(OverlayPaths origPaths, OverlayPaths newPaths) { |
| if (Objects.equals(origPaths, newPaths)) { |
| return false; |
| } |
| if ((origPaths == null && newPaths.isEmpty()) |
| || (newPaths == null && origPaths.isEmpty())) { |
| return false; |
| } |
| return true; |
| } |
| |
| private void maybeUpdateSystemOverlays(String targetPackageName, OverlayPaths newOverlayPaths) { |
| if (!mResolverReplaced) { |
| if (targetPackageName.equals("android")) { |
| if (newOverlayPaths == null) { |
| mPlatformPackageOverlayPaths = null; |
| mPlatformPackageOverlayResourceDirs = null; |
| } else { |
| mPlatformPackageOverlayPaths = newOverlayPaths.getOverlayPaths().toArray( |
| new String[0]); |
| mPlatformPackageOverlayResourceDirs = newOverlayPaths.getResourceDirs().toArray( |
| new String[0]); |
| } |
| applyUpdatedSystemOverlayPaths(); |
| } |
| } else { |
| if (targetPackageName.equals(mResolveActivity.applicationInfo.packageName)) { |
| if (newOverlayPaths == null) { |
| mReplacedResolverPackageOverlayPaths = null; |
| mReplacedResolverPackageOverlayResourceDirs = null; |
| } else { |
| mReplacedResolverPackageOverlayPaths = |
| newOverlayPaths.getOverlayPaths().toArray(new String[0]); |
| mReplacedResolverPackageOverlayResourceDirs = |
| newOverlayPaths.getResourceDirs().toArray(new String[0]); |
| } |
| applyUpdatedSystemOverlayPaths(); |
| } |
| } |
| } |
| |
| private void applyUpdatedSystemOverlayPaths() { |
| if (mAndroidApplication == null) { |
| Slog.i(TAG, "Skipped the AndroidApplication overlay paths update - no app yet"); |
| } else { |
| mAndroidApplication.overlayPaths = mPlatformPackageOverlayPaths; |
| mAndroidApplication.resourceDirs = mPlatformPackageOverlayResourceDirs; |
| } |
| if (mResolverReplaced) { |
| mResolveActivity.applicationInfo.overlayPaths = mReplacedResolverPackageOverlayPaths; |
| mResolveActivity.applicationInfo.resourceDirs = |
| mReplacedResolverPackageOverlayResourceDirs; |
| } |
| } |
| |
| private void enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( |
| @NonNull String message) { |
| if (mContext.checkCallingOrSelfPermission( |
| Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) |
| != PackageManager.PERMISSION_GRANTED |
| && mContext.checkCallingOrSelfPermission( |
| Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS) |
| != PackageManager.PERMISSION_GRANTED) { |
| throw new SecurityException(message + " requires " |
| + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " or " |
| + Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS); |
| } |
| } |
| |
| // TODO: Remove |
| @Deprecated |
| @Nullable |
| @GuardedBy("mLock") |
| PackageSetting getPackageSettingForMutation(String packageName) { |
| return mSettings.getPackageLPr(packageName); |
| } |
| |
| // TODO: Remove |
| @Deprecated |
| @Nullable |
| @GuardedBy("mLock") |
| PackageSetting getDisabledPackageSettingForMutation(String packageName) { |
| return mSettings.getDisabledSystemPkgLPr(packageName); |
| } |
| |
| @Deprecated |
| void forEachPackageSetting(Consumer<PackageSetting> actionLocked) { |
| synchronized (mLock) { |
| int size = mSettings.getPackagesLocked().size(); |
| for (int index = 0; index < size; index++) { |
| actionLocked.accept(mSettings.getPackagesLocked().valueAt(index)); |
| } |
| } |
| } |
| |
| void forEachPackageState(@NonNull Computer snapshot, Consumer<PackageStateInternal> consumer) { |
| forEachPackageState(snapshot.getPackageStates(), consumer); |
| } |
| |
| void forEachPackage(@NonNull Computer snapshot, Consumer<AndroidPackage> consumer) { |
| final ArrayMap<String, ? extends PackageStateInternal> packageStates = |
| snapshot.getPackageStates(); |
| int size = packageStates.size(); |
| for (int index = 0; index < size; index++) { |
| PackageStateInternal packageState = packageStates.valueAt(index); |
| if (packageState.getPkg() != null) { |
| consumer.accept(packageState.getPkg()); |
| } |
| } |
| } |
| |
| void forEachPackageInternal(@NonNull Computer snapshot, |
| @NonNull Consumer<AndroidPackageInternal> consumer) { |
| final ArrayMap<String, ? extends PackageStateInternal> packageStates = |
| snapshot.getPackageStates(); |
| int size = packageStates.size(); |
| for (int index = 0; index < size; index++) { |
| PackageStateInternal packageState = packageStates.valueAt(index); |
| if (packageState.getPkg() != null) { |
| consumer.accept(packageState.getPkg()); |
| } |
| } |
| } |
| |
| private void forEachPackageState( |
| @NonNull ArrayMap<String, ? extends PackageStateInternal> packageStates, |
| @NonNull Consumer<PackageStateInternal> consumer) { |
| int size = packageStates.size(); |
| for (int index = 0; index < size; index++) { |
| PackageStateInternal packageState = packageStates.valueAt(index); |
| consumer.accept(packageState); |
| } |
| } |
| |
| void forEachInstalledPackage(@NonNull Computer snapshot, @NonNull Consumer<AndroidPackage> action, |
| @UserIdInt int userId) { |
| Consumer<PackageStateInternal> actionWrapped = packageState -> { |
| if (packageState.getPkg() != null |
| && packageState.getUserStateOrDefault(userId).isInstalled()) { |
| action.accept(packageState.getPkg()); |
| } |
| }; |
| forEachPackageState(snapshot.getPackageStates(), actionWrapped); |
| } |
| |
| boolean isHistoricalPackageUsageAvailable() { |
| return mPackageUsage.isHistoricalPackageUsageAvailable(); |
| } |
| |
| public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) { |
| return getOrCreateCompilerPackageStats(pkg.getPackageName()); |
| } |
| |
| public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) { |
| return mCompilerStats.getOrCreatePackageStats(pkgName); |
| } |
| |
| void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId, |
| Intent intent, @AppIdInt int recipientAppId, int visibleUid, boolean direct, |
| boolean retainOnUpdate) { |
| final AndroidPackage visiblePackage = snapshot.getPackage(visibleUid); |
| final int recipientUid = UserHandle.getUid(userId, recipientAppId); |
| if (visiblePackage == null || snapshot.getPackage(recipientUid) == null) { |
| return; |
| } |
| |
| final boolean instantApp = snapshot.isInstantAppInternal( |
| visiblePackage.getPackageName(), userId, visibleUid); |
| final boolean accessGranted; |
| if (instantApp) { |
| if (!direct) { |
| // if the interaction that lead to this granting access to an instant app |
| // was indirect (i.e.: URI permission grant), do not actually execute the |
| // grant. |
| return; |
| } |
| accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent, |
| recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/); |
| } else { |
| accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid, |
| retainOnUpdate); |
| } |
| |
| if (accessGranted) { |
| ApplicationPackageManager.invalidateGetPackagesForUidCache(); |
| } |
| } |
| |
| boolean canHaveOatDir(@NonNull Computer snapshot, String packageName) { |
| final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState == null || packageState.getPkg() == null) { |
| return false; |
| } |
| return AndroidPackageUtils.canHaveOatDir(packageState, packageState.getPkg()); |
| } |
| |
| long deleteOatArtifactsOfPackage(@NonNull Computer snapshot, String packageName) { |
| PackageManagerServiceUtils.enforceSystemOrRootOrShell( |
| "Only the system or shell can delete oat artifacts"); |
| |
| if (DexOptHelper.useArtService()) { |
| // TODO(chiuwinson): Retrieve filtered snapshot from Computer instance instead. |
| try (PackageManagerLocal.FilteredSnapshot filteredSnapshot = |
| PackageManagerServiceUtils.getPackageManagerLocal() |
| .withFilteredSnapshot()) { |
| try { |
| DeleteResult res = DexOptHelper.getArtManagerLocal().deleteDexoptArtifacts( |
| filteredSnapshot, packageName); |
| return res.getFreedBytes(); |
| } catch (IllegalArgumentException e) { |
| Log.e(TAG, e.toString()); |
| return -1; |
| } catch (IllegalStateException e) { |
| Slog.wtfStack(TAG, e.toString()); |
| return -1; |
| } |
| } |
| } else { |
| PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState == null || packageState.getPkg() == null) { |
| return -1; // error code of deleteOptimizedFiles |
| } |
| try { |
| return mDexManager.deleteOptimizedFiles( |
| ArtUtils.createArtPackageInfo(packageState.getPkg(), packageState)); |
| } catch (LegacyDexoptDisabledException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| List<String> getMimeGroupInternal(@NonNull Computer snapshot, String packageName, |
| String mimeGroup) { |
| final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); |
| if (packageState == null) { |
| return Collections.emptyList(); |
| } |
| |
| final Map<String, Set<String>> mimeGroups = packageState.getMimeGroups(); |
| Set<String> mimeTypes = mimeGroups != null ? mimeGroups.get(mimeGroup) : null; |
| if (mimeTypes == null) { |
| throw new IllegalArgumentException("Unknown MIME group " + mimeGroup |
| + " for package " + packageName); |
| } |
| return new ArrayList<>(mimeTypes); |
| } |
| |
| /** |
| * Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's |
| * writeLegacyPermissionsTEMP() beforehand. |
| * |
| * TODO: In the meantime, can this be moved to a schedule call? |
| * TODO(b/182523293): This should be removed once we finish migration of permission storage. |
| */ |
| @SuppressWarnings("GuardedBy") |
| void writeSettingsLPrTEMP(boolean sync) { |
| snapshotComputer(false); |
| mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions); |
| mSettings.writeLPr(mLiveComputer, sync); |
| } |
| |
| // Default async version. |
| void writeSettingsLPrTEMP() { |
| writeSettingsLPrTEMP(/*sync=*/false); |
| } |
| |
| @Override |
| public void verifyHoldLockToken(IBinder token) { |
| if (!Build.IS_DEBUGGABLE) { |
| throw new SecurityException("holdLock requires a debuggable build"); |
| } |
| |
| if (token == null) { |
| throw new SecurityException("null holdLockToken"); |
| } |
| |
| if (token.queryLocalInterface("holdLock:" + Binder.getCallingUid()) != this) { |
| throw new SecurityException("Invalid holdLock() token"); |
| } |
| } |
| |
| static String getDefaultTimeouts() { |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, |
| PROPERTY_INCFS_DEFAULT_TIMEOUTS, ""); |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| static String getKnownDigestersList() { |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, |
| PROPERTY_KNOWN_DIGESTERS_LIST, ""); |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| static boolean isPreapprovalRequestAvailable() { |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| if (!Resources.getSystem().getBoolean( |
| com.android.internal.R.bool.config_isPreApprovalRequestAvailable)) { |
| return false; |
| } |
| return DeviceConfig.getBoolean(NAMESPACE_PACKAGE_MANAGER_SERVICE, |
| PROPERTY_IS_PRE_APPROVAL_REQUEST_AVAILABLE, true /* defaultValue */); |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| static boolean isUpdateOwnershipEnforcementAvailable() { |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| return DeviceConfig.getBoolean(NAMESPACE_PACKAGE_MANAGER_SERVICE, |
| PROPERTY_IS_UPDATE_OWNERSHIP_ENFORCEMENT_AVAILABLE, true /* defaultValue */); |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| } |
| |
| /** |
| * Returns the array containing per-uid timeout configuration. |
| * This is derived from DeviceConfig flags. |
| */ |
| public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts(@NonNull Computer snapshot) { |
| PerUidReadTimeouts[] result = mPerUidReadTimeoutsCache; |
| if (result == null) { |
| result = parsePerUidReadTimeouts(snapshot); |
| mPerUidReadTimeoutsCache = result; |
| } |
| return result; |
| } |
| |
| private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts(@NonNull Computer snapshot) { |
| final String defaultTimeouts = getDefaultTimeouts(); |
| final String knownDigestersList = getKnownDigestersList(); |
| final List<PerPackageReadTimeouts> perPackageReadTimeouts = |
| PerPackageReadTimeouts.parseDigestersList(defaultTimeouts, knownDigestersList); |
| |
| if (perPackageReadTimeouts.size() == 0) { |
| return EMPTY_PER_UID_READ_TIMEOUTS_ARRAY; |
| } |
| |
| final int[] allUsers = mInjector.getUserManagerService().getUserIds(); |
| final List<PerUidReadTimeouts> result = new ArrayList<>(perPackageReadTimeouts.size()); |
| for (int i = 0, size = perPackageReadTimeouts.size(); i < size; ++i) { |
| final PerPackageReadTimeouts perPackage = perPackageReadTimeouts.get(i); |
| final PackageStateInternal ps = |
| snapshot.getPackageStateInternal(perPackage.packageName); |
| if (ps == null) { |
| if (DEBUG_PER_UID_READ_TIMEOUTS) { |
| Slog.i(TAG, "PerUidReadTimeouts: package not found = " |
| + perPackage.packageName); |
| } |
| continue; |
| } |
| if (ps.getAppId() < Process.FIRST_APPLICATION_UID) { |
| if (DEBUG_PER_UID_READ_TIMEOUTS) { |
| Slog.i(TAG, "PerUidReadTimeouts: package is system, appId=" |
| + ps.getAppId()); |
| } |
| continue; |
| } |
| |
| final AndroidPackage pkg = ps.getPkg(); |
| if (pkg.getLongVersionCode() < perPackage.versionCodes.minVersionCode |
| || pkg.getLongVersionCode() > perPackage.versionCodes.maxVersionCode) { |
| if (DEBUG_PER_UID_READ_TIMEOUTS) { |
| Slog.i(TAG, "PerUidReadTimeouts: version code is not in range = " |
| + perPackage.packageName + ":" + pkg.getLongVersionCode()); |
| } |
| continue; |
| } |
| if (perPackage.sha256certificate != null |
| && !pkg.getSigningDetails().hasSha256Certificate( |
| perPackage.sha256certificate)) { |
| if (DEBUG_PER_UID_READ_TIMEOUTS) { |
| Slog.i(TAG, "PerUidReadTimeouts: invalid certificate = " |
| + perPackage.packageName + ":" + pkg.getLongVersionCode()); |
| } |
| continue; |
| } |
| for (int userId : allUsers) { |
| if (!ps.getUserStateOrDefault(userId).isInstalled()) { |
| continue; |
| } |
| final int uid = UserHandle.getUid(userId, ps.getAppId()); |
| final PerUidReadTimeouts perUid = new PerUidReadTimeouts(); |
| perUid.uid = uid; |
| perUid.minTimeUs = perPackage.timeouts.minTimeUs; |
| perUid.minPendingTimeUs = perPackage.timeouts.minPendingTimeUs; |
| perUid.maxPendingTimeUs = perPackage.timeouts.maxPendingTimeUs; |
| result.add(perUid); |
| } |
| } |
| return result.toArray(new PerUidReadTimeouts[result.size()]); |
| } |
| |
| void setKeepUninstalledPackagesInternal(@NonNull Computer snapshot, List<String> packageList) { |
| Preconditions.checkNotNull(packageList); |
| synchronized (mKeepUninstalledPackages) { |
| List<String> toRemove = new ArrayList<>(mKeepUninstalledPackages); |
| toRemove.removeAll(packageList); // Do not remove anything still in the list |
| |
| mKeepUninstalledPackages.clear(); |
| mKeepUninstalledPackages.addAll(packageList); |
| |
| for (int i = 0; i < toRemove.size(); i++) { |
| deletePackageIfUnused(snapshot, toRemove.get(i)); |
| } |
| } |
| } |
| |
| boolean shouldKeepUninstalledPackageLPr(String packageName) { |
| synchronized (mKeepUninstalledPackages) { |
| return mKeepUninstalledPackages.contains(packageName); |
| } |
| } |
| |
| boolean getSafeMode() { |
| return mSafeMode; |
| } |
| |
| ComponentName getResolveComponentName() { |
| return mResolveComponentName; |
| } |
| |
| DefaultAppProvider getDefaultAppProvider() { |
| return mDefaultAppProvider; |
| } |
| |
| File getCacheDir() { |
| return mCacheDir; |
| } |
| |
| PackageProperty getPackageProperty() { |
| return mPackageProperty; |
| } |
| |
| WatchedArrayMap<ComponentName, ParsedInstrumentation> getInstrumentation() { |
| return mInstrumentation; |
| } |
| |
| int getSdkVersion() { |
| return mSdkVersion; |
| } |
| |
| void addAllPackageProperties(@NonNull AndroidPackage pkg) { |
| mPackageProperty.addAllProperties(pkg); |
| } |
| |
| void addInstrumentation(ComponentName name, ParsedInstrumentation instrumentation) { |
| mInstrumentation.put(name, instrumentation); |
| } |
| |
| String[] getKnownPackageNamesInternal(@NonNull Computer snapshot, int knownPackage, |
| int userId) { |
| return new KnownPackages( |
| mDefaultAppProvider, |
| mRequiredInstallerPackage, |
| mRequiredUninstallerPackage, |
| mSetupWizardPackage, |
| mRequiredVerifierPackages, |
| mDefaultTextClassifierPackage, |
| mSystemTextClassifierPackageName, |
| mRequiredPermissionControllerPackage, |
| mConfiguratorPackage, |
| mIncidentReportApproverPackage, |
| mAmbientContextDetectionPackage, |
| mWearableSensingPackage, |
| mAppPredictionServicePackage, |
| COMPANION_PACKAGE_NAME, |
| mRetailDemoPackage, |
| mOverlayConfigSignaturePackage, |
| mRecentsPackage) |
| .getKnownPackageNames(snapshot, knownPackage, userId); |
| } |
| |
| String getActiveLauncherPackageName(int userId) { |
| return mDefaultAppProvider.getDefaultHome(userId); |
| } |
| |
| boolean setActiveLauncherPackage(@NonNull String packageName, @UserIdInt int userId, |
| @NonNull Consumer<Boolean> callback) { |
| return mDefaultAppProvider.setDefaultHome(packageName, userId, mContext.getMainExecutor(), |
| callback); |
| } |
| |
| @Nullable |
| String getDefaultBrowser(@UserIdInt int userId) { |
| return mDefaultAppProvider.getDefaultBrowser(userId); |
| } |
| |
| void setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) { |
| mDefaultAppProvider.setDefaultBrowser(packageName, userId); |
| } |
| |
| PackageUsage getPackageUsage() { |
| return mPackageUsage; |
| } |
| |
| String getModuleMetadataPackageName() { |
| return mModuleInfoProvider.getPackageName(); |
| } |
| |
| File getAppInstallDir() { |
| return mAppInstallDir; |
| } |
| |
| boolean isExpectingBetter(String packageName) { |
| return mInitAppsHelper.isExpectingBetter(packageName); |
| } |
| |
| int getDefParseFlags() { |
| return mDefParseFlags; |
| } |
| |
| void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) { |
| synchronized (mLock) { |
| mResolverReplaced = true; |
| |
| // The instance created in PackageManagerService is special cased to be non-user |
| // specific, so initialize all the needed fields here. |
| ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0, |
| PackageUserStateInternal.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting); |
| |
| // Set up information for custom user intent resolution activity. |
| mResolveActivity.applicationInfo = appInfo; |
| mResolveActivity.name = mCustomResolverComponentName.getClassName(); |
| mResolveActivity.packageName = pkg.getPackageName(); |
| mResolveActivity.processName = pkg.getProcessName(); |
| mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; |
| mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
| | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS |
| | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; |
| mResolveActivity.theme = 0; |
| mResolveActivity.exported = true; |
| mResolveActivity.enabled = true; |
| mResolveInfo.activityInfo = mResolveActivity; |
| mResolveInfo.priority = 0; |
| mResolveInfo.preferredOrder = 0; |
| mResolveInfo.match = 0; |
| mResolveComponentName = mCustomResolverComponentName; |
| PackageManagerService.onChanged(); |
| Slog.i(TAG, "Replacing default ResolverActivity with custom activity: " |
| + mResolveComponentName); |
| } |
| } |
| |
| void setPlatformPackage(AndroidPackage pkg, PackageSetting pkgSetting) { |
| synchronized (mLock) { |
| // Set up information for our fall-back user intent resolution activity. |
| mPlatformPackage = pkg; |
| |
| // The instance stored in PackageManagerService is special cased to be non-user |
| // specific, so initialize all the needed fields here. |
| mAndroidApplication = PackageInfoUtils.generateApplicationInfo(pkg, 0, |
| PackageUserStateInternal.DEFAULT, UserHandle.USER_SYSTEM, pkgSetting); |
| |
| if (!mResolverReplaced) { |
| mResolveActivity.applicationInfo = mAndroidApplication; |
| mResolveActivity.name = ResolverActivity.class.getName(); |
| mResolveActivity.packageName = mAndroidApplication.packageName; |
| mResolveActivity.processName = "system:ui"; |
| mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; |
| mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER; |
| mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
| | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY |
| | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; |
| mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert; |
| mResolveActivity.exported = true; |
| mResolveActivity.enabled = true; |
| mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; |
| mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE |
| | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE |
| | ActivityInfo.CONFIG_SCREEN_LAYOUT |
| | ActivityInfo.CONFIG_ORIENTATION |
| | ActivityInfo.CONFIG_KEYBOARD |
| | ActivityInfo.CONFIG_KEYBOARD_HIDDEN; |
| mResolveInfo.activityInfo = mResolveActivity; |
| mResolveInfo.priority = 0; |
| mResolveInfo.preferredOrder = 0; |
| mResolveInfo.match = 0; |
| mResolveComponentName = new ComponentName( |
| mAndroidApplication.packageName, mResolveActivity.name); |
| } |
| PackageManagerService.onChanged(); |
| } |
| applyUpdatedSystemOverlayPaths(); |
| } |
| |
| ApplicationInfo getCoreAndroidApplication() { |
| return mAndroidApplication; |
| } |
| |
| boolean isSystemReady() { |
| return mSystemReady; |
| } |
| |
| AndroidPackage getPlatformPackage() { |
| return mPlatformPackage; |
| } |
| |
| boolean isPreNMR1Upgrade() { |
| return mIsPreNMR1Upgrade; |
| } |
| |
| boolean isOverlayMutable(String packageName) { |
| return mOverlayConfig.isMutable(packageName); |
| } |
| |
| @ScanFlags int getSystemPackageScanFlags(File codePath) { |
| List<ScanPartition> dirsToScanAsSystem = |
| mInitAppsHelper.getDirsToScanAsSystem(); |
| @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM; |
| for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) { |
| ScanPartition partition = dirsToScanAsSystem.get(i); |
| if (partition.containsFile(codePath)) { |
| scanFlags |= partition.scanFlag; |
| if (partition.containsPrivApp(codePath)) { |
| scanFlags |= SCAN_AS_PRIVILEGED; |
| } |
| break; |
| } |
| } |
| return scanFlags; |
| } |
| |
| Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile, |
| int systemScanFlags, int systemParseFlags) { |
| List<ScanPartition> dirsToScanAsSystem = |
| mInitAppsHelper.getDirsToScanAsSystem(); |
| @ParsingPackageUtils.ParseFlags int reparseFlags = 0; |
| @PackageManagerService.ScanFlags int rescanFlags = 0; |
| for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) { |
| final ScanPartition partition = dirsToScanAsSystem.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; |
| } |
| } |
| return new Pair<>(rescanFlags, reparseFlags); |
| } |
| |
| |
| /** |
| * @see PackageManagerInternal#recordInitialState() |
| */ |
| @NonNull |
| public PackageStateMutator.InitialState recordInitialState() { |
| return mPackageStateMutator.initialState(mChangedPackagesTracker.getSequenceNumber()); |
| } |
| |
| /** |
| * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState, |
| * Consumer) |
| */ |
| @NonNull |
| public PackageStateMutator.Result commitPackageStateMutation( |
| @Nullable PackageStateMutator.InitialState initialState, |
| @NonNull Consumer<PackageStateMutator> consumer) { |
| synchronized (mPackageStateWriteLock) { |
| final PackageStateMutator.Result result = mPackageStateMutator.generateResult( |
| initialState, mChangedPackagesTracker.getSequenceNumber()); |
| if (result != PackageStateMutator.Result.SUCCESS) { |
| return result; |
| } |
| |
| consumer.accept(mPackageStateMutator); |
| mPackageStateMutator.onFinished(); |
| } |
| |
| return PackageStateMutator.Result.SUCCESS; |
| } |
| |
| /** |
| * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState, |
| * Consumer) |
| */ |
| @NonNull |
| public PackageStateMutator.Result commitPackageStateMutation( |
| @Nullable PackageStateMutator.InitialState initialState, @NonNull String packageName, |
| @NonNull Consumer<PackageStateWrite> consumer) { |
| PackageStateMutator.Result result = null; |
| if (Thread.holdsLock(mPackageStateWriteLock)) { |
| // If the thread is already holding the lock, this is likely a retry based on a prior |
| // failure, and re-calculating whether a state change occurred can be skipped. |
| result = PackageStateMutator.Result.SUCCESS; |
| } |
| synchronized (mPackageStateWriteLock) { |
| if (result == null) { |
| // If the thread wasn't previously holding, this is a first-try commit and so a |
| // state change may have happened. |
| result = mPackageStateMutator.generateResult( |
| initialState, mChangedPackagesTracker.getSequenceNumber()); |
| } |
| if (result != PackageStateMutator.Result.SUCCESS) { |
| return result; |
| } |
| |
| PackageStateWrite state = mPackageStateMutator.forPackage(packageName); |
| if (state == null) { |
| return PackageStateMutator.Result.SPECIFIC_PACKAGE_NULL; |
| } else { |
| consumer.accept(state); |
| } |
| |
| state.onChanged(); |
| } |
| |
| return PackageStateMutator.Result.SUCCESS; |
| } |
| |
| void notifyInstantAppPackageInstalled(String packageName, int[] newUsers) { |
| mInstantAppRegistry.onPackageInstalled(snapshotComputer(), packageName, newUsers); |
| } |
| |
| void addInstallerPackageName(InstallSource installSource) { |
| synchronized (mLock) { |
| mSettings.addInstallerPackageNames(installSource); |
| } |
| } |
| |
| public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName, |
| @NonNull List<String> subDirNames, int userId, int appId, int previousAppId, |
| @NonNull String seInfo, int flags) throws IOException { |
| synchronized (mInstallLock) { |
| ReconcileSdkDataArgs args = mInstaller.buildReconcileSdkDataArgs(volumeUuid, |
| packageName, subDirNames, userId, appId, seInfo, |
| flags); |
| args.previousAppId = previousAppId; |
| try { |
| mInstaller.reconcileSdkData(args); |
| } catch (InstallerException e) { |
| throw new IOException(e.getMessage()); |
| } |
| } |
| } |
| |
| void removeCodePath(@Nullable File codePath) { |
| mRemovePackageHelper.removeCodePath(codePath); |
| } |
| |
| void cleanUpResources(@Nullable File codeFile, @Nullable String[] instructionSets) { |
| mRemovePackageHelper.cleanUpResources(codeFile, instructionSets); |
| } |
| |
| void cleanUpForMoveInstall(String volumeUuid, String packageName, String fromCodePath) { |
| mRemovePackageHelper.cleanUpForMoveInstall(volumeUuid, packageName, fromCodePath); |
| } |
| |
| void sendPendingBroadcasts() { |
| mInstallPackageHelper.sendPendingBroadcasts(); |
| } |
| |
| void handlePackagePostInstall(@NonNull InstallRequest request, boolean launchedForRestore) { |
| mInstallPackageHelper.handlePackagePostInstall(request, launchedForRestore); |
| } |
| |
| Pair<Integer, IntentSender> installExistingPackageAsUser( |
| @Nullable String packageName, |
| @UserIdInt int userId, @PackageManager.InstallFlags int installFlags, |
| @PackageManager.InstallReason int installReason, |
| @Nullable List<String> allowlistedRestrictedPermissions, |
| @Nullable IntentSender intentSender) { |
| return mInstallPackageHelper.installExistingPackageAsUser(packageName, userId, installFlags, |
| installReason, allowlistedRestrictedPermissions, intentSender); |
| } |
| AndroidPackage initPackageTracedLI(File scanFile, final int parseFlags, int scanFlags) |
| throws PackageManagerException { |
| return mInstallPackageHelper.initPackageTracedLI(scanFile, parseFlags, scanFlags); |
| } |
| |
| void restoreDisabledSystemPackageLIF(@NonNull DeletePackageAction action, |
| @NonNull int[] allUserHandles, |
| boolean writeSettings) throws SystemDeleteException { |
| mInstallPackageHelper.restoreDisabledSystemPackageLIF( |
| action, allUserHandles, writeSettings); |
| } |
| boolean enableCompressedPackage(@NonNull AndroidPackage stubPkg, |
| @NonNull PackageSetting stubPs) { |
| return mInstallPackageHelper.enableCompressedPackage(stubPkg, stubPs); |
| } |
| |
| void installPackagesTraced(List<InstallRequest> requests) { |
| mInstallPackageHelper.installPackagesTraced(requests); |
| } |
| |
| void restoreAndPostInstall(InstallRequest request) { |
| mInstallPackageHelper.restoreAndPostInstall(request); |
| } |
| |
| Pair<Integer, String> verifyReplacingVersionCode(@NonNull PackageInfoLite pkgLite, |
| long requiredInstalledVersionCode, |
| int installFlags) { |
| return mInstallPackageHelper.verifyReplacingVersionCode( |
| pkgLite, requiredInstalledVersionCode, installFlags); |
| } |
| |
| int getUidForVerifier(VerifierInfo verifierInfo) { |
| return mInstallPackageHelper.getUidForVerifier(verifierInfo); |
| } |
| |
| int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags, |
| boolean removedBySystem) { |
| return mDeletePackageHelper.deletePackageX(packageName, |
| PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM, |
| PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/); |
| } |
| } |