All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.pm.PackageManagerService Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2006 The Android Open Source Project
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import static android.Manifest.permission.DELETE_PACKAGES;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_VERSION_CODE;
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_APEX;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageManager.TYPE_ACTIVITY;
import static android.content.pm.PackageManager.TYPE_PROVIDER;
import static android.content.pm.PackageManager.TYPE_RECEIVER;
import static android.content.pm.PackageManager.TYPE_SERVICE;
import static android.content.pm.PackageManager.TYPE_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;

import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;

import android.Manifest;
import android.annotation.AppIdInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.PermissionChecker;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AuxiliaryResolveInfo;
import android.content.pm.ChangedPackages;
import android.content.pm.Checksum;
import android.content.pm.ComponentInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureInfo;
import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ComponentType;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.ModuleInfoFlags;
import android.content.pm.PackageManager.Property;
import android.content.pm.PackageManager.PropertyLocation;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.PackagePartitions;
import android.content.pm.PackagePartitions.SystemPartition;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingPackageUtils.ParseFlags;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SELinux;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
import android.os.incremental.PerUidReadTimeouts;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.permission.PermissionManager;
import android.provider.ContactsContract;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
import android.stats.storage.StorageEnums;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.LogPrinter;
import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.PackageUtils;
import android.util.Pair;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimingsTraceLog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.apk.ApkSignatureVerifier;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
import android.view.Display;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.AttributeCache;
import com.android.internal.security.VerityUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.DomainVerificationUtils;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedLongSparseArray;
import com.android.server.utils.WatchedSparseBooleanArray;
import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
import com.android.server.wm.ActivityTaskManagerInternal;

import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;

import libcore.io.IoUtils;
import libcore.util.EmptyArray;
import libcore.util.HexEncoding;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * Keep track of all those APKs everywhere.
 * 

* Internally there are three important locks: *

    *
  • {@link #mLock} is used to guard all in-memory parsed package details * and other related state. It is a fine-grained lock that should only be held * momentarily, as it's one of the most contended locks in the system. *
  • {@link #mInstallLock} is used to guard all {@code installd} access, whose * operations typically involve heavy lifting of application data on disk. Since * {@code installd} is single-threaded, and it's operations can often be slow, * this lock should never be acquired while already holding {@link #mLock}. * Conversely, it's safe to acquire {@link #mLock} momentarily while already * holding {@link #mInstallLock}. *
  • {@link #mSnapshotLock} is used to guard access to two snapshot fields: the snapshot * itself and the snapshot invalidation flag. This lock should never be acquired while * already holding {@link #mLock}. Conversely, it's safe to acquire {@link #mLock} * momentarily while already holding {@link #mSnapshotLock}. *
* Many internal methods rely on the caller to hold the appropriate locks, and * this contract is expressed through method name suffixes: *
    *
  • fooLI(): the caller must hold {@link #mInstallLock} *
  • fooLIF(): the caller must hold {@link #mInstallLock} and the package * being modified must be frozen *
  • fooLPr(): the caller must hold {@link #mLock} for reading *
  • fooLPw(): the caller must hold {@link #mLock} for writing *
* {@link #mSnapshotLock} is taken in exactly one place - {@code snapshotComputer()}. It * should not be taken anywhere else or used for any other purpose. *

* Because this class is very central to the platform's security; please run all * CTS and unit tests whenever making modifications: * *

 * $ runtest -c android.content.pm.PackageManagerTests frameworks-core
 * $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
 * 
*/ public class PackageManagerService extends IPackageManager.Stub implements PackageSender, TestUtilityService { static final String TAG = "PackageManager"; public static final boolean DEBUG_SETTINGS = false; static final boolean DEBUG_PREFERRED = false; static final boolean DEBUG_UPGRADE = false; static final boolean DEBUG_DOMAIN_VERIFICATION = false; private static final boolean DEBUG_BACKUP = false; public static final boolean DEBUG_INSTALL = false; public static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; public static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_VERIFY = false; public static final boolean DEBUG_PERMISSIONS = false; private static final boolean DEBUG_SHARED_LIBRARIES = false; public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE; public static final boolean TRACE_SNAPSHOTS = false; private static final boolean DEBUG_PER_UID_READ_TIMEOUTS = false; // Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService // and PackageDexOptimizer. All these classes have their own flag to allow switching a single // user, but by default initialize to this. public static final boolean DEBUG_DEXOPT = false; static final boolean DEBUG_ABI_SELECTION = false; private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE; private static final boolean DEBUG_APP_DATA = false; /** REMOVE. According to Svet, this was only used to reset permissions during development. */ static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false; private static final boolean HIDE_EPHEMERAL_APIS = false; private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts"; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID; private static final int SHELL_UID = Process.SHELL_UID; private static final int SE_UID = Process.SE_UID; private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID; private static final int UWB_UID = Process.UWB_UID; static final int SCAN_NO_DEX = 1 << 0; static final int SCAN_UPDATE_SIGNATURE = 1 << 1; static final int SCAN_NEW_INSTALL = 1 << 2; static final int SCAN_UPDATE_TIME = 1 << 3; static final int SCAN_BOOTING = 1 << 4; static final int SCAN_REQUIRE_KNOWN = 1 << 7; static final int SCAN_MOVE = 1 << 8; static final int SCAN_INITIAL = 1 << 9; static final int SCAN_DONT_KILL_APP = 1 << 10; static final int SCAN_IGNORE_FROZEN = 1 << 11; static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12; static final int SCAN_AS_INSTANT_APP = 1 << 13; static final int SCAN_AS_FULL_APP = 1 << 14; static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15; static final int SCAN_AS_SYSTEM = 1 << 16; static final int SCAN_AS_PRIVILEGED = 1 << 17; static final int SCAN_AS_OEM = 1 << 18; static final int SCAN_AS_VENDOR = 1 << 19; static final int SCAN_AS_PRODUCT = 1 << 20; static final int SCAN_AS_SYSTEM_EXT = 1 << 21; static final int SCAN_AS_ODM = 1 << 22; static final int SCAN_AS_APK_IN_APEX = 1 << 23; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, SCAN_UPDATE_SIGNATURE, SCAN_NEW_INSTALL, SCAN_UPDATE_TIME, SCAN_BOOTING, SCAN_REQUIRE_KNOWN, SCAN_MOVE, SCAN_INITIAL, SCAN_DONT_KILL_APP, SCAN_IGNORE_FROZEN, SCAN_FIRST_BOOT_OR_UPGRADE, SCAN_AS_INSTANT_APP, SCAN_AS_FULL_APP, SCAN_AS_VIRTUAL_PRELOAD, }) @Retention(RetentionPolicy.SOURCE) public @interface ScanFlags {} /** * Used as the result code of the {@link #getPackageStartability}. */ @IntDef(value = { PACKAGE_STARTABILITY_OK, PACKAGE_STARTABILITY_NOT_FOUND, PACKAGE_STARTABILITY_NOT_SYSTEM, PACKAGE_STARTABILITY_FROZEN, PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED, }) @Retention(RetentionPolicy.SOURCE) public @interface PackageStartability {} /** * Used as the result code of the {@link #getPackageStartability} to indicate * the given package is allowed to start. */ static final int PACKAGE_STARTABILITY_OK = 0; /** * Used as the result code of the {@link #getPackageStartability} to indicate * the given package is not allowed to start because it's not found * (could be due to that package is invisible to the given user). */ static final int PACKAGE_STARTABILITY_NOT_FOUND = 1; /** * Used as the result code of the {@link #getPackageStartability} to indicate * the given package is not allowed to start because it's not a system app * and the system is running in safe mode. */ static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2; /** * Used as the result code of the {@link #getPackageStartability} to indicate * the given package is not allowed to start because it's currently frozen. */ static final int PACKAGE_STARTABILITY_FROZEN = 3; /** * Used as the result code of the {@link #getPackageStartability} to indicate * the given package is not allowed to start because it doesn't support * direct boot. */ static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4; private static final String STATIC_SHARED_LIB_DELIMITER = "_"; /** Extension of the compressed packages */ public final static String COMPRESSED_EXTENSION = ".gz"; /** Suffix of stub packages on the system partition */ public final static String STUB_SUFFIX = "-Stub"; private static final int[] EMPTY_INT_ARRAY = new int[0]; /** * Timeout (in milliseconds) after which the watchdog should declare that * our handler thread is wedged. The usual default for such things is one * minute but we sometimes do very lengthy I/O operations on this thread, * such as installing multi-gigabyte applications, so ours needs to be longer. */ static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes /** * Wall-clock timeout (in milliseconds) after which we *require* that an fstrim * be run on this device. We use the value in the Settings.Global.MANDATORY_FSTRIM_INTERVAL * settings entry if available, otherwise we use the hardcoded default. If it's been * more than this long since the last fstrim, we force one during the boot sequence. * * This backstops other fstrim scheduling: if the device is alive at midnight+idle, * one gets run at the next available charging+idle time. This final mandatory * no-fstrim check kicks in only of the other scheduling criteria is never met. */ private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS; /** * Whether verification is enabled by default. */ private static final boolean DEFAULT_VERIFY_ENABLE = true; /** * Whether integrity verification is enabled by default. */ private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true; /** * The default maximum time to wait for the verification agent to return in * milliseconds. */ private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; /** * The default maximum time to wait for the integrity verification to return in * milliseconds. */ private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000; /** * Timeout duration in milliseconds for enabling package rollback. If we fail to enable * rollback within that period, the install will proceed without rollback enabled. * *

If flag value is negative, the default value will be assigned. * * Flag type: {@code long} * Namespace: NAMESPACE_ROLLBACK */ private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout"; /** * The default duration to wait for rollback to be enabled in * milliseconds. */ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000; /** * Default IncFs timeouts. Maximum values in IncFs is 1hr. * *

If flag value is empty, the default value will be assigned. * * Flag type: {@code String} * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE */ private static final String PROPERTY_INCFS_DEFAULT_TIMEOUTS = "incfs_default_timeouts"; /** * Known digesters with optional timeouts. * * Flag type: {@code String} * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE */ private static final String PROPERTY_KNOWN_DIGESTERS_LIST = "known_digesters_list"; /** * The default response for package verification timeout. * * This can be either PackageManager.VERIFICATION_ALLOW or * PackageManager.VERIFICATION_REJECT. */ private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW; /** * Adding an installer package name to a package that does not have one set requires the * INSTALL_PACKAGES permission. * * If the caller targets R, this will throw a SecurityException. Otherwise the request will * fail silently. In both cases, and regardless of whether this change is enabled, the * installer package will remain unchanged. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE = 150857253; /** * Apps targeting Android S and above need to declare dependencies to the public native * shared libraries that are defined by the device maker using {@code uses-native-library} tag * in its {@code AndroidManifest.xml}. * * If any of the dependencies cannot be satisfied, i.e. one of the dependency doesn't exist, * the package manager rejects to install the app. The dependency can be specified as optional * using {@code android:required} attribute in the tag, in which case failing to satisfy the * dependency doesn't stop the installation. *

Once installed, an app is provided with only the native shared libraries that are * specified in the app manifest. {@code dlopen}ing a native shared library that doesn't appear * in the app manifest will fail even if it actually exists on the device. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088; public static final String PLATFORM_PACKAGE_NAME = "android"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; private static final String PACKAGE_SCHEME = "package"; private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager"; // Compilation reasons. public static final int REASON_FIRST_BOOT = 0; public static final int REASON_BOOT_AFTER_OTA = 1; public static final int REASON_POST_BOOT = 2; public static final int REASON_INSTALL = 3; public static final int REASON_INSTALL_FAST = 4; public static final int REASON_INSTALL_BULK = 5; public static final int REASON_INSTALL_BULK_SECONDARY = 6; public static final int REASON_INSTALL_BULK_DOWNGRADED = 7; public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 8; public static final int REASON_BACKGROUND_DEXOPT = 9; public static final int REASON_AB_OTA = 10; public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11; public static final int REASON_CMDLINE = 12; public static final int REASON_SHARED = 13; public static final int REASON_LAST = REASON_SHARED; /** * The initial enabled state of the cache before other checks are done. */ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true; /** * Whether to skip all other checks and force the cache to be enabled. * * Setting this to true will cause the cache to be named "debug" to avoid eviction from * build fingerprint changes. */ private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false; /** * Permissions required in order to receive instant application lifecycle broadcasts. */ private static final String[] INSTANT_APP_BROADCAST_PERMISSION = new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS }; private static final String RANDOM_DIR_PREFIX = "~~"; final Handler mHandler; private final ProcessLoggingHandler mProcessLoggingHandler; private final boolean mEnableFreeCacheV2; final int mSdkVersion; final Context mContext; final boolean mFactoryTest; final boolean mOnlyCore; final DisplayMetrics mMetrics; final int mDefParseFlags; final String[] mSeparateProcesses; final boolean mIsUpgrade; final boolean mIsPreNUpgrade; final boolean mIsPreNMR1Upgrade; final boolean mIsPreQUpgrade; @GuardedBy("mLock") private boolean mDexOptDialogShown; // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages // LOCK HELD. Can be called with mInstallLock held. @GuardedBy("mInstallLock") final Installer mInstaller; /** Directory where installed applications are stored */ private final File mAppInstallDir; /** Directory where installed application's 32-bit native libraries are copied. */ @VisibleForTesting final File mAppLib32InstallDir; private static File getAppLib32InstallDir() { return new File(Environment.getDataDirectory(), "app-lib"); } // ---------------------------------------------------------------- // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the suffix "LI". final Object mInstallLock; // ---------------------------------------------------------------- // Lock for global state used when modifying package state or settings. // Methods that must be called with this lock held have // the suffix "Locked". Some methods may use the legacy suffix "LP" final PackageManagerTracedLock mLock; // Keys are String (package name), values are Package. @Watched @GuardedBy("mLock") final WatchedArrayMap mPackages = new WatchedArrayMap<>(); private final SnapshotCache> mPackagesSnapshot = new SnapshotCache.Auto(mPackages, mPackages, "PackageManagerService.mPackages"); // Keys are isolated uids and values are the uid of the application // that created the isolated process. @Watched @GuardedBy("mLock") final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray(); private final SnapshotCache mIsolatedOwnersSnapshot = new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners, "PackageManagerService.mIsolatedOwners"); /** * Tracks new system packages [received in an OTA] that we expect to * find updated user-installed versions. Keys are package name, values * are package location. */ final private ArrayMap mExpectingBetter = new ArrayMap<>(); /** * Tracks existing packages prior to receiving an OTA. Keys are package name. * Only non-null during an OTA, and even then it is nulled again once systemReady(). */ private @Nullable ArraySet mExistingPackages = null; /** * List of code paths that need to be released when the system becomes ready. *

* NOTE: We have to delay releasing cblocks for no other reason than we cannot * retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. When * we no longer need to read that setting, cblock release can occur in the * constructor. * * @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL * @see #systemReady() */ private @Nullable List mReleaseOnSystemReady; /** * Whether or not system app permissions should be promoted from install to runtime. */ boolean mPromoteSystemApps; private final PackageManagerInternal mPmInternal; private final TestUtilityService mTestUtilityService; @Watched @GuardedBy("mLock") final Settings mSettings; /** * Set of package names that are currently "frozen", which means active * surgery is being done on the code/data for that package. The platform * will refuse to launch frozen packages to avoid race conditions. * * @see PackageFreezer */ @GuardedBy("mLock") final ArraySet mFrozenPackages = new ArraySet<>(); final ProtectedPackages mProtectedPackages; @GuardedBy("mLoadedVolumes") final ArraySet mLoadedVolumes = new ArraySet<>(); boolean mFirstBoot; private final boolean mIsEngBuild; private final boolean mIsUserDebugBuild; private final String mIncrementalVersion; PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; @GuardedBy("mAvailableFeatures") final ArrayMap mAvailableFeatures; @Watched private final InstantAppRegistry mInstantAppRegistry; @GuardedBy("mLock") int mChangedPackagesSequenceNumber; /** * List of changed [installed, removed or updated] packages. * mapping from user id -> sequence number -> package name */ @GuardedBy("mLock") final SparseArray> mChangedPackages = new SparseArray<>(); /** * The sequence number of the last change to a package. * mapping from user id -> package name -> sequence number */ @GuardedBy("mLock") final SparseArray> mChangedPackagesSequenceNumbers = new SparseArray<>(); @GuardedBy("mLock") final private ArraySet mPackageListObservers = new ArraySet<>(); @GuardedBy("mLock") private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray(); private final ModuleInfoProvider mModuleInfoProvider; private final ApexManager mApexManager; private final Injector mInjector; private final SystemWrapper mSystemWrapper; /** * The list of all system partitions that may contain packages in ascending order of * specificity (the more generic, the earlier in the list a partition appears). */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static final List SYSTEM_PARTITIONS = Collections.unmodifiableList( PackagePartitions.getOrderedPartitions(ScanPartition::new)); private final List mDirsToScanAsSystem; private final OverlayConfig mOverlayConfig; @GuardedBy("itself") final private ArrayList mPackageChangeObservers = new ArrayList<>(); // Cached parsed flag value. Invalidated on each flag change. private PerUidReadTimeouts[] mPerUidReadTimeoutsCache; private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {}; /** * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors. * * NOTE: All getters should return the same instance for every call. */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Injector { @VisibleForTesting(visibility = Visibility.PRIVATE) interface Producer { /** Produce an instance of type {@link T} */ T produce(Injector injector, PackageManagerService packageManager); } interface ProducerWithArgument { T produce(Injector injector, PackageManagerService packageManager, R argument); } interface ServiceProducer { T produce(Class c); } @VisibleForTesting(visibility = Visibility.PRIVATE) static class Singleton { private final Producer mProducer; private volatile T mInstance = null; Singleton(Producer producer) { this.mProducer = producer; } T get(Injector injector, PackageManagerService packageManagerService) { if (mInstance == null) { mInstance = mProducer.produce(injector, packageManagerService); } return mInstance; } } private PackageManagerService mPackageManager; private final PackageAbiHelper mAbiHelper; private final Context mContext; private final PackageManagerTracedLock mLock; private final Installer mInstaller; private final Object mInstallLock; private final Handler mBackgroundHandler; private final Executor mBackgroundExecutor; private final List mSystemPartitions; // ----- producers ----- private final Singleton mComponentResolverProducer; private final Singleton mPermissionManagerServiceProducer; private final Singleton mUserManagerProducer; private final Singleton mSettingsProducer; private final Singleton mAppsFilterProducer; private final Singleton mPlatformCompatProducer; private final Singleton mSystemConfigProducer; private final Singleton mPackageDexOptimizerProducer; private final Singleton mDexManagerProducer; private final Singleton mArtManagerServiceProducer; private final Singleton mApexManagerProducer; private final Singleton mViewCompilerProducer; private final Singleton mIncrementalManagerProducer; private final Singleton mDefaultAppProviderProducer; private final Singleton mDisplayMetricsProducer; private final Producer mScanningCachingPackageParserProducer; private final Producer mScanningPackageParserProducer; private final Producer mPreparingPackageParserProducer; private final Singleton mPackageInstallerServiceProducer; private final ProducerWithArgument mInstantAppResolverConnectionProducer; private final Singleton mLegacyPermissionManagerInternalProducer; private final SystemWrapper mSystemWrapper; private final ServiceProducer mGetLocalServiceProducer; private final ServiceProducer mGetSystemServiceProducer; private final Singleton mModuleInfoProviderProducer; private final Singleton mDomainVerificationManagerInternalProducer; private final Singleton mHandlerProducer; Injector(Context context, PackageManagerTracedLock lock, Installer installer, Object installLock, PackageAbiHelper abiHelper, Handler backgroundHandler, List systemPartitions, Producer componentResolverProducer, Producer permissionManagerServiceProducer, Producer userManagerProducer, Producer settingsProducer, Producer appsFilterProducer, Producer platformCompatProducer, Producer systemConfigProducer, Producer packageDexOptimizerProducer, Producer dexManagerProducer, Producer artManagerServiceProducer, Producer apexManagerProducer, Producer viewCompilerProducer, Producer incrementalManagerProducer, Producer defaultAppProviderProducer, Producer displayMetricsProducer, Producer scanningCachingPackageParserProducer, Producer scanningPackageParserProducer, Producer preparingPackageParserProducer, Producer packageInstallerServiceProducer, ProducerWithArgument instantAppResolverConnectionProducer, Producer moduleInfoProviderProducer, Producer legacyPermissionManagerInternalProducer, Producer domainVerificationManagerInternalProducer, Producer handlerProducer, SystemWrapper systemWrapper, ServiceProducer getLocalServiceProducer, ServiceProducer getSystemServiceProducer) { mContext = context; mLock = lock; mInstaller = installer; mAbiHelper = abiHelper; mInstallLock = installLock; mBackgroundHandler = backgroundHandler; mBackgroundExecutor = new HandlerExecutor(backgroundHandler); mSystemPartitions = systemPartitions; mComponentResolverProducer = new Singleton<>(componentResolverProducer); mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer); mUserManagerProducer = new Singleton<>(userManagerProducer); mSettingsProducer = new Singleton<>(settingsProducer); mAppsFilterProducer = new Singleton<>(appsFilterProducer); mPlatformCompatProducer = new Singleton<>(platformCompatProducer); mSystemConfigProducer = new Singleton<>(systemConfigProducer); mPackageDexOptimizerProducer = new Singleton<>(packageDexOptimizerProducer); mDexManagerProducer = new Singleton<>(dexManagerProducer); mArtManagerServiceProducer = new Singleton<>(artManagerServiceProducer); mApexManagerProducer = new Singleton<>(apexManagerProducer); mViewCompilerProducer = new Singleton<>(viewCompilerProducer); mIncrementalManagerProducer = new Singleton<>(incrementalManagerProducer); mDefaultAppProviderProducer = new Singleton<>(defaultAppProviderProducer); mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer); mScanningCachingPackageParserProducer = scanningCachingPackageParserProducer; mScanningPackageParserProducer = scanningPackageParserProducer; mPreparingPackageParserProducer = preparingPackageParserProducer; mPackageInstallerServiceProducer = new Singleton<>(packageInstallerServiceProducer); mInstantAppResolverConnectionProducer = instantAppResolverConnectionProducer; mModuleInfoProviderProducer = new Singleton<>(moduleInfoProviderProducer); mLegacyPermissionManagerInternalProducer = new Singleton<>( legacyPermissionManagerInternalProducer); mSystemWrapper = systemWrapper; mGetLocalServiceProducer = getLocalServiceProducer; mGetSystemServiceProducer = getSystemServiceProducer; mDomainVerificationManagerInternalProducer = new Singleton<>(domainVerificationManagerInternalProducer); mHandlerProducer = new Singleton<>(handlerProducer); } /** * Bootstraps this injector with the {@link PackageManagerService instance to which it * belongs. */ public void bootstrap(PackageManagerService pm) { this.mPackageManager = pm; } public UserManagerInternal getUserManagerInternal() { return getUserManagerService().getInternalForInjectorOnly(); } public PackageAbiHelper getAbiHelper() { return mAbiHelper; } public Object getInstallLock() { return mInstallLock; } public List getSystemPartitions() { return mSystemPartitions; } public UserManagerService getUserManagerService() { return mUserManagerProducer.get(this, mPackageManager); } public PackageManagerTracedLock getLock() { return mLock; } public Installer getInstaller() { return mInstaller; } public ComponentResolver getComponentResolver() { return mComponentResolverProducer.get(this, mPackageManager); } public PermissionManagerServiceInternal getPermissionManagerServiceInternal() { return mPermissionManagerServiceProducer.get(this, mPackageManager); } public Context getContext() { return mContext; } public Settings getSettings() { return mSettingsProducer.get(this, mPackageManager); } public AppsFilter getAppsFilter() { return mAppsFilterProducer.get(this, mPackageManager); } public PlatformCompat getCompatibility() { return mPlatformCompatProducer.get(this, mPackageManager); } public SystemConfig getSystemConfig() { return mSystemConfigProducer.get(this, mPackageManager); } public PackageDexOptimizer getPackageDexOptimizer() { return mPackageDexOptimizerProducer.get(this, mPackageManager); } public DexManager getDexManager() { return mDexManagerProducer.get(this, mPackageManager); } public ArtManagerService getArtManagerService() { return mArtManagerServiceProducer.get(this, mPackageManager); } public ApexManager getApexManager() { return mApexManagerProducer.get(this, mPackageManager); } public ViewCompiler getViewCompiler() { return mViewCompilerProducer.get(this, mPackageManager); } public Handler getBackgroundHandler() { return mBackgroundHandler; } public Executor getBackgroundExecutor() { return mBackgroundExecutor; } public DisplayMetrics getDisplayMetrics() { return mDisplayMetricsProducer.get(this, mPackageManager); } public T getLocalService(Class c) { return mGetLocalServiceProducer.produce(c); } public T getSystemService(Class c) { return mGetSystemServiceProducer.produce(c); } public SystemWrapper getSystemWrapper() { return mSystemWrapper; } public IncrementalManager getIncrementalManager() { return mIncrementalManagerProducer.get(this, mPackageManager); } public DefaultAppProvider getDefaultAppProvider() { return mDefaultAppProviderProducer.get(this, mPackageManager); } public PackageParser2 getScanningCachingPackageParser() { return mScanningCachingPackageParserProducer.produce(this, mPackageManager); } public PackageParser2 getScanningPackageParser() { return mScanningPackageParserProducer.produce(this, mPackageManager); } public PackageParser2 getPreparingPackageParser() { return mPreparingPackageParserProducer.produce(this, mPackageManager); } public PackageInstallerService getPackageInstallerService() { return mPackageInstallerServiceProducer.get(this, mPackageManager); } public InstantAppResolverConnection getInstantAppResolverConnection( ComponentName instantAppResolverComponent) { return mInstantAppResolverConnectionProducer.produce( this, mPackageManager, instantAppResolverComponent); } public ModuleInfoProvider getModuleInfoProvider() { return mModuleInfoProviderProducer.get(this, mPackageManager); } public LegacyPermissionManagerInternal getLegacyPermissionManagerInternal() { return mLegacyPermissionManagerInternalProducer.get(this, mPackageManager); } public DomainVerificationManagerInternal getDomainVerificationManagerInternal() { return mDomainVerificationManagerInternalProducer.get(this, mPackageManager); } public Handler getHandler() { return mHandlerProducer.get(this, mPackageManager); } } /** Provides an abstraction to static access to system state. */ public interface SystemWrapper { void disablePackageCaches(); void enablePackageCaches(); } private static class DefaultSystemWrapper implements SystemWrapper { @Override public void disablePackageCaches() { // disable all package caches that shouldn't apply within system server PackageManager.disableApplicationInfoCache(); PackageManager.disablePackageInfoCache(); ApplicationPackageManager.invalidateGetPackagesForUidCache(); ApplicationPackageManager.disableGetPackagesForUidCache(); ApplicationPackageManager.invalidateHasSystemFeatureCache(); // Avoid invalidation-thrashing by preventing cache invalidations from causing property // writes if the cache isn't enabled yet. We re-enable writes later when we're // done initializing. sSnapshotCorked.incrementAndGet(); PackageManager.corkPackageInfoCache(); } @Override public void enablePackageCaches() { // Uncork cache invalidations and allow clients to cache package information. int corking = sSnapshotCorked.decrementAndGet(); if (TRACE_SNAPSHOTS && corking == 0) { Log.i(TAG, "snapshot: corking returns to 0"); } PackageManager.uncorkPackageInfoCache(); } } @VisibleForTesting(visibility = Visibility.PRIVATE) public static class TestParams { public ApexManager apexManager; public @Nullable String appPredictionServicePackage; public ArtManagerService artManagerService; public @Nullable String configuratorPackage; public int defParseFlags; public DefaultAppProvider defaultAppProvider; public DexManager dexManager; public List dirsToScanAsSystem; public @Nullable String documenterPackage; public boolean factoryTest; public ArrayMap availableFeatures; public Handler handler; public @Nullable String incidentReportApproverPackage; public IncrementalManager incrementalManager; public PackageInstallerService installerService; public InstantAppRegistry instantAppRegistry; public InstantAppResolverConnection instantAppResolverConnection; public ComponentName instantAppResolverSettingsComponent; public boolean isPreNmr1Upgrade; public boolean isPreNupgrade; public boolean isPreQupgrade; public boolean isUpgrade; public LegacyPermissionManagerInternal legacyPermissionManagerInternal; public DisplayMetrics Metrics; public ModuleInfoProvider moduleInfoProvider; public MoveCallbacks moveCallbacks; public boolean onlyCore; public OverlayConfig overlayConfig; public PackageDexOptimizer packageDexOptimizer; public PackageParser2.Callback packageParserCallback; public PendingPackageBroadcasts pendingPackageBroadcasts; public PackageManagerInternal pmInternal; public TestUtilityService testUtilityService; public ProcessLoggingHandler processLoggingHandler; public ProtectedPackages protectedPackages; public @NonNull String requiredInstallerPackage; public @NonNull String requiredPermissionControllerPackage; public @NonNull String requiredUninstallerPackage; public @Nullable String requiredVerifierPackage; public String[] separateProcesses; public @NonNull String servicesExtensionPackageName; public @Nullable String setupWizardPackage; public @NonNull String sharedSystemSharedLibraryPackageName; public @Nullable String storageManagerPackage; public @Nullable String defaultTextClassifierPackage; public @Nullable String systemTextClassifierPackage; public @Nullable String overlayConfigSignaturePackage; public ViewCompiler viewCompiler; public @Nullable String retailDemoPackage; public @Nullable String recentsPackage; public ComponentName resolveComponentName; public ArrayMap packages; public boolean enableFreeCacheV2; public int sdkVersion; public SystemWrapper systemWrapper; public File appInstallDir; public File appLib32InstallDir; public boolean isEngBuild; public boolean isUserDebugBuild; public int sdkInt = Build.VERSION.SDK_INT; public String incrementalVersion = Build.VERSION.INCREMENTAL; } @Watched private final AppsFilter mAppsFilter; final PackageParser2.Callback mPackageParserCallback; // Currently known shared libraries. @Watched final WatchedArrayMap> mSharedLibraries = new WatchedArrayMap<>(); private final SnapshotCache>> mSharedLibrariesSnapshot = new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries, "PackageManagerService.mSharedLibraries"); @Watched final WatchedArrayMap> mStaticLibsByDeclaringPackage = new WatchedArrayMap<>(); private final SnapshotCache>> mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage, "PackageManagerService.mStaticLibsByDeclaringPackage"); // Mapping from instrumentation class names to info about them. @Watched final WatchedArrayMap mInstrumentation = new WatchedArrayMap<>(); private final SnapshotCache> mInstrumentationSnapshot = new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation, "PackageManagerService.mInstrumentation"); // Packages whose data we have transfered into another package, thus // should no longer exist. final ArraySet mTransferredPackages = new ArraySet<>(); // Broadcast actions that are only available to the system. @GuardedBy("mProtectedBroadcasts") final ArraySet mProtectedBroadcasts = new ArraySet<>(); /** List of packages waiting for verification. */ final SparseArray mPendingVerification = new SparseArray<>(); /** List of packages waiting for rollback to be enabled. */ final SparseArray mPendingEnableRollback = new SparseArray<>(); final PackageInstallerService mInstallerService; final ArtManagerService mArtManagerService; final PackageDexOptimizer mPackageDexOptimizer; // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). private final DexManager mDexManager; private final ViewCompiler mViewCompiler; private AtomicInteger mNextMoveId = new AtomicInteger(); private final MoveCallbacks mMoveCallbacks; // Cache of users who need badging. private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; /** Token for keys in mPendingEnableRollback. */ private int mPendingEnableRollbackToken = 0; @Watched(manual = true) volatile boolean mSystemReady; @Watched(manual = true) private volatile boolean mSafeMode; volatile boolean mHasSystemUidErrors; @Watched private final WatchedSparseBooleanArray mWebInstantAppsDisabled = new WatchedSparseBooleanArray(); @Watched(manual = true) private ApplicationInfo mAndroidApplication; @Watched(manual = true) final ActivityInfo mResolveActivity = new ActivityInfo(); final ResolveInfo mResolveInfo = new ResolveInfo(); @Watched(manual = true) private ComponentName mResolveComponentName; AndroidPackage mPlatformPackage; ComponentName mCustomResolverComponentName; boolean mResolverReplaced = false; @NonNull private final DomainVerificationManagerInternal mDomainVerificationManager; /** The service connection to the ephemeral resolver */ final InstantAppResolverConnection mInstantAppResolverConnection; /** Component used to show resolver settings for Instant Apps */ final ComponentName mInstantAppResolverSettingsComponent; /** Activity used to install instant applications */ @Watched(manual = true) private ActivityInfo mInstantAppInstallerActivity; @Watched(manual = true) private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo(); private final Map> mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>()); // Internal interface for permission manager private final PermissionManagerServiceInternal mPermissionManager; @Watched private final ComponentResolver mComponentResolver; // List of packages names to keep cached, even if they are uninstalled for all users private List mKeepUninstalledPackages; // Cached reference to IDevicePolicyManager. private IDevicePolicyManager mDevicePolicyManager = null; private File mCacheDir; private Future mPrepareAppDataFuture; private final IncrementalManager mIncrementalManager; private final DefaultAppProvider mDefaultAppProvider; private final LegacyPermissionManagerInternal mLegacyPermissionManager; private final PackageProperty mPackageProperty = new PackageProperty(); // Set of pending broadcasts for aggregating enable/disable of components. @VisibleForTesting(visibility = Visibility.PACKAGE) public static class PendingPackageBroadcasts { // for each user id, a map of components within that package> final SparseArray>> mUidMap; public PendingPackageBroadcasts() { mUidMap = new SparseArray<>(2); } public ArrayList get(int userId, String packageName) { ArrayMap> packages = getOrAllocate(userId); return packages.get(packageName); } public void put(int userId, String packageName, ArrayList components) { ArrayMap> packages = getOrAllocate(userId); packages.put(packageName, components); } public void remove(int userId, String packageName) { ArrayMap> packages = mUidMap.get(userId); if (packages != null) { packages.remove(packageName); } } public void remove(int userId) { mUidMap.remove(userId); } public int userIdCount() { return mUidMap.size(); } public int userIdAt(int n) { return mUidMap.keyAt(n); } public ArrayMap> packagesForUserId(int userId) { return mUidMap.get(userId); } public int size() { // total number of pending broadcast entries across all userIds int num = 0; for (int i = 0; i< mUidMap.size(); i++) { num += mUidMap.valueAt(i).size(); } return num; } public void clear() { mUidMap.clear(); } private ArrayMap> getOrAllocate(int userId) { ArrayMap> map = mUidMap.get(userId); if (map == null) { map = new ArrayMap<>(); mUidMap.put(userId, map); } return map; } } final PendingPackageBroadcasts mPendingBroadcasts; static final int SEND_PENDING_BROADCAST = 1; static final int INIT_COPY = 5; static final int POST_INSTALL = 9; static final int WRITE_SETTINGS = 13; static final int WRITE_PACKAGE_RESTRICTIONS = 14; static final int PACKAGE_VERIFIED = 15; static final int CHECK_PENDING_VERIFICATION = 16; // public static final int UNUSED = 17; // public static final int UNUSED = 18; static final int WRITE_PACKAGE_LIST = 19; static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20; static final int ENABLE_ROLLBACK_STATUS = 21; static final int ENABLE_ROLLBACK_TIMEOUT = 22; static final int DEFERRED_NO_KILL_POST_DELETE = 23; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24; static final int INTEGRITY_VERIFICATION_COMPLETE = 25; static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26; static final int DOMAIN_VERIFICATION = 27; static final int SNAPSHOT_UNCORK = 28; static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds private static final long BROADCAST_DELAY_DURING_STARTUP = 10 * 1000L; // 10 seconds (in millis) private static final long BROADCAST_DELAY = 1 * 1000L; // 1 second (in millis) // When the service constructor finished plus a delay (used for broadcast delay computation) private long mServiceStartWithDelay; private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD = 2 * 60 * 60 * 1000L; /* two hours */ final UserManagerService mUserManager; // Stores a list of users whose package restrictions file needs to be updated private ArraySet mDirtyUsers = new ArraySet<>(); // Recordkeeping of restore-after-install operations that are currently in flight // between the Package Manager and the Backup Manager static class PostInstallData { @Nullable public final InstallArgs args; @NonNull public final PackageInstalledInfo res; @Nullable public final Runnable mPostInstallRunnable; PostInstallData(@Nullable InstallArgs args, @NonNull PackageInstalledInfo res, @Nullable Runnable postInstallRunnable) { this.args = args; this.res = res; mPostInstallRunnable = postInstallRunnable; } } final SparseArray mRunningInstalls = new SparseArray<>(); int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows // XML tags for backup/restore of various bits of state private static final String TAG_PREFERRED_BACKUP = "pa"; private static final String TAG_DEFAULT_APPS = "da"; private static final String TAG_INTENT_FILTER_VERIFICATION = "iv"; private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup"; private static final String TAG_ALL_GRANTS = "rt-grants"; private static final String TAG_GRANT = "grant"; private static final String ATTR_PACKAGE_NAME = "pkg"; private static final String TAG_PERMISSION = "perm"; private static final String ATTR_PERMISSION_NAME = "name"; private static final String ATTR_IS_GRANTED = "g"; private static final String ATTR_USER_SET = "set"; private static final String ATTR_USER_FIXED = "fixed"; private static final String ATTR_REVOKE_ON_UPGRADE = "rou"; // System/policy permission grants are not backed up private static final int SYSTEM_RUNTIME_GRANT_MASK = FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_GRANTED_BY_DEFAULT; // And we back up these user-adjusted states private static final int USER_RUNTIME_GRANT_MASK = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_REVOKED_COMPAT; final @Nullable String mRequiredVerifierPackage; final @NonNull String mRequiredInstallerPackage; final @NonNull String mRequiredUninstallerPackage; final @NonNull String mRequiredPermissionControllerPackage; final @Nullable String mSetupWizardPackage; final @Nullable String mStorageManagerPackage; final @Nullable String mDefaultTextClassifierPackage; final @Nullable String mSystemTextClassifierPackageName; final @Nullable String mDocumenterPackage; final @Nullable String mConfiguratorPackage; final @Nullable String mAppPredictionServicePackage; final @Nullable String mIncidentReportApproverPackage; final @Nullable String mServicesExtensionPackageName; final @Nullable String mSharedSystemSharedLibraryPackageName; final @Nullable String mRetailDemoPackage; final @Nullable String mOverlayConfigSignaturePackage; final @Nullable String mRecentsPackage; @GuardedBy("mLock") private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); private final DomainVerificationConnection mDomainVerificationConnection = new DomainVerificationConnection(); private class DomainVerificationConnection implements DomainVerificationService.Connection, DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection { @Override public void scheduleWriteSettings() { synchronized (mLock) { PackageManagerService.this.scheduleWriteSettingsLocked(); } } @Override public int getCallingUid() { return Binder.getCallingUid(); } @UserIdInt @Override public int getCallingUserId() { return UserHandle.getCallingUserId(); } @Override public void schedule(int code, @Nullable Object object) { Message message = mHandler.obtainMessage(DOMAIN_VERIFICATION); message.arg1 = code; message.obj = object; mHandler.sendMessage(message); } @Override public long getPowerSaveTempWhitelistAppDuration() { return PackageManagerService.this.getVerificationTimeout(); } @Override public DeviceIdleInternal getDeviceIdleInternal() { return mInjector.getLocalService(DeviceIdleInternal.class); } @Override public boolean isCallerPackage(int callingUid, @NonNull String packageName) { final int callingUserId = UserHandle.getUserId(callingUid); return callingUid == getPackageUid(packageName, 0, callingUserId); } @Nullable @Override public AndroidPackage getPackage(@NonNull String packageName) { return PackageManagerService.this.getPackage(packageName); } @Override public boolean filterAppAccess(String packageName, int callingUid, int userId) { return mPmInternal.filterAppAccess(packageName, callingUid, userId); } @Override public int[] getAllUserIds() { return mUserManager.getUserIds(); } @Override public boolean doesUserExist(@UserIdInt int userId) { return mUserManager.exists(userId); } @Override public void withPackageSettingsSnapshot( @NonNull Consumer> block) { mPmInternal.withPackageSettingsSnapshot(block); } @Override public Output withPackageSettingsSnapshotReturning( @NonNull FunctionalUtils.ThrowingFunction, Output> block) { return mPmInternal.withPackageSettingsSnapshotReturning(block); } @Override public void withPackageSettingsSnapshotThrowing( @NonNull FunctionalUtils.ThrowingCheckedConsumer, ExceptionType> block) throws ExceptionType { mPmInternal.withPackageSettingsSnapshotThrowing(block); } @Override public void withPackageSettingsSnapshotThrowing2( @NonNull FunctionalUtils.ThrowingChecked2Consumer< Function, ExceptionOne, ExceptionTwo> block) throws ExceptionOne, ExceptionTwo { mPmInternal.withPackageSettingsSnapshotThrowing2(block); } @Override public Output withPackageSettingsSnapshotReturningThrowing( @NonNull FunctionalUtils.ThrowingCheckedFunction< Function, Output, ExceptionType> block) throws ExceptionType { return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block); } } /** * Invalidate the package info cache, which includes updating the cached computer. * @hide */ public static void invalidatePackageInfoCache() { PackageManager.invalidatePackageInfoCache(); onChanged(); } private final Watcher mWatcher = new Watcher() { @Override public void onChange(@Nullable Watchable what) { PackageManagerService.this.onChange(what); } }; /** * A Snapshot is a subset of PackageManagerService state. A snapshot is either live * or snapped. Live snapshots directly reference PackageManagerService attributes. * Snapped snapshots contain deep copies of the attributes. */ private class Snapshot { public static final int LIVE = 1; public static final int SNAPPED = 2; public final Settings settings; public final WatchedSparseIntArray isolatedOwners; public final WatchedArrayMap packages; public final WatchedArrayMap> sharedLibs; public final WatchedArrayMap> staticLibs; public final WatchedArrayMap instrumentation; public final WatchedSparseBooleanArray webInstantAppsDisabled; public final ComponentName resolveComponentName; public final ActivityInfo resolveActivity; public final ActivityInfo instantAppInstallerActivity; public final ResolveInfo instantAppInstallerInfo; public final InstantAppRegistry instantAppRegistry; public final ApplicationInfo androidApplication; public final String appPredictionServicePackage; public final AppsFilter appsFilter; public final ComponentResolver componentResolver; public final PackageManagerService service; Snapshot(int type) { if (type == Snapshot.SNAPPED) { settings = mSettings.snapshot(); isolatedOwners = mIsolatedOwnersSnapshot.snapshot(); packages = mPackagesSnapshot.snapshot(); sharedLibs = mSharedLibrariesSnapshot.snapshot(); staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot(); instrumentation = mInstrumentationSnapshot.snapshot(); resolveComponentName = mResolveComponentName.clone(); resolveActivity = new ActivityInfo(mResolveActivity); instantAppInstallerActivity = (mInstantAppInstallerActivity == null) ? null : new ActivityInfo(mInstantAppInstallerActivity); instantAppInstallerInfo = new ResolveInfo(mInstantAppInstallerInfo); webInstantAppsDisabled = mWebInstantAppsDisabled.snapshot(); instantAppRegistry = mInstantAppRegistry.snapshot(); androidApplication = (mAndroidApplication == null) ? null : new ApplicationInfo(mAndroidApplication); appPredictionServicePackage = mAppPredictionServicePackage; appsFilter = mAppsFilter.snapshot(); componentResolver = mComponentResolver.snapshot(); } else if (type == Snapshot.LIVE) { settings = mSettings; isolatedOwners = mIsolatedOwners; packages = mPackages; sharedLibs = mSharedLibraries; staticLibs = mStaticLibsByDeclaringPackage; instrumentation = mInstrumentation; resolveComponentName = mResolveComponentName; resolveActivity = mResolveActivity; instantAppInstallerActivity = mInstantAppInstallerActivity; instantAppInstallerInfo = mInstantAppInstallerInfo; webInstantAppsDisabled = mWebInstantAppsDisabled; instantAppRegistry = mInstantAppRegistry; androidApplication = mAndroidApplication; appPredictionServicePackage = mAppPredictionServicePackage; appsFilter = mAppsFilter; componentResolver = mComponentResolver; } else { throw new IllegalArgumentException(); } service = PackageManagerService.this; } } /** * A {@link Computer} provides a set of functions that can operate on live data or snapshot * data. At this time, the {@link Computer} is implemented by the * {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}. * * New functions must be added carefully. *

    *
  1. New functions must be true functions with respect to data collected in a * {@link Snapshot}. Such data may never be modified from inside a {@link Computer} * function. *
  2. * *
  3. A new function must be implemented in {@link ComputerEngine}. *
  4. * *
  5. A new function must be overridden in {@link ComputerLocked} if the function * cannot safely access live data without holding the PackageManagerService lock. The * form of the {@link ComputerLocked} function must be a single call to the * {@link ComputerEngine} implementation, wrapped in a synchronized * block. Functions in {@link ComputerLocked} should never include any other code. *
  6. * * Care must be taken when deciding if a function should be overridden in * {@link ComputerLocked}. The complex lock relationships of PackageManagerService * and other managers (like PermissionManager) mean deadlock is possible. On the * other hand, not overriding in {@link ComputerLocked} may leave a function walking * unstable data. * * To coax developers to consider such issues carefully, all methods in * {@link Computer} must be annotated with @LiveImplementation(override = * MANDATORY) or LiveImplementation(locked = NOT_ALLOWED). A unit * test verifies the annotation and that the annotation corresponds to the code in * {@link ComputerEngine} and {@link ComputerLocked}. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected interface Computer { /** * Every method must be annotated. */ @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface LiveImplementation { // A Computer method must be annotated with one of the following values: // MANDATORY - the method must be overridden in ComputerEngineLive. The // format of the override is a call to the super method, wrapped in a // synchronization block. // NOT_ALLOWED - the method may not appear in the live computer. It must // be final in the ComputerEngine. int MANDATORY = 1; int NOT_ALLOWED = 2; int override() default MANDATORY; String rationale() default ""; } /** * Administrative statistics: record that the snapshot has been used. Every call * to use() increments the usage counter. */ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) default void use() { } /** * Fetch the snapshot usage counter. * @return The number of times this snapshot was used. */ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) default int getUsed() { return 0; } @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps); @LiveImplementation(override = LiveImplementation.MANDATORY) @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ActivityInfo getActivityInfo(ComponentName component, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) AndroidPackage getPackage(String packageName); @LiveImplementation(override = LiveImplementation.MANDATORY) AndroidPackage getPackage(int uid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo getApplicationInfo(String packageName, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ComponentName getDefaultHomeActivity(int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) Intent getHomeIntent(); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) List getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) List applyPostResolutionFilter(@NonNull List resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo getPackageInfo(String packageName, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageSetting getPackageSetting(String packageName); @LiveImplementation(override = LiveImplementation.MANDATORY) PackageSetting getPackageSettingInternal(String packageName, int callingUid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ParceledListSlice getInstalledPackages(int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, int sourceUserId, int targetUserId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ServiceInfo getServiceInfo(ComponentName component, int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version); @LiveImplementation(override = LiveImplementation.MANDATORY) String getInstantAppPackageName(int callingUid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String resolveExternalPackageNameLPr(AndroidPackage pkg); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String resolveInternalPackageNameLPr(String packageName, long versionCode); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String[] getPackagesForUid(int uid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) UserInfo getProfileParent(int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean canViewInstantApps(int callingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isCallerSameApp(String packageName, int uid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isComponentVisibleToInstantApp(@Nullable ComponentName component); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isComponentVisibleToInstantApp(@Nullable ComponentName component, @ComponentType int type); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, String resolvedType, int flags); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isInstantApp(String packageName, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int checkUidPermission(String permName, int uid); @LiveImplementation(override = LiveImplementation.MANDATORY) int getPackageUidInternal(String packageName, int flags, int userId, int callingUid); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForApplication(int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForComponent(int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForPackage(int flags, int userId); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message); @LiveImplementation(override = LiveImplementation.MANDATORY) SigningDetails getSigningDetails(@NonNull String packageName); @LiveImplementation(override = LiveImplementation.MANDATORY) SigningDetails getSigningDetails(int uid); @LiveImplementation(override = LiveImplementation.MANDATORY) boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) boolean filterAppAccess(String packageName, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered); @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId); } /** * This class contains the implementation of the Computer functions. It * is entirely self-contained - it has no implicit access to * PackageManagerService. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected static class ComputerEngine implements Computer { // The administrative use counter. private int mUsed = 0; // Cached attributes. The names in this class are the same as the // names in PackageManagerService; see that class for documentation. protected final Settings mSettings; private final WatchedSparseIntArray mIsolatedOwners; private final WatchedArrayMap mPackages; private final WatchedArrayMap mInstrumentation; private final WatchedArrayMap> mStaticLibsByDeclaringPackage; private final WatchedArrayMap> mSharedLibraries; private final ComponentName mLocalResolveComponentName; private final ActivityInfo mResolveActivity; private final WatchedSparseBooleanArray mWebInstantAppsDisabled; private final ActivityInfo mLocalInstantAppInstallerActivity; private final ResolveInfo mInstantAppInstallerInfo; private final InstantAppRegistry mInstantAppRegistry; private final ApplicationInfo mLocalAndroidApplication; private final AppsFilter mAppsFilter; // Immutable service attribute private final String mAppPredictionServicePackage; // The following are not cloned since changes to these have never // been guarded by the PMS lock. private final Context mContext; private final UserManagerService mUserManager; private final PermissionManagerServiceInternal mPermissionManager; private final ApexManager mApexManager; private final Injector mInjector; private final ComponentResolver mComponentResolver; private final InstantAppResolverConnection mInstantAppResolverConnection; private final DefaultAppProvider mDefaultAppProvider; private final DomainVerificationManagerInternal mDomainVerificationManager; private final PackageDexOptimizer mPackageDexOptimizer; private final DexManager mDexManager; private final CompilerStats mCompilerStats; // PackageManagerService attributes that are primitives are referenced through the // pms object directly. Primitives are the only attributes so referenced. protected final PackageManagerService mService; private boolean safeMode() { return mService.mSafeMode; } protected ComponentName resolveComponentName() { return mLocalResolveComponentName; } protected ActivityInfo instantAppInstallerActivity() { return mLocalInstantAppInstallerActivity; } protected ApplicationInfo androidApplication() { return mLocalAndroidApplication; } ComputerEngine(Snapshot args) { mSettings = args.settings; mIsolatedOwners = args.isolatedOwners; mPackages = args.packages; mSharedLibraries = args.sharedLibs; mStaticLibsByDeclaringPackage = args.staticLibs; mInstrumentation = args.instrumentation; mWebInstantAppsDisabled = args.webInstantAppsDisabled; mLocalResolveComponentName = args.resolveComponentName; mResolveActivity = args.resolveActivity; mLocalInstantAppInstallerActivity = args.instantAppInstallerActivity; mInstantAppInstallerInfo = args.instantAppInstallerInfo; mInstantAppRegistry = args.instantAppRegistry; mLocalAndroidApplication = args.androidApplication; mAppsFilter = args.appsFilter; mComponentResolver = args.componentResolver; mAppPredictionServicePackage = args.appPredictionServicePackage; // The following are not cached copies. Instead they are // references to outside services. mPermissionManager = args.service.mPermissionManager; mUserManager = args.service.mUserManager; mContext = args.service.mContext; mInjector = args.service.mInjector; mApexManager = args.service.mApexManager; mInstantAppResolverConnection = args.service.mInstantAppResolverConnection; mDefaultAppProvider = args.service.mDefaultAppProvider; mDomainVerificationManager = args.service.mDomainVerificationManager; mPackageDexOptimizer = args.service.mPackageDexOptimizer; mDexManager = args.service.mDexManager; mCompilerStats = args.service.mCompilerStats; // Used to reference PMS attributes that are primitives and which are not // updated under control of the PMS lock. mService = args.service; } /** * Record that the snapshot was used. */ public final void use() { mUsed++; } /** * Return the usage counter. */ public final int getUsed() { return mUsed; } public final @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { if (!mUserManager.exists(userId)) return Collections.emptyList(); final String instantAppPkgName = getInstantAppPackageName(filterCallingUid); enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, "query intent activities"); final String pkgName = intent.getPackage(); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart, comp != null || pkgName != null /*onlyExposedExplicitly*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); if (comp != null) { final List list = new ArrayList<>(1); final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { // When specifying an explicit component, we prevent the activity from being // used when either 1) the calling package is normal and the activity is within // an ephemeral application or 2) the calling package is ephemeral and the // activity is not visible to ephemeral applications. final boolean matchInstantApp = (flags & PackageManager.MATCH_INSTANT) != 0; final boolean matchVisibleToInstantAppOnly = (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; final boolean matchExplicitlyVisibleOnly = (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; final boolean isCallerInstantApp = instantAppPkgName != null; final boolean isTargetSameInstantApp = comp.getPackageName().equals(instantAppPkgName); final boolean isTargetInstantApp = (ai.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetVisibleToInstantApp = (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean isTargetExplicitlyVisibleToInstantApp = isTargetVisibleToInstantApp && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; final boolean isTargetHiddenFromInstantApp = !isTargetVisibleToInstantApp || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp); final boolean blockInstantResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); final boolean blockNormalResolution = !resolveForStart && !isTargetInstantApp && !isCallerInstantApp && shouldFilterApplicationLocked( getPackageSettingInternal(ai.applicationInfo.packageName, Process.SYSTEM_UID), filterCallingUid, userId); if (!blockInstantResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } } List result = applyPostResolutionFilter( list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); return result; } QueryIntentActivitiesResult lockedResult = queryIntentActivitiesInternalBody( intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName); if (lockedResult.answer != null) { return lockedResult.answer; } if (lockedResult.addInstant) { String callingPkgName = getInstantAppPackageName(filterCallingUid); boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId); lockedResult.result = maybeAddInstantAppInstaller(lockedResult.result, intent, resolvedType, flags, userId, resolveForStart, isRequesterInstantApp); } if (lockedResult.sortResult) { Collections.sort(lockedResult.result, RESOLVE_PRIORITY_SORTER); } return applyPostResolutionFilter( lockedResult.result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); } public final @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId) { return queryIntentActivitiesInternal( intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(), userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); } public final @NonNull List queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps) { if (!mUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserOrProfilePermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "query intent receivers"); final String instantAppPkgName = getInstantAppPackageName(callingUid); flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList<>(1); final ServiceInfo si = getServiceInfo(comp, flags, userId); if (si != null) { // When specifying an explicit component, we prevent the service from being // used when either 1) the service is in an instant application and the // caller is not the same instant application or 2) the calling package is // ephemeral and the activity is not visible to ephemeral applications. final boolean matchInstantApp = (flags & PackageManager.MATCH_INSTANT) != 0; final boolean matchVisibleToInstantAppOnly = (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; final boolean isCallerInstantApp = instantAppPkgName != null; final boolean isTargetSameInstantApp = comp.getPackageName().equals(instantAppPkgName); final boolean isTargetInstantApp = (si.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetHiddenFromInstantApp = (si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0; final boolean blockInstantResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp && shouldFilterApplicationLocked( getPackageSettingInternal(si.applicationInfo.packageName, Process.SYSTEM_UID), callingUid, userId); if (!blockInstantResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.serviceInfo = si; list.add(ri); } } return list; } return queryIntentServicesInternalBody(intent, resolvedType, flags, userId, callingUid, instantAppPkgName); } protected @NonNull List queryIntentServicesInternalBody(Intent intent, String resolvedType, int flags, int userId, int callingUid, String instantAppPkgName) { // reader String pkgName = intent.getPackage(); if (pkgName == null) { final List resolveInfos = mComponentResolver.queryServices(intent, resolvedType, flags, userId); if (resolveInfos == null) { return Collections.emptyList(); } return applyPostServiceResolutionFilter( resolveInfos, instantAppPkgName, userId, callingUid); } final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List resolveInfos = mComponentResolver.queryServices(intent, resolvedType, flags, pkg.getServices(), userId); if (resolveInfos == null) { return Collections.emptyList(); } return applyPostServiceResolutionFilter( resolveInfos, instantAppPkgName, userId, callingUid); } return Collections.emptyList(); } public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName) { // reader boolean sortResult = false; boolean addInstant = false; List result = null; if (pkgName == null) { List matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); // Check for results that need to skip the current profile. ResolveInfo skipProfileInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (skipProfileInfo != null) { List xpResult = new ArrayList<>(1); xpResult.add(skipProfileInfo); return new QueryIntentActivitiesResult( applyPostResolutionFilter( filterIfNotSystemUser(xpResult, userId), instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent)); } // Check for results in the current profile. result = filterIfNotSystemUser(mComponentResolver.queryActivities( intent, resolvedType, flags, userId), userId); addInstant = isInstantAppResolutionAllowed(intent, result, userId, false /*skipPackageCheck*/, flags); // Check for cross profile results. boolean hasNonNegativePriorityResult = hasNonNegativePriority(result); CrossProfileDomainInfo specificXpInfo = queryCrossProfileIntents( matchingFilters, intent, resolvedType, flags, userId, hasNonNegativePriorityResult); if (intent.hasWebURI()) { CrossProfileDomainInfo generalXpInfo = null; final UserInfo parent = getProfileParent(userId); if (parent != null) { generalXpInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, userId, parent.id); } // Generalized cross profile intents take precedence over specific. // Note that this is the opposite of the intuitive order. CrossProfileDomainInfo prioritizedXpInfo = generalXpInfo != null ? generalXpInfo : specificXpInfo; if (!addInstant) { if (result.isEmpty() && prioritizedXpInfo != null) { // No result in current profile, but found candidate in parent user. // And we are not going to add ephemeral app, so we can return the // result straight away. result.add(prioritizedXpInfo.resolveInfo); return new QueryIntentActivitiesResult( applyPostResolutionFilter(result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent)); } else if (result.size() <= 1 && prioritizedXpInfo == null) { // No result in parent user and <= 1 result in current profile, and we // are not going to add ephemeral app, so we can return the result // without further processing. return new QueryIntentActivitiesResult( applyPostResolutionFilter(result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent)); } } // We have more than one candidate (combining results from current and parent // profile), so we need filtering and sorting. result = filterCandidatesWithDomainPreferredActivitiesLPr( intent, flags, result, prioritizedXpInfo, userId); sortResult = true; } else { // If not web Intent, just add result to candidate set and let ResolverActivity // figure it out. if (specificXpInfo != null) { result.add(specificXpInfo.resolveInfo); sortResult = true; } } } else { final PackageSetting setting = getPackageSettingInternal(pkgName, Process.SYSTEM_UID); result = null; if (setting != null && setting.pkg != null && (resolveForStart || !shouldFilterApplicationLocked(setting, filterCallingUid, userId))) { result = filterIfNotSystemUser(mComponentResolver.queryActivities( intent, resolvedType, flags, setting.pkg.getActivities(), userId), userId); } if (result == null || result.size() == 0) { // the caller wants to resolve for a particular package; however, there // were no installed results, so, try to find an ephemeral result addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId, true /*skipPackageCheck*/, flags); if (result == null) { result = new ArrayList<>(); } } } return new QueryIntentActivitiesResult(sortResult, addInstant, result); } /** * Returns the activity component that can handle install failures. *

    By default, the instant application installer handles failures. However, an * application may want to handle failures on its own. Applications do this by * creating an activity with an intent filter that handles the action * {@link Intent#ACTION_INSTALL_FAILURE}. */ private @Nullable ComponentName findInstallFailureActivity( String packageName, int filterCallingUid, int userId) { final Intent failureActivityIntent = new Intent(Intent.ACTION_INSTALL_FAILURE); failureActivityIntent.setPackage(packageName); // IMPORTANT: disallow dynamic splits to avoid an infinite loop final List result = queryIntentActivitiesInternal( failureActivityIntent, null /*resolvedType*/, 0 /*flags*/, 0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/, false /*allowDynamicSplits*/); final int NR = result.size(); if (NR > 0) { for (int i = 0; i < NR; i++) { final ResolveInfo info = result.get(i); if (info.activityInfo.splitName != null) { continue; } return new ComponentName(packageName, info.activityInfo.name); } } return null; } public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out activities * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId); if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) { enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, "get activity info"); } return getActivityInfoInternalBody(component, flags, filterCallingUid, userId); } protected ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags, int filterCallingUid, int userId) { ParsedActivity a = mComponentResolver.getActivity(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName()); if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { return null; } return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId, ps); } if (resolveComponentName().equals(component)) { return PackageParser.generateActivityInfo( mResolveActivity, flags, new PackageUserState(), userId); } return null; } public AndroidPackage getPackage(String packageName) { packageName = resolveInternalPackageNameLPr( packageName, PackageManager.VERSION_CODE_HIGHEST); return mPackages.get(packageName); } public AndroidPackage getPackage(int uid) { final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID); AndroidPackage pkg = null; final int numPackages = packageNames == null ? 0 : packageNames.length; for (int i = 0; pkg == null && i < numPackages; i++) { pkg = mPackages.get(packageNames[i]); } return pkg; } public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } if (ps.pkg == null) { final PackageInfo pInfo = generatePackageInfo(ps, flags, userId); if (pInfo != null) { return pInfo.applicationInfo; } return null; } ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } return ai; } return null; } public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out applications * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForApplication(flags, userId); if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) { enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, "get application info"); } return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId); } protected ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags, int filterCallingUid, int userId) { // writer // Normalize package name to handle renamed packages and static libs packageName = resolveInternalPackageNameLPr(packageName, PackageManager.VERSION_CODE_HIGHEST); AndroidPackage p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getApplicationInfo " + packageName + ": " + p); if (p != null) { PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) return null; if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } // Note: isEnabledLP() does not apply here - always return info ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo( p, flags, ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); } return ai; } if ((flags & PackageManager.MATCH_APEX) != 0) { // For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo // returned from getApplicationInfo, but for APEX packages difference shouldn't be // very big. // TODO(b/155328545): generate proper application info for APEXes as well. int apexFlags = ApexManager.MATCH_ACTIVE_PACKAGE; if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { apexFlags = ApexManager.MATCH_FACTORY_PACKAGE; } final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags); if (pi == null) { return null; } return pi.applicationInfo; } if ("android".equals(packageName)||"system".equals(packageName)) { return androidApplication(); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { // Already generates the external package name return generateApplicationInfoFromSettingsLPw(packageName, flags, filterCallingUid, userId); } return null; } protected ArrayList filterCandidatesWithDomainPreferredActivitiesLPrBody( Intent intent, int matchFlags, List candidates, CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) { final ArrayList result = new ArrayList<>(); final ArrayList matchAllList = new ArrayList<>(); final ArrayList undefinedList = new ArrayList<>(); // Blocking instant apps is usually done in applyPostResolutionFilter, but since // domain verification can resolve to a single result, which can be an instant app, // it will then be filtered to an empty list in that method. Instead, do blocking // here so that instant apps can be ignored for approval filtering and a lower // priority result chosen instead. final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId); final int count = candidates.size(); // First, try to use approved apps. for (int n = 0; n < count; n++) { ResolveInfo info = candidates.get(n); if (blockInstant && (info.isInstantAppAvailable || isInstantApp(info.activityInfo.packageName, userId))) { continue; } // Add to the special match all list (Browser use case) if (info.handleAllWebDataURI) { matchAllList.add(info); } else { undefinedList.add(info); } } // We'll want to include browser possibilities in a few cases boolean includeBrowser = false; if (!DomainVerificationUtils.isDomainVerificationIntent(intent, matchFlags)) { result.addAll(undefinedList); // Maybe add one for the other profile. if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) { result.add(xpDomainInfo.resolveInfo); } includeBrowser = true; } else { Pair, Integer> infosAndLevel = mDomainVerificationManager .filterToApprovedApp(intent, undefinedList, userId, mSettings::getPackageLPr); List approvedInfos = infosAndLevel.first; Integer highestApproval = infosAndLevel.second; // If no apps are approved for the domain, resolve only to browsers if (approvedInfos.isEmpty()) { includeBrowser = true; if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) { result.add(xpDomainInfo.resolveInfo); } } else { result.addAll(approvedInfos); // If the other profile has an app that's higher approval, add it if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel > highestApproval) { result.add(xpDomainInfo.resolveInfo); } } } if (includeBrowser) { // Also add browsers (all of them or only the default one) if (DEBUG_DOMAIN_VERIFICATION) { Slog.v(TAG, " ...including browsers in candidate set"); } if ((matchFlags & MATCH_ALL) != 0) { result.addAll(matchAllList); } else { // Browser/generic handling case. If there's a default browser, go straight // to that (but only if there is no other higher-priority match). final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser( userId); int maxMatchPrio = 0; ResolveInfo defaultBrowserMatch = null; final int numCandidates = matchAllList.size(); for (int n = 0; n < numCandidates; n++) { ResolveInfo info = matchAllList.get(n); // track the highest overall match priority... if (info.priority > maxMatchPrio) { maxMatchPrio = info.priority; } // ...and the highest-priority default browser match if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) { if (defaultBrowserMatch == null || (defaultBrowserMatch.priority < info.priority)) { if (debug) { Slog.v(TAG, "Considering default browser match " + info); } defaultBrowserMatch = info; } } } if (defaultBrowserMatch != null && defaultBrowserMatch.priority >= maxMatchPrio && !TextUtils.isEmpty(defaultBrowserPackageName)) { if (debug) { Slog.v(TAG, "Default browser match " + defaultBrowserMatch); } result.add(defaultBrowserMatch); } else { result.addAll(matchAllList); } } // If there is nothing selected, add all candidates if (result.size() == 0) { result.addAll(candidates); } } return result; } /** * Report the 'Home' activity which is currently set as "always use this one". If non is set * then reports the most likely home activity or null if there are more than one. */ public final ComponentName getDefaultHomeActivity(int userId) { List allHomeCandidates = new ArrayList<>(); ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId); if (cn != null) { return cn; } // TODO: This should not happen since there should always be a default package set for // ROLE_HOME in RoleManager. Continue with a warning log for now. Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager"); // Find the launcher with the highest priority and return that component if there are no // other home activity with the same priority. int lastPriority = Integer.MIN_VALUE; ComponentName lastComponent = null; final int size = allHomeCandidates.size(); for (int i = 0; i < size; i++) { final ResolveInfo ri = allHomeCandidates.get(i); if (ri.priority > lastPriority) { lastComponent = ri.activityInfo.getComponentName(); lastPriority = ri.priority; } else if (ri.priority == lastPriority) { // Two components found with same priority. lastComponent = null; } } return lastComponent; } public final ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId) { Intent intent = getHomeIntent(); List resolveInfos = queryIntentActivitiesInternal(intent, null, PackageManager.GET_META_DATA, userId); allHomeCandidates.clear(); if (resolveInfos == null) { return null; } allHomeCandidates.addAll(resolveInfos); String packageName = mDefaultAppProvider.getDefaultHome(userId); if (packageName == null) { // Role changes are not and cannot be atomic because its implementation lives inside // a system app, so when the home role changes, there is a window when the previous // role holder is removed and the new role holder is granted the preferred activity, // but hasn't become the role holder yet. However, this case may be easily hit // because the preferred activity change triggers a broadcast and receivers may try // to get the default home activity there. So we need to fix it for this time // window, and an easy workaround is to fallback to the current preferred activity. final int appId = UserHandle.getAppId(Binder.getCallingUid()); final boolean filtered = appId >= Process.FIRST_APPLICATION_UID; FindPreferredActivityBodyResult result = findPreferredActivityInternal( intent, null, 0, resolveInfos, true, false, false, userId, filtered); ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo; if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) { packageName = preferredResolveInfo.activityInfo.packageName; } } if (packageName == null) { return null; } int resolveInfosSize = resolveInfos.size(); for (int i = 0; i < resolveInfosSize; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); if (resolveInfo.activityInfo != null && TextUtils.equals( resolveInfo.activityInfo.packageName, packageName)) { return new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); } } return null; } public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, sourceUserId)) { return null; } List resultTargetUser = mComponentResolver.queryActivities(intent, resolvedType, flags, parentUserId); if (resultTargetUser == null || resultTargetUser.isEmpty()) { return null; } CrossProfileDomainInfo result = null; int size = resultTargetUser.size(); for (int i = 0; i < size; i++) { ResolveInfo riTargetUser = resultTargetUser.get(i); // Intent filter verification is only for filters that specify a host. So don't //return // those that handle all web uris. if (riTargetUser.handleAllWebDataURI) { continue; } String packageName = riTargetUser.activityInfo.packageName; PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { continue; } int approvalLevel = mDomainVerificationManager .approvalLevelForDomain(ps, intent, flags, parentUserId); if (result == null) { result = new CrossProfileDomainInfo(createForwardingResolveInfoUnchecked( new WatchedIntentFilter(), sourceUserId, parentUserId), approvalLevel); } else { result.highestApprovalLevel = Math.max(approvalLevel, result.highestApprovalLevel); } } if (result != null && result.highestApprovalLevel <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) { return null; } return result; } public final Intent getHomeIntent() { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.addCategory(Intent.CATEGORY_DEFAULT); return intent; } public final List getMatchingCrossProfileIntentFilters( Intent intent, String resolvedType, int userId) { CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId); if (resolver != null) { return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); } return null; } /** * Filters out ephemeral activities. *

    When resolving for an ephemeral app, only activities that 1) are defined in the * ephemeral app or 2) marked with {@code visibleToEphemeral} are returned. * * @param resolveInfos The pre-filtered list of resolved activities * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering * is performed. * @param intent * @return A filtered list of resolved activities. */ public final List applyPostResolutionFilter( @NonNull List resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId); for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); // remove locally resolved instant app web results when disabled if (info.isInstantAppAvailable && blockInstant) { resolveInfos.remove(i); continue; } // allow activities that are defined in the provided package if (allowDynamicSplits && info.activityInfo != null && info.activityInfo.splitName != null && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames, info.activityInfo.splitName)) { if (instantAppInstallerActivity() == null) { if (DEBUG_INSTALL) { Slog.v(TAG, "No installer - not adding it to the ResolveInfo list"); } resolveInfos.remove(i); continue; } if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) { resolveInfos.remove(i); continue; } // requested activity is defined in a split that hasn't been installed yet. // add the installer to the resolve list if (DEBUG_INSTALL) { Slog.v(TAG, "Adding installer to the ResolveInfo list"); } final ResolveInfo installerInfo = new ResolveInfo( mInstantAppInstallerInfo); final ComponentName installFailureActivity = findInstallFailureActivity( info.activityInfo.packageName, filterCallingUid, userId); installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo( installFailureActivity, info.activityInfo.packageName, info.activityInfo.applicationInfo.longVersionCode, info.activityInfo.splitName); // add a non-generic filter installerInfo.filter = new IntentFilter(); // This resolve info may appear in the chooser UI, so let us make it // look as the one it replaces as far as the user is concerned which // requires loading the correct label and icon for the resolve info. installerInfo.resolvePackageName = info.getComponentInfo().packageName; installerInfo.labelRes = info.resolveLabelResId(); installerInfo.icon = info.resolveIconResId(); installerInfo.isInstantAppAvailable = true; resolveInfos.set(i, installerInfo); continue; } if (ephemeralPkgName == null) { // caller is a full app SettingBase callingSetting = mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid)); PackageSetting resolvedSetting = getPackageSettingInternal(info.activityInfo.packageName, 0); if (resolveForStart || !mAppsFilter.shouldFilterApplication( filterCallingUid, callingSetting, resolvedSetting, userId)) { continue; } } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) { // caller is same app; don't need to apply any other filtering continue; } else if (resolveForStart && (intent.isWebIntent() || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) && intent.getPackage() == null && intent.getComponent() == null) { // ephemeral apps can launch other ephemeral apps indirectly continue; } else if (((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0) && !info.activityInfo.applicationInfo.isInstantApp()) { // allow activities that have been explicitly exposed to ephemeral apps continue; } resolveInfos.remove(i); } return resolveInfos; } private List applyPostServiceResolutionFilter(List resolveInfos, String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) { for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); if (instantAppPkgName == null) { SettingBase callingSetting = mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid)); PackageSetting resolvedSetting = getPackageSettingInternal(info.serviceInfo.packageName, 0); if (!mAppsFilter.shouldFilterApplication( filterCallingUid, callingSetting, resolvedSetting, userId)) { continue; } } final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp(); // allow services that are defined in the provided package if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) { if (info.serviceInfo.splitName != null && !ArrayUtils.contains(info.serviceInfo.applicationInfo.splitNames, info.serviceInfo.splitName)) { if (instantAppInstallerActivity() == null) { if (DEBUG_INSTANT) { Slog.v(TAG, "No installer - not adding it to the ResolveInfo" + "list"); } resolveInfos.remove(i); continue; } // requested service is defined in a split that hasn't been installed yet. // add the installer to the resolve list if (DEBUG_INSTANT) { Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); } final ResolveInfo installerInfo = new ResolveInfo( mInstantAppInstallerInfo); installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo( null /* installFailureActivity */, info.serviceInfo.packageName, info.serviceInfo.applicationInfo.longVersionCode, info.serviceInfo.splitName); // add a non-generic filter installerInfo.filter = new IntentFilter(); // load resources from the correct package installerInfo.resolvePackageName = info.getComponentInfo().packageName; resolveInfos.set(i, installerInfo); } continue; } // allow services that have been explicitly exposed to ephemeral apps if (!isEphemeralApp && ((info.serviceInfo.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) { continue; } resolveInfos.remove(i); } return resolveInfos; } private List filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent, int matchFlags, List candidates, CrossProfileDomainInfo xpDomainInfo, int userId) { final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0; if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) { Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " + candidates.size()); } final ArrayList result = filterCandidatesWithDomainPreferredActivitiesLPrBody( intent, matchFlags, candidates, xpDomainInfo, userId, debug); if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) { Slog.v(TAG, "Filtered results with preferred activities. New candidates count: " + result.size()); for (ResolveInfo info : result) { Slog.v(TAG, " + " + info.activityInfo); } } return result; } /** * Filter out activities with systemUserOnly flag set, when current user is not System. * * @return filtered list */ private List filterIfNotSystemUser(List resolveInfos, int userId) { if (userId == UserHandle.USER_SYSTEM) { return resolveInfos; } for (int i = resolveInfos.size() - 1; i >= 0; i--) { ResolveInfo info = resolveInfos.get(i); if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) { resolveInfos.remove(i); } } return resolveInfos; } private List maybeAddInstantAppInstaller(List result, Intent intent, String resolvedType, int flags, int userId, boolean resolveForStart, boolean isRequesterInstantApp) { // first, check to see if we've got an instant app already installed final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0; ResolveInfo localInstantApp = null; boolean blockResolution = false; if (!alreadyResolvedLocally) { final List instantApps = mComponentResolver.queryActivities( intent, resolvedType, flags | PackageManager.GET_RESOLVED_FILTER | PackageManager.MATCH_INSTANT | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY, userId); for (int i = instantApps.size() - 1; i >= 0; --i) { final ResolveInfo info = instantApps.get(i); final String packageName = info.activityInfo.packageName; final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps.getInstantApp(userId)) { if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags, userId)) { if (DEBUG_INSTANT) { Slog.v(TAG, "Instant app approved for intent; pkg: " + packageName); } localInstantApp = info; } else { if (DEBUG_INSTANT) { Slog.v(TAG, "Instant app not approved for intent; pkg: " + packageName); } blockResolution = true; } break; } } } // no app installed, let's see if one's available AuxiliaryResolveInfo auxiliaryResponse = null; if (!blockResolution) { if (localInstantApp == null) { // we don't have an instant app locally, resolve externally Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); String token = UUID.randomUUID().toString(); InstantAppDigest digest = InstantAppResolver.parseDigest(intent); final InstantAppRequest requestObject = new InstantAppRequest(null /*responseObj*/, intent /*origIntent*/, resolvedType, null /*callingPackage*/, null /*callingFeatureId*/, isRequesterInstantApp, userId, null /*verificationBundle*/, resolveForStart, digest.getDigestPrefixSecure(), token); auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne( mInstantAppResolverConnection, requestObject); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } else { // we have an instant application locally, but, we can't admit that since // callers shouldn't be able to determine prior browsing. create a placeholder // auxiliary response so the downstream code behaves as if there's an // instant application available externally. when it comes time to start // the instant application, we'll do the right thing. final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo; auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */, ai.packageName, ai.longVersionCode, null /* splitName */); } } if (intent.isWebIntent() && auxiliaryResponse == null) { return result; } final PackageSetting ps = mSettings.getPackageLPr(instantAppInstallerActivity().packageName); if (ps == null || !ps.readUserState(userId).isEnabled(instantAppInstallerActivity(), 0)) { return result; } final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo); ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo( instantAppInstallerActivity(), 0, ps.readUserState(userId), userId); ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART | IntentFilter.MATCH_ADJUSTMENT_NORMAL; // add a non-generic filter ephemeralInstaller.filter = new IntentFilter(); if (intent.getAction() != null) { ephemeralInstaller.filter.addAction(intent.getAction()); } if (intent.getData() != null && intent.getData().getPath() != null) { ephemeralInstaller.filter.addDataPath( intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL); } ephemeralInstaller.isInstantAppAvailable = true; // make sure this resolver is the default ephemeralInstaller.isDefault = true; ephemeralInstaller.auxiliaryInfo = auxiliaryResponse; if (DEBUG_INSTANT) { Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); } result.add(ephemeralInstaller); return result; } public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { if (!mUserManager.exists(userId)) return null; if (ps == null) { return null; } final int callingUid = Binder.getCallingUid(); // Filter out ephemeral app metadata: // * The system/shell/root can see metadata for any app // * An installed app can see metadata for 1) other installed apps // and 2) ephemeral apps that have explicitly interacted with it // * Ephemeral apps can only see their own data and exposed installed apps // * Holding a signature permission allows seeing instant apps if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; } if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && ps.isSystem()) { flags |= MATCH_ANY_USER; } final PackageUserState state = ps.readUserState(userId); AndroidPackage p = ps.pkg; if (p != null) { // Compute GIDs only if requested final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); // Compute granted permissions only if package has requested permissions final Set permissions = ((flags & PackageManager.GET_PERMISSIONS) == 0 || ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet() : mPermissionManager.getGrantedPermissions(ps.name, userId); PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags, ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps); if (packageInfo == null) { return null; } packageInfo.packageName = packageInfo.applicationInfo.packageName = resolveExternalPackageNameLPr(p); return packageInfo; } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) { PackageInfo pi = new PackageInfo(); pi.packageName = ps.name; pi.setLongVersionCode(ps.versionCode); pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null; pi.firstInstallTime = ps.firstInstallTime; pi.lastUpdateTime = ps.lastUpdateTime; ApplicationInfo ai = new ApplicationInfo(); ai.packageName = ps.name; ai.uid = UserHandle.getUid(userId, ps.appId); ai.primaryCpuAbi = ps.primaryCpuAbiString; ai.secondaryCpuAbi = ps.secondaryCpuAbiString; ai.setVersionCode(ps.versionCode); ai.flags = ps.pkgFlags; ai.privateFlags = ps.pkgPrivateFlags; pi.applicationInfo = PackageParser.generateApplicationInfo(ai, flags, state, userId); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for [" + ps.name + "]. Provides a minimum info."); return pi; } else { return null; } } public final PackageInfo getPackageInfo(String packageName, int flags, int userId) { return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST, flags, Binder.getCallingUid(), userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out packages * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ public final PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForPackage(flags, userId); enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission */, false /* checkShell */, "get package info"); return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid, userId); } protected PackageInfo getPackageInfoInternalBody(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { // reader // Normalize package name to handle renamed packages and static libs packageName = resolveInternalPackageNameLPr(packageName, versionCode); final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0; if (matchFactoryOnly) { // Instant app filtering for APEX modules is ignored if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_FACTORY_PACKAGE); } final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); if (ps != null) { if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } return generatePackageInfo(ps, flags, userId); } } AndroidPackage p = mPackages.get(packageName); if (matchFactoryOnly && p != null && !p.isSystem()) { return null; } if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { final PackageSetting ps = getPackageSetting(p.getPackageName()); if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } return generatePackageInfo(ps, flags, userId); } if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) return null; if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } return generatePackageInfo(ps, flags, userId); } if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); } return null; } @Nullable public final PackageSetting getPackageSetting(String packageName) { return getPackageSettingInternal(packageName, Binder.getCallingUid()); } public PackageSetting getPackageSettingInternal(String packageName, int callingUid) { packageName = resolveInternalPackageNameInternalLocked( packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid); return mSettings.getPackageLPr(packageName); } public final ParceledListSlice getInstalledPackages(int flags, int userId) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return ParceledListSlice.emptyList(); } if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId); enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get installed packages"); return getInstalledPackagesBody(flags, userId, callingUid); } protected ParceledListSlice getInstalledPackagesBody(int flags, int userId, int callingUid) { // writer final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; final boolean listApex = (flags & MATCH_APEX) != 0; final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0; ArrayList list; if (listUninstalled) { list = new ArrayList<>(mSettings.getPackagesLocked().size()); for (PackageSetting ps : mSettings.getPackagesLocked().values()) { if (listFactory) { if (!ps.isSystem()) { continue; } PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps); if (psDisabled != null) { ps = psDisabled; } } if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } final PackageInfo pi = generatePackageInfo(ps, flags, userId); if (pi != null) { list.add(pi); } } } else { list = new ArrayList<>(mPackages.size()); for (AndroidPackage p : mPackages.values()) { PackageSetting ps = getPackageSetting(p.getPackageName()); if (listFactory) { if (!p.isSystem()) { continue; } PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps); if (psDisabled != null) { ps = psDisabled; } } if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } final PackageInfo pi = generatePackageInfo(ps, flags, userId); if (pi != null) { list.add(pi); } } } if (listApex) { if (listFactory) { list.addAll(mApexManager.getFactoryPackages()); } else { list.addAll(mApexManager.getActivePackages()); } if (listUninstalled) { list.addAll(mApexManager.getInactivePackages()); } } return new ParceledListSlice<>(list); } /** * If the filter's target user can handle the intent and is enabled: a [ResolveInfo] that * will forward the intent to the filter's target user, along with the highest approval of * any handler in the target user. Otherwise, returns null. */ @Nullable private CrossProfileDomainInfo createForwardingResolveInfo( @NonNull CrossProfileIntentFilter filter, @NonNull Intent intent, @Nullable String resolvedType, int flags, int sourceUserId) { int targetUserId = filter.getTargetUserId(); if (!isUserEnabled(targetUserId)) { return null; } List resultTargetUser = mComponentResolver.queryActivities(intent, resolvedType, flags, targetUserId); if (CollectionUtils.isEmpty(resultTargetUser)) { return null; } ResolveInfo forwardingInfo = null; for (int i = resultTargetUser.size() - 1; i >= 0; i--) { ResolveInfo targetUserResolveInfo = resultTargetUser.get(i); if ((targetUserResolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) == 0) { forwardingInfo = createForwardingResolveInfoUnchecked(filter, sourceUserId, targetUserId); break; } } if (forwardingInfo == null) { // If all the matches in the target profile are suspended, return null. return null; } int highestApprovalLevel = DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE; int size = resultTargetUser.size(); for (int i = 0; i < size; i++) { ResolveInfo riTargetUser = resultTargetUser.get(i); if (riTargetUser.handleAllWebDataURI) { continue; } String packageName = riTargetUser.activityInfo.packageName; PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { continue; } highestApprovalLevel = Math.max(highestApprovalLevel, mDomainVerificationManager .approvalLevelForDomain(ps, intent, flags, targetUserId)); } return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel); } public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, int sourceUserId, int targetUserId) { ResolveInfo forwardingResolveInfo = new ResolveInfo(); final long ident = Binder.clearCallingIdentity(); boolean targetIsProfile; try { targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile(); } finally { Binder.restoreCallingIdentity(ident); } String className; if (targetIsProfile) { className = FORWARD_INTENT_TO_MANAGED_PROFILE; } else { className = FORWARD_INTENT_TO_PARENT; } ComponentName forwardingActivityComponentName = new ComponentName( androidApplication().packageName, className); ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0, sourceUserId); if (!targetIsProfile) { forwardingActivityInfo.showUserIcon = targetUserId; forwardingResolveInfo.noResourceId = true; } forwardingResolveInfo.activityInfo = forwardingActivityInfo; forwardingResolveInfo.priority = 0; forwardingResolveInfo.preferredOrder = 0; forwardingResolveInfo.match = 0; forwardingResolveInfo.isDefault = true; forwardingResolveInfo.filter = new IntentFilter(filter.getIntentFilter()); forwardingResolveInfo.targetUserId = targetUserId; return forwardingResolveInfo; } // Return matching ResolveInfo in target user if any. @Nullable private CrossProfileDomainInfo queryCrossProfileIntents( List matchingFilters, Intent intent, String resolvedType, int flags, int sourceUserId, boolean matchInCurrentProfile) { if (matchingFilters == null) { return null; } // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and // match the same intent. For performance reasons, it is better not to // run queryIntent twice for the same userId SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray(); CrossProfileDomainInfo resultInfo = null; int size = matchingFilters.size(); for (int i = 0; i < size; i++) { CrossProfileIntentFilter filter = matchingFilters.get(i); int targetUserId = filter.getTargetUserId(); boolean skipCurrentProfile = (filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0; boolean skipCurrentProfileIfNoMatchFound = (filter.getFlags() & PackageManager.ONLY_IF_NO_MATCH_FOUND) != 0; if (!skipCurrentProfile && !alreadyTriedUserIds.get(targetUserId) && (!skipCurrentProfileIfNoMatchFound || !matchInCurrentProfile)) { // Checking if there are activities in the target user that can handle the // intent. CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent, resolvedType, flags, sourceUserId); if (info != null) { resultInfo = info; break; } alreadyTriedUserIds.put(targetUserId, true); } } if (resultInfo == null) { return null; } ResolveInfo forwardingResolveInfo = resultInfo.resolveInfo; if (!isUserEnabled(forwardingResolveInfo.targetUserId)) { return null; } List filteredResult = filterIfNotSystemUser(Collections.singletonList(forwardingResolveInfo), sourceUserId); if (filteredResult.isEmpty()) { return null; } return resultInfo; } private ResolveInfo querySkipCurrentProfileIntents( List matchingFilters, Intent intent, String resolvedType, int flags, int sourceUserId) { if (matchingFilters != null) { int size = matchingFilters.size(); for (int i = 0; i < size; i ++) { CrossProfileIntentFilter filter = matchingFilters.get(i); if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) { // Checking if there are activities in the target user that can handle the // intent. CrossProfileDomainInfo info = createForwardingResolveInfo(filter, intent, resolvedType, flags, sourceUserId); if (info != null) { return info.resolveInfo; } } } } return null; } public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId); enforceCrossUserOrProfilePermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get service info"); return getServiceInfoBody(component, flags, userId, callingUid); } protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId, int callingUid) { ParsedService s = mComponentResolver.getService(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); if (s == null) { return null; } AndroidPackage pkg = mPackages.get(s.getPackageName()); if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) { PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_SERVICE, userId)) { return null; } return PackageInfoUtils.generateServiceInfo(pkg, s, flags, ps.readUserState(userId), userId, ps); } return null; } @Nullable public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) { return getSharedLibraryInfo(name, version, mSharedLibraries, null); } /** * Returns the package name of the calling Uid if it's an instant app. If it isn't * instant, returns {@code null}. */ public String getInstantAppPackageName(int callingUid) { // If the caller is an isolated app use the owner's uid for the lookup. if (Process.isIsolated(callingUid)) { callingUid = getIsolatedOwner(callingUid); } final int appId = UserHandle.getAppId(callingUid); final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); return isInstantApp ? ps.pkg.getPackageName() : null; } return null; } /** * Finds the owner for the provided isolated UID. Throws IllegalStateException if no such * isolated UID is found. */ private int getIsolatedOwner(int isolatedUid) { final int ownerUid = mIsolatedOwners.get(isolatedUid, -1); if (ownerUid == -1) { throw new IllegalStateException( "No owner UID found for isolated UID " + isolatedUid); } return ownerUid; } public final String resolveExternalPackageNameLPr(AndroidPackage pkg) { if (pkg.getStaticSharedLibName() != null) { return pkg.getManifestPackageName(); } return pkg.getPackageName(); } private String resolveInternalPackageNameInternalLocked( String packageName, long versionCode, int callingUid) { // Handle renamed packages String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName); packageName = normalizedPackageName != null ? normalizedPackageName : packageName; // Is this a static library? WatchedLongSparseArray versionedLib = mStaticLibsByDeclaringPackage.get(packageName); if (versionedLib == null || versionedLib.size() <= 0) { return packageName; } // Figure out which lib versions the caller can see LongSparseLongArray versionsCallerCanSee = null; final int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID && callingAppId != Process.ROOT_UID) { versionsCallerCanSee = new LongSparseLongArray(); String libName = versionedLib.valueAt(0).getName(); String[] uidPackages = getPackagesForUidInternal(callingUid, callingUid); if (uidPackages != null) { for (String uidPackage : uidPackages) { PackageSetting ps = mSettings.getPackageLPr(uidPackage); final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName); if (libIdx >= 0) { final long libVersion = ps.usesStaticLibrariesVersions[libIdx]; versionsCallerCanSee.append(libVersion, libVersion); } } } } // Caller can see nothing - done if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) { return packageName; } // Find the version the caller can see and the app version code SharedLibraryInfo highestVersion = null; final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { SharedLibraryInfo libraryInfo = versionedLib.valueAt(i); if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey( libraryInfo.getLongVersion()) < 0) { continue; } final long libVersionCode = libraryInfo.getDeclaringPackage().getLongVersionCode(); if (versionCode != PackageManager.VERSION_CODE_HIGHEST) { if (libVersionCode == versionCode) { return libraryInfo.getPackageName(); } } else if (highestVersion == null) { highestVersion = libraryInfo; } else if (libVersionCode > highestVersion .getDeclaringPackage().getLongVersionCode()) { highestVersion = libraryInfo; } } if (highestVersion != null) { return highestVersion.getPackageName(); } return packageName; } public final String resolveInternalPackageNameLPr(String packageName, long versionCode) { final int callingUid = Binder.getCallingUid(); return resolveInternalPackageNameInternalLocked(packageName, versionCode, callingUid); } /** * IMPORTANT: Not all packages returned by this method may be known * to the system. There are two conditions in which this may occur: *

      *
    1. The package is on adoptable storage and the device has been removed
    2. *
    3. The package is being removed and the internal structures are partially updated
    4. *
    * The second is an artifact of the current data structures and should be fixed. See * b/111075456 for one such instance. * This binder API is cached. If the algorithm in this method changes, * or if the underlying objecs (as returned by getSettingLPr()) change * then the logic that invalidates the cache must be revisited. See * calls to invalidateGetPackagesForUidCache() to locate the points at * which the cache is invalidated. */ public final String[] getPackagesForUid(int uid) { return getPackagesForUidInternal(uid, Binder.getCallingUid()); } private String[] getPackagesForUidInternal(int uid, int callingUid) { final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; final int userId = UserHandle.getUserId(uid); final int appId = UserHandle.getAppId(uid); return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp); } protected String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId, boolean isCallerInstantApp) { // reader final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { return null; } final SharedUserSetting sus = (SharedUserSetting) obj; final int N = sus.packages.size(); String[] res = new String[N]; int i = 0; for (int index = 0; index < N; index++) { final PackageSetting ps = sus.packages.valueAt(index); if (ps.getInstalled(userId) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { res[i++] = ps.name; } } return ArrayUtils.trimToSize(res, i); } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (ps.getInstalled(userId) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { return new String[]{ps.name}; } } return null; } public final UserInfo getProfileParent(int userId) { final long identity = Binder.clearCallingIdentity(); try { return mUserManager.getProfileParent(userId); } finally { Binder.restoreCallingIdentity(identity); } } /** * Returns whether or not instant apps have been disabled remotely. */ private boolean areWebInstantAppsDisabled(int userId) { return mWebInstantAppsDisabled.get(userId); } /** * Returns whether or not a full application can see an instant application. *

    * Currently, there are four cases in which this can occur: *

      *
    1. The calling application is a "special" process. Special processes * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.
    2. *
    3. The calling application has the permission * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.
    4. *
    5. The calling application is the default launcher on the * system partition.
    6. *
    7. The calling application is the default app prediction service.
    8. *
    */ public final boolean canViewInstantApps(int callingUid, int userId) { if (callingUid < Process.FIRST_APPLICATION_UID) { return true; } if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED) { return true; } if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.VIEW_INSTANT_APPS) == PERMISSION_GRANTED) { final ComponentName homeComponent = getDefaultHomeActivity(userId); if (homeComponent != null && isCallerSameApp(homeComponent.getPackageName(), callingUid)) { return true; } // TODO(b/122900055) Change/Remove this and replace with new permission role. if (mAppPredictionServicePackage != null && isCallerSameApp(mAppPredictionServicePackage, callingUid)) { return true; } } return false; } public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags) { // Callers can access only the libs they depend on, otherwise they need to explicitly // ask for the shared libraries given the caller is allowed to access all static libs. if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) { // System/shell/root get to see all static libs final int appId = UserHandle.getAppId(uid); if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID || appId == Process.ROOT_UID) { return false; } // Installer gets to see all static libs. if (PackageManager.PERMISSION_GRANTED == checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) { return false; } } // No package means no static lib as it is always on internal storage if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) { return false; } final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion()); if (libraryInfo == null) { return false; } final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); final String[] uidPackageNames = getPackagesForUid(resolvedUid); if (uidPackageNames == null) { return true; } for (String uidPackageName : uidPackageNames) { if (ps.name.equals(uidPackageName)) { return false; } PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName); if (uidPs != null) { final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries, libraryInfo.getName()); if (index < 0) { continue; } if (uidPs.pkg.getUsesStaticLibrariesVersions()[index] == libraryInfo.getLongVersion()) { return false; } } } return true; } private boolean hasCrossUserPermission( int callingUid, int callingUserId, int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) { if (!requirePermissionWhenSameUser && userId == callingUserId) { return true; } if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) { return true; } if (requireFullPermission) { return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL); } return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS); } /** * @param resolveInfos list of resolve infos in descending priority order * @return if the list contains a resolve info with non-negative priority */ private boolean hasNonNegativePriority(List resolveInfos) { return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0; } private boolean hasPermission(String permission) { return mContext.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; } public final boolean isCallerSameApp(String packageName, int uid) { AndroidPackage pkg = mPackages.get(packageName); return pkg != null && UserHandle.getAppId(uid) == pkg.getUid(); } public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) { return true; } if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) { return true; } if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) { return true; } return false; } public final boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { final ParsedActivity activity = mComponentResolver.getActivity(component); if (activity == null) { return false; } final boolean visibleToInstantApp = (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { final ParsedActivity activity = mComponentResolver.getReceiver(component); if (activity == null) { return false; } final boolean visibleToInstantApp = (activity.getFlags() & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = (activity.getFlags() & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { final ParsedService service = mComponentResolver.getService(component); return service != null && (service.getFlags() & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; } else if (type == TYPE_PROVIDER) { final ParsedProvider provider = mComponentResolver.getProvider(component); return provider != null && (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; } else if (type == TYPE_UNKNOWN) { return isComponentVisibleToInstantApp(component); } return false; } /** * From Android R, * camera intents have to match system apps. The only exception to this is if * the DPC has set the camera persistent preferred activity. This case was introduced * because it is important that the DPC has the ability to set both system and non-system * camera persistent preferred activities. * * @return {@code true} if the intent is a camera intent and the persistent preferred * activity was not set by the DPC. */ public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, String resolvedType, int flags) { return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm( intent, userId, resolvedType, flags); } public final boolean isInstantApp(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "isInstantApp"); return isInstantAppInternal(packageName, userId, callingUid); } public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid) { if (HIDE_EPHEMERAL_APIS) { return false; } return isInstantAppInternalBody(packageName, userId, callingUid); } protected boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid) { if (Process.isIsolated(callingUid)) { callingUid = getIsolatedOwner(callingUid); } final PackageSetting ps = mSettings.getPackageLPr(packageName); final boolean returnAllowed = ps != null && (isCallerSameApp(packageName, callingUid) || canViewInstantApps(callingUid, userId) || mInstantAppRegistry.isInstantAccessGranted( userId, UserHandle.getAppId(callingUid), ps.appId)); if (returnAllowed) { return ps.getInstantApp(userId); } return false; } private boolean isInstantAppResolutionAllowed( Intent intent, List resolvedActivities, int userId, boolean skipPackageCheck, int flags) { if (mInstantAppResolverConnection == null) { return false; } if (instantAppInstallerActivity() == null) { return false; } if (intent.getComponent() != null) { return false; } if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) { return false; } if (!skipPackageCheck && intent.getPackage() != null) { return false; } if (!intent.isWebIntent()) { // for non web intents, we should not resolve externally if an app already exists to // handle it or if the caller didn't explicitly request it. if ((resolvedActivities != null && resolvedActivities.size() != 0) || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) { return false; } } else { if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) { return false; } else if (areWebInstantAppsDisabled(userId)) { return false; } } // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution. // Or if there's already an ephemeral app installed that handles the action return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId, skipPackageCheck, flags); } // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution. // Or if there's already an ephemeral app installed that handles the action protected boolean isInstantAppResolutionAllowedBody( Intent intent, List resolvedActivities, int userId, boolean skipPackageCheck, int flags) { final int count = (resolvedActivities == null ? 0 : resolvedActivities.size()); for (int n = 0; n < count; n++) { final ResolveInfo info = resolvedActivities.get(n); final String packageName = info.activityInfo.packageName; final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { // only check domain verification status if the app is not a browser if (!info.handleAllWebDataURI) { if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags, userId)) { if (DEBUG_INSTANT) { Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName + ", approved"); } return false; } } if (ps.getInstantApp(userId)) { if (DEBUG_INSTANT) { Slog.v(TAG, "DENY instant app installed;" + " pkg: " + packageName); } return false; } } } // We've exhausted all ways to deny ephemeral application; let the system look for them. return true; } private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId, String resolvedType, int flags) { PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); //TODO(b/158003772): Remove double query List pprefs = ppir != null ? ppir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) : new ArrayList<>(); for (PersistentPreferredActivity ppa : pprefs) { if (ppa.mIsSetByDpm) { return true; } } return false; } private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) { if (!mInjector.getLocalService(ActivityTaskManagerInternal.class) .isCallerRecents(callingUid)) { return false; } final long token = Binder.clearCallingIdentity(); try { final int callingUserId = UserHandle.getUserId(callingUid); if (ActivityManager.getCurrentUser() != callingUserId) { return false; } return mUserManager.isSameProfileGroup(callingUserId, targetUserId); } finally { Binder.restoreCallingIdentity(token); } } public final boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { final long identity = Binder.clearCallingIdentity(); try { return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId); } finally { Binder.restoreCallingIdentity(identity); } } private boolean isUserEnabled(int userId) { final long callingId = Binder.clearCallingIdentity(); try { UserInfo userInfo = mUserManager.getUserInfo(userId); return userInfo != null && userInfo.isEnabled(); } finally { Binder.restoreCallingIdentity(callingId); } } /** * Returns whether or not access to the application should be filtered. *

    * Access may be limited based upon whether the calling or target applications * are instant applications. * * @see #canViewInstantApps(int, int) */ public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId) { // if we're in an isolated process, get the real calling UID if (Process.isIsolated(callingUid)) { callingUid = getIsolatedOwner(callingUid); } final String instantAppPkgName = getInstantAppPackageName(callingUid); final boolean callerIsInstantApp = instantAppPkgName != null; if (ps == null) { if (callerIsInstantApp) { // pretend the application exists, but, needs to be filtered return true; } return false; } // if the target and caller are the same application, don't filter if (isCallerSameApp(ps.name, callingUid)) { return false; } if (callerIsInstantApp) { // both caller and target are both instant, but, different applications, filter if (ps.getInstantApp(userId)) { return true; } // request for a specific component; if it hasn't been explicitly exposed through // property or instrumentation target, filter if (component != null) { final ParsedInstrumentation instrumentation = mInstrumentation.get(component); if (instrumentation != null && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) { return false; } return !isComponentVisibleToInstantApp(component, componentType); } // request for application; if no components have been explicitly exposed, filter return !ps.pkg.isVisibleToInstantApps(); } if (ps.getInstantApp(userId)) { // caller can see all components of all instant applications, don't filter if (canViewInstantApps(callingUid, userId)) { return false; } // request for a specific instant application component, filter if (component != null) { return true; } // request for an instant application; if the caller hasn't been granted access, //filter return !mInstantAppRegistry.isInstantAccessGranted( userId, UserHandle.getAppId(callingUid), ps.appId); } int appId = UserHandle.getAppId(callingUid); final SettingBase callingPs = mSettings.getSettingLPr(appId); return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId); } /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ public final boolean shouldFilterApplicationLocked( @Nullable PackageSetting ps, int callingUid, int userId) { return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId); } /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, int userId) { boolean filterApp = true; for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) { filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index), callingUid, /* component */ null, TYPE_UNKNOWN, userId); } return filterApp; } /** * Verification statuses are ordered from the worse to the best, except for * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse. */ private int bestDomainVerificationStatus(int status1, int status2) { if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status2; } if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status1; } return (int) MathUtils.max(status1, status2); } // NOTE: Can't remove without a major refactor. Keep around for now. public final int checkUidPermission(String permName, int uid) { return mPermissionManager.checkUidPermission(uid, permName); } public int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { // reader final AndroidPackage p = mPackages.get(packageName); if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return -1; } return UserHandle.getUid(userId, p.getUid()); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && ps.isMatch(flags) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { return UserHandle.getUid(userId, ps.appId); } } return -1; } /** * Update given flags based on encryption status of current user. */ private int updateFlags(int flags, int userId) { if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) { // Caller expressed an explicit opinion about what encryption // aware/unaware components they want to see, so fall through and // give them what they want } else { final UserManagerInternal umInternal = mInjector.getUserManagerInternal(); // Caller expressed no opinion, so match based on user state if (umInternal.isUserUnlockingOrUnlocked(userId)) { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; } else { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE; } } return flags; } /** * Update given flags when being used to request {@link ApplicationInfo}. */ public final int updateFlagsForApplication(int flags, int userId) { return updateFlagsForPackage(flags, userId); } /** * Update given flags when being used to request {@link ComponentInfo}. */ public final int updateFlagsForComponent(int flags, int userId) { return updateFlags(flags, userId); } /** * Update given flags when being used to request {@link PackageInfo}. */ public final int updateFlagsForPackage(int flags, int userId) { final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM; if ((flags & PackageManager.MATCH_ANY_USER) != 0) { // require the permission to be held; the calling uid and given user id referring // to the same user is not sufficient enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId), "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission"); } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser && mUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) { // If the caller wants all packages and has a restricted profile associated with it, // then match all users. This is to make sure that launchers that need to access //work // profile apps don't start breaking. TODO: Remove this hack when launchers stop //using // MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380 flags |= PackageManager.MATCH_ANY_USER; } return updateFlags(flags, userId); } /** * Update given flags when being used to request {@link ResolveInfo}. *

    Instant apps are resolved specially, depending upon context. Minimally, * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT} * flag set. However, this flag is only honoured in three circumstances: *

      *
    • when called from a system process
    • *
    • when the caller holds the permission {@code * android.permission.ACCESS_INSTANT_APPS}
    • *
    • when resolution occurs to start an activity with a {@code android.intent.action.VIEW} * action and a {@code android.intent.category.BROWSABLE} category
    • *
    */ public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { return updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, false /*onlyExposedExplicitly*/, isImplicitImageCaptureIntentAndNotSetByDpc); } public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { // Safe mode means we shouldn't match any third-party components if (safeMode() || isImplicitImageCaptureIntentAndNotSetByDpc) { flags |= PackageManager.MATCH_SYSTEM_ONLY; } if (getInstantAppPackageName(callingUid) != null) { // But, ephemeral apps see both ephemeral and exposed, non-ephemeral components if (onlyExposedExplicitly) { flags |= PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY; } flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY; flags |= PackageManager.MATCH_INSTANT; } else { final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0; final boolean allowMatchInstant = wantInstantApps || (wantMatchInstant && canViewInstantApps(callingUid, userId)); flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY | PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY); if (!allowMatchInstant) { flags &= ~PackageManager.MATCH_INSTANT; } } return updateFlagsForComponent(flags, userId); } /** * Checks if the request is from the system or an app that has the appropriate cross-user * permissions defined as follows: *
      *
    • INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.
    • *
    • INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group * to the caller.
    • *
    • Otherwise, * INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile * group as the caller.
    • *
    * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { if (userId < 0) { throw new IllegalArgumentException("Invalid userId " + userId); } if (checkShell) { PackageManagerServiceUtils.enforceShellRestriction( mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId); } final int callingUserId = UserHandle.getUserId(callingUid); if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission, /*requirePermissionWhenSameUser= */ false)) { return; } final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId); if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight( mContext, android.Manifest.permission.INTERACT_ACROSS_PROFILES, PermissionChecker.PID_UNKNOWN, callingUid, getPackage(callingUid).getPackageName()) == PermissionChecker.PERMISSION_GRANTED) { return; } String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage( callingUid, userId, message, requireFullPermission, isSameProfileGroup); Slog.w(TAG, errorMessage); throw new SecurityException(errorMessage); } /** * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller. * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false, message); } /** * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller. * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param requirePermissionWhenSameUser When {@code true}, still require the cross user * permission to be held even if the callingUid and * userId * reference the same user. * @param message the message to log on security exception */ public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message) { if (userId < 0) { throw new IllegalArgumentException("Invalid userId " + userId); } if (checkShell) { PackageManagerServiceUtils.enforceShellRestriction( mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId); } final int callingUserId = UserHandle.getUserId(callingUid); if (hasCrossUserPermission( callingUid, callingUserId, userId, requireFullPermission, requirePermissionWhenSameUser)) { return; } String errorMessage = buildInvalidCrossUserPermissionMessage( callingUid, userId, message, requireFullPermission); Slog.w(TAG, errorMessage); throw new SecurityException(errorMessage); } public SigningDetails getSigningDetails(@NonNull String packageName) { AndroidPackage p = mPackages.get(packageName); if (p == null) { return null; } return p.getSigningDetails(); } public SigningDetails getSigningDetails(int uid) { final int appId = UserHandle.getAppId(uid); final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { return ((SharedUserSetting) obj).signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; return ps.signatures.mSigningDetails; } } return SigningDetails.UNKNOWN; } public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { PackageSetting ps = getPackageSetting(pkg.getPackageName()); return shouldFilterApplicationLocked(ps, callingUid, userId); } public boolean filterAppAccess(String packageName, int callingUid, int userId) { PackageSetting ps = getPackageSetting(packageName); return shouldFilterApplicationLocked(ps, callingUid, userId); } public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { final String packageName = dumpState.getTargetPackageName(); final boolean checkin = dumpState.isCheckIn(); switch (type) { case DumpState.DUMP_VERSION: { if (dumpState.onTitlePrinted()) { pw.println(); } pw.println("Database versions:"); mSettings.dumpVersionLPr(new IndentingPrintWriter(pw, " ")); break; } case DumpState.DUMP_LIBS: { boolean printedHeader = false; final int numSharedLibraries = mSharedLibraries.size(); for (int index = 0; index < numSharedLibraries; index++) { final String libName = mSharedLibraries.keyAt(index); final WatchedLongSparseArray versionedLib = mSharedLibraries.get(libName); if (versionedLib == null) { continue; } final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { SharedLibraryInfo libraryInfo = versionedLib.valueAt(i); if (!checkin) { if (!printedHeader) { if (dumpState.onTitlePrinted()) { pw.println(); } pw.println("Libraries:"); printedHeader = true; } pw.print(" "); } else { pw.print("lib,"); } pw.print(libraryInfo.getName()); if (libraryInfo.isStatic()) { pw.print(" version=" + libraryInfo.getLongVersion()); } if (!checkin) { pw.print(" -> "); } if (libraryInfo.getPath() != null) { if (libraryInfo.isNative()) { pw.print(" (so) "); } else { pw.print(" (jar) "); } pw.print(libraryInfo.getPath()); } else { pw.print(" (apk) "); pw.print(libraryInfo.getPackageName()); } pw.println(); } } break; } case DumpState.DUMP_PREFERRED: mSettings.dumpPreferred(pw, dumpState, packageName); break; case DumpState.DUMP_PREFERRED_XML: { pw.flush(); FileOutputStream fout = new FileOutputStream(fd); BufferedOutputStream str = new BufferedOutputStream(fout); TypedXmlSerializer serializer = Xml.newFastSerializer(); try { serializer.setOutput(str, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.setFeature( "http://xmlpull.org/v1/doc/features.html#indent-output", true); mSettings.writePreferredActivitiesLPr(serializer, 0, dumpState.isFullPreferred()); serializer.endDocument(); serializer.flush(); } catch (IllegalArgumentException e) { pw.println("Failed writing: " + e); } catch (IllegalStateException e) { pw.println("Failed writing: " + e); } catch (IOException e) { pw.println("Failed writing: " + e); } break; } case DumpState.DUMP_QUERIES: { final PackageSetting setting = mSettings.getPackageLPr(packageName); Integer filteringAppId = setting == null ? null : setting.appId; mAppsFilter.dumpQueries( pw, filteringAppId, dumpState, mUserManager.getUserIds(), this::getPackagesForUidInternalBody); break; } case DumpState.DUMP_DOMAIN_PREFERRED: { final android.util.IndentingPrintWriter writer = new android.util.IndentingPrintWriter(pw); if (dumpState.onTitlePrinted()) pw.println(); writer.println("Domain verification status:"); writer.increaseIndent(); try { mDomainVerificationManager.printState(writer, packageName, UserHandle.USER_ALL, mSettings::getPackageLPr); } catch (Exception e) { pw.println("Failure printing domain verification information"); Slog.e(TAG, "Failure printing domain verification information", e); } writer.decreaseIndent(); break; } case DumpState.DUMP_DEXOPT: { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.println(); ipw.println("Dexopt state:"); ipw.increaseIndent(); Collection pkgSettings; if (packageName != null) { PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName); if (targetPkgSetting != null) { pkgSettings = Collections.singletonList(targetPkgSetting); } else { ipw.println("Unable to find package: " + packageName); return; } } else { pkgSettings = mSettings.getPackagesLocked().values(); } for (PackageSetting pkgSetting : pkgSettings) { final AndroidPackage pkg = pkgSetting.getPkg(); if (pkg == null) { continue; } ipw.println("[" + pkgSetting.name + "]"); ipw.increaseIndent(); mPackageDexOptimizer.dumpDexoptState(ipw, pkg, pkgSetting, mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName())); ipw.decreaseIndent(); } break; } case DumpState.DUMP_COMPILER_STATS: { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.println(); ipw.println("Compiler stats:"); ipw.increaseIndent(); Collection packages; if (packageName != null) { AndroidPackage targetPackage = mPackages.get(packageName); if (targetPackage != null) { packages = Collections.singletonList(targetPackage); } else { ipw.println("Unable to find package: " + packageName); return; } } else { packages = mPackages.values(); } for (AndroidPackage pkg : packages) { final String pkgName = pkg.getPackageName(); ipw.println("[" + pkgName + "]"); ipw.increaseIndent(); CompilerStats.PackageStats stats = mCompilerStats.getPackageStats(pkgName); if (stats == null) { ipw.println("(No recorded stats)"); } else { stats.dump(ipw); } ipw.decreaseIndent(); } break; } } // switch } // The body of findPreferredActivity. protected FindPreferredActivityBodyResult findPreferredActivityBody( Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, int callingUid, boolean isDeviceProvisioned) { FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); flags = updateFlagsForResolve( flags, userId, callingUid, false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); intent = updateIntentForResolve(intent); // Try to find a matching persistent preferred activity. result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, resolvedType, flags, query, debug, userId); // If a persistent preferred activity matched, use it. if (result.mPreferredResolveInfo != null) { return result; } PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); // Get the list of preferred activities that handle the intent if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); List prefs = pir != null ? pir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) : null; if (prefs != null && prefs.size() > 0) { // First figure out how good the original match set is. // We will only allow preferred activities that came // from the same match quality. int match = 0; if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); final int N = query.size(); for (int j = 0; j < N; j++) { final ResolveInfo ri = query.get(j); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Match for " + ri.activityInfo + ": 0x" + Integer.toHexString(match)); } if (ri.match > match) { match = ri.match; } } if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); } match &= IntentFilter.MATCH_CATEGORY_MASK; final int M = prefs.size(); for (int i = 0; i < M; i++) { final PreferredActivity pa = prefs.get(i); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Checking PreferredActivity ds=" + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "") + "\n component=" + pa.mPref.mComponent); pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } if (pa.mPref.mMatch != match) { if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Skipping bad match " + Integer.toHexString(pa.mPref.mMatch)); } continue; } // If it's not an "always" type preferred activity and that's what we're // looking for, skip it. if (always && !pa.mPref.mAlways) { if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); continue; } final ActivityInfo ai = getActivityInfo( pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found preferred activity:"); if (ai != null) { ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } else { Slog.v(TAG, " null"); } } final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) && !isDeviceProvisioned; final boolean allowSetMutation = !excludeSetupWizardHomeActivity && !queryMayBeFiltered; if (ai == null) { // Do not remove launcher's preferred activity during SetupWizard // due to it may not install yet if (!allowSetMutation) { continue; } // This previously registered preferred activity // component is no longer known. Most likely an update // to the app was installed and in the new version this // component no longer exists. Clean it up by removing // it from the preferred activities list, and skip it. Slog.w(TAG, "Removing dangling preferred activity: " + pa.mPref.mComponent); pir.removeFilter(pa); result.mChanged = true; continue; } for (int j = 0; j < N; j++) { final ResolveInfo ri = query.get(j); if (!ri.activityInfo.applicationInfo.packageName .equals(ai.applicationInfo.packageName)) { continue; } if (!ri.activityInfo.name.equals(ai.name)) { continue; } if (removeMatches && allowSetMutation) { pir.removeFilter(pa); result.mChanged = true; if (DEBUG_PREFERRED) { Slog.v(TAG, "Removing match " + pa.mPref.mComponent); } break; } // Okay we found a previously set preferred or last chosen app. // If the result set is different from when this // was created, and is not a subset of the preferred set, we need to // clear it and re-ask the user their preference, if we're looking for // an "always" type entry. if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { if (allowSetMutation) { // some components of the set are no longer present in // the query, but the preferred activity can still be reused if (DEBUG_PREFERRED) { Slog.i(TAG, "Result set changed, but PreferredActivity" + " is still valid as only non-preferred" + " components were removed for " + intent + " type " + resolvedType); } // remove obsolete components and re-add the up-to-date // filter PreferredActivity freshPa = new PreferredActivity(pa, pa.mPref.mMatch, pa.mPref.discardObsoleteComponents(query), pa.mPref.mComponent, pa.mPref.mAlways); pir.removeFilter(pa); pir.addFilter(freshPa); result.mChanged = true; } else { if (DEBUG_PREFERRED) { Slog.i(TAG, "Do not remove preferred activity"); } } } else { if (allowSetMutation) { Slog.i(TAG, "Result set changed, dropping preferred activity " + "for " + intent + " type " + resolvedType); if (DEBUG_PREFERRED) { Slog.v(TAG, "Removing preferred activity since set changed " + pa.mPref.mComponent); } pir.removeFilter(pa); // Re-add the filter as a "last chosen" entry (!always) PreferredActivity lastChosen = new PreferredActivity( pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false); pir.addFilter(lastChosen); result.mChanged = true; } result.mPreferredResolveInfo = null; return result; } } // Yay! Either the set matched or we're looking for the last chosen if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Returning preferred activity: " + ri.activityInfo.packageName + "/" + ri.activityInfo.name); } result.mPreferredResolveInfo = ri; return result; } } } return result; } public final FindPreferredActivityBodyResult findPreferredActivityInternal( Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { final int callingUid = Binder.getCallingUid(); // Do NOT hold the packages lock; this calls up into the settings provider which // could cause a deadlock. final boolean isDeviceProvisioned = android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; // Find the preferred activity - the lock is held inside the method. return findPreferredActivityBody( intent, resolvedType, flags, query, always, removeMatches, debug, userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); } public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId) { final int N = query.size(); PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); // Get the list of persistent preferred activities that handle the intent if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Looking for persistent preferred activities..."); } List pprefs = ppir != null ? ppir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) : null; if (pprefs != null && pprefs.size() > 0) { final int M = pprefs.size(); for (int i = 0; i < M; i++) { final PersistentPreferredActivity ppa = pprefs.get(i); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Checking PersistentPreferredActivity ds=" + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "") + "\n component=" + ppa.mComponent); ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } final ActivityInfo ai = getActivityInfo(ppa.mComponent, flags | MATCH_DISABLED_COMPONENTS, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found persistent preferred activity:"); if (ai != null) { ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } else { Slog.v(TAG, " null"); } } if (ai == null) { // This previously registered persistent preferred activity // component is no longer known. Ignore it and do NOT remove it. continue; } for (int j = 0; j < N; j++) { final ResolveInfo ri = query.get(j); if (!ri.activityInfo.applicationInfo.packageName .equals(ai.applicationInfo.packageName)) { continue; } if (!ri.activityInfo.name.equals(ai.name)) { continue; } // Found a persistent preference that can handle the intent. if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Returning persistent preferred activity: " + ri.activityInfo.packageName + "/" + ri.activityInfo.name); } return ri; } } } return null; } } /** * This subclass is the external interface to the live computer. Some internal helper * methods are overridden to fetch live data instead of snapshot data. For each * Computer interface that is overridden in this class, the override takes the PM lock * and then delegates to the live computer engine. This is required because there are * no locks taken in the engine itself. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected static class ComputerLocked extends ComputerEngine { private final Object mLock; ComputerLocked(Snapshot args) { super(args); mLock = mService.mLock; } protected final ComponentName resolveComponentName() { return mService.mResolveComponentName; } protected final ActivityInfo instantAppInstallerActivity() { return mService.mInstantAppInstallerActivity; } protected final ApplicationInfo androidApplication() { return mService.mAndroidApplication; } public final @NonNull List queryIntentServicesInternalBody(Intent intent, String resolvedType, int flags, int userId, int callingUid, String instantAppPkgName) { synchronized (mLock) { return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId, callingUid, instantAppPkgName); } } public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName) { synchronized (mLock) { return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName); } } public final ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getActivityInfoInternalBody(component, flags, filterCallingUid, userId); } } public final AndroidPackage getPackage(String packageName) { synchronized (mLock) { return super.getPackage(packageName); } } public final AndroidPackage getPackage(int uid) { synchronized (mLock) { return super.getPackage(uid); } } public final ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId); } } public final ArrayList filterCandidatesWithDomainPreferredActivitiesLPrBody( Intent intent, int matchFlags, List candidates, CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) { synchronized (mLock) { return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent, matchFlags, candidates, xpDomainInfo, userId, debug); } } public final PackageInfo getPackageInfoInternalBody(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid, userId); } } public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) { synchronized (mLock) { return super.getPackageSettingInternal(packageName, callingUid); } } public final ParceledListSlice getInstalledPackagesBody(int flags, int userId, int callingUid) { synchronized (mLock) { return super.getInstalledPackagesBody(flags, userId, callingUid); } } public final ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId, int callingUid) { synchronized (mLock) { return super.getServiceInfoBody(component, flags, userId, callingUid); } } public final String getInstantAppPackageName(int callingUid) { synchronized (mLock) { return super.getInstantAppPackageName(callingUid); } } public final String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId, boolean isCallerInstantApp) { synchronized (mLock) { return super.getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp); } } public final boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid) { synchronized (mLock) { return super.isInstantAppInternalBody(packageName, userId, callingUid); } } public final boolean isInstantAppResolutionAllowedBody(Intent intent, List resolvedActivities, int userId, boolean skipPackageCheck, int flags) { synchronized (mLock) { return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId, skipPackageCheck, flags); } } public final int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { synchronized (mLock) { return super.getPackageUidInternal(packageName, flags, userId, callingUid); } } public final SigningDetails getSigningDetails(@NonNull String packageName) { synchronized (mLock) { return super.getSigningDetails(packageName); } } public final SigningDetails getSigningDetails(int uid) { synchronized (mLock) { return super.getSigningDetails(uid); } } public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { synchronized (mLock) { return super.filterAppAccess(pkg, callingUid, userId); } } public final boolean filterAppAccess(String packageName, int callingUid, int userId) { synchronized (mLock) { return super.filterAppAccess(packageName, callingUid, userId); } } public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { synchronized (mLock) { super.dump(type, fd, pw, dumpState); } } public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, int callingUid, boolean isDeviceProvisioned) { synchronized (mLock) { return super.findPreferredActivityBody(intent, resolvedType, flags, query, always, removeMatches, debug, userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); } } } /** * This subclass delegates to methods in a Computer after reference-counting the computer. */ private static class ComputerTracker implements Computer { // The number of times a thread reused a computer in its stack instead of fetching // a snapshot computer. private final AtomicInteger mReusedSnapshot = new AtomicInteger(0); // The number of times a thread reused a computer in its stack instead of fetching // a live computer. private final AtomicInteger mReusedLive = new AtomicInteger(0); private PackageManagerService mService; ComputerTracker(PackageManagerService s) { mService = s; } private ThreadComputer live() { ThreadComputer current = mService.sThreadComputer.get(); if (current.mRefCount > 0) { current.acquire(); mReusedLive.incrementAndGet(); } else { current.acquire(mService.liveComputer()); } return current; } private ThreadComputer snapshot() { ThreadComputer current = mService.sThreadComputer.get(); if (current.mRefCount > 0) { current.acquire(); mReusedSnapshot.incrementAndGet(); } else { current.acquire(mService.snapshotComputer()); } return current; } public final @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { ThreadComputer current = snapshot(); try { return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags, privateResolveFlags, filterCallingUid, userId, resolveForStart, allowDynamicSplits); } finally { current.release(); } } public final @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags, userId); } finally { current.release(); } } public final @NonNull List queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps) { ThreadComputer current = snapshot(); try { return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid, includeInstantApps); } finally { current.release(); } } public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName) { ThreadComputer current = live(); try { return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName); } finally { current.release(); } } public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.getActivityInfo(component, flags, userId); } finally { current.release(); } } public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid, userId); } finally { current.release(); } } public final AndroidPackage getPackage(String packageName) { ThreadComputer current = snapshot(); try { return current.mComputer.getPackage(packageName); } finally { current.release(); } } public final AndroidPackage getPackage(int uid) { ThreadComputer current = snapshot(); try { return current.mComputer.getPackage(uid); } finally { current.release(); } } public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags, filterCallingUid, userId); } finally { current.release(); } } public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.getApplicationInfo(packageName, flags, userId); } finally { current.release(); } } public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.getApplicationInfoInternal(packageName, flags, filterCallingUid, userId); } finally { current.release(); } } public final ComponentName getDefaultHomeActivity(int userId) { ThreadComputer current = live(); try { return current.mComputer.getDefaultHomeActivity(userId); } finally { current.release(); } } public final ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId) { ThreadComputer current = live(); try { return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId); } finally { current.release(); } } public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { ThreadComputer current = live(); try { return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, sourceUserId, parentUserId); } finally { current.release(); } } public final Intent getHomeIntent() { ThreadComputer current = live(); try { return current.mComputer.getHomeIntent(); } finally { current.release(); } } public final List getMatchingCrossProfileIntentFilters( Intent intent, String resolvedType, int userId) { ThreadComputer current = live(); try { return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); } finally { current.release(); } } public final List applyPostResolutionFilter( @NonNull List resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { ThreadComputer current = live(); try { return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); } finally { current.release(); } } public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { ThreadComputer current = live(); try { return current.mComputer.generatePackageInfo(ps, flags, userId); } finally { current.release(); } } public final PackageInfo getPackageInfo(String packageName, int flags, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.getPackageInfo(packageName, flags, userId); } finally { current.release(); } } public final PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags, filterCallingUid, userId); } finally { current.release(); } } public final PackageSetting getPackageSetting(String packageName) { ThreadComputer current = snapshot(); try { return current.mComputer.getPackageSetting(packageName); } finally { current.release(); } } public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) { ThreadComputer current = live(); try { return current.mComputer.getPackageSettingInternal(packageName, callingUid); } finally { current.release(); } } public final ParceledListSlice getInstalledPackages(int flags, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.getInstalledPackages(flags, userId); } finally { current.release(); } } public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, int sourceUserId, int targetUserId) { ThreadComputer current = live(); try { return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId, targetUserId); } finally { current.release(); } } public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { ThreadComputer current = live(); try { return current.mComputer.getServiceInfo(component, flags, userId); } finally { current.release(); } } public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) { ThreadComputer current = live(); try { return current.mComputer.getSharedLibraryInfoLPr(name, version); } finally { current.release(); } } public final SigningDetails getSigningDetails(@NonNull String packageName) { ThreadComputer current = snapshot(); try { return current.mComputer.getSigningDetails(packageName); } finally { current.release(); } } public final SigningDetails getSigningDetails(int uid) { ThreadComputer current = snapshot(); try { return current.mComputer.getSigningDetails(uid); } finally { current.release(); } } public final String getInstantAppPackageName(int callingUid) { ThreadComputer current = snapshot(); try { return current.mComputer.getInstantAppPackageName(callingUid); } finally { current.release(); } } public final String resolveExternalPackageNameLPr(AndroidPackage pkg) { ThreadComputer current = live(); try { return current.mComputer.resolveExternalPackageNameLPr(pkg); } finally { current.release(); } } public final String resolveInternalPackageNameLPr(String packageName, long versionCode) { ThreadComputer current = live(); try { return current.mComputer.resolveInternalPackageNameLPr(packageName, versionCode); } finally { current.release(); } } public final String[] getPackagesForUid(int uid) { ThreadComputer current = snapshot(); try { return current.mComputer.getPackagesForUid(uid); } finally { current.release(); } } public final UserInfo getProfileParent(int userId) { ThreadComputer current = live(); try { return current.mComputer.getProfileParent(userId); } finally { current.release(); } } public final boolean canViewInstantApps(int callingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.canViewInstantApps(callingUid, userId); } finally { current.release(); } } public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.filterAppAccess(pkg, callingUid, userId); } finally { current.release(); } } public final boolean filterAppAccess(String packageName, int callingUid, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.filterAppAccess(packageName, callingUid, userId); } finally { current.release(); } } public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags) { ThreadComputer current = live(); try { return current.mComputer.filterSharedLibPackageLPr(ps, uid, userId, flags); } finally { current.release(); } } public final boolean isCallerSameApp(String packageName, int uid) { ThreadComputer current = live(); try { return current.mComputer.isCallerSameApp(packageName, uid); } finally { current.release(); } } public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { ThreadComputer current = live(); try { return current.mComputer.isComponentVisibleToInstantApp(component); } finally { current.release(); } } public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component, @ComponentType int type) { ThreadComputer current = live(); try { return current.mComputer.isComponentVisibleToInstantApp(component, type); } finally { current.release(); } } public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, String resolvedType, int flags) { ThreadComputer current = live(); try { return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags); } finally { current.release(); } } public final boolean isInstantApp(String packageName, int userId) { ThreadComputer current = snapshot(); try { return current.mComputer.isInstantApp(packageName, userId); } finally { current.release(); } } public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid) { ThreadComputer current = live(); try { return current.mComputer.isInstantAppInternal(packageName, userId, callingUid); } finally { current.release(); } } public final boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { ThreadComputer current = live(); try { return current.mComputer.isSameProfileGroup(callerUserId, userId); } finally { current.release(); } } public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.shouldFilterApplicationLocked(sus, callingUid, userId); } finally { current.release(); } } public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId) { ThreadComputer current = live(); try { return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, component, componentType, userId); } finally { current.release(); } } public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, int userId) { ThreadComputer current = live(); try { return current.mComputer.shouldFilterApplicationLocked(ps, callingUid, userId); } finally { current.release(); } } public final int checkUidPermission(String permName, int uid) { ThreadComputer current = snapshot(); try { return current.mComputer.checkUidPermission(permName, uid); } finally { current.release(); } } public final int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { ThreadComputer current = live(); try { return current.mComputer.getPackageUidInternal(packageName, flags, userId, callingUid); } finally { current.release(); } } public final int updateFlagsForApplication(int flags, int userId) { ThreadComputer current = live(); try { return current.mComputer.updateFlagsForApplication(flags, userId); } finally { current.release(); } } public final int updateFlagsForComponent(int flags, int userId) { ThreadComputer current = live(); try { return current.mComputer.updateFlagsForComponent(flags, userId); } finally { current.release(); } } public final int updateFlagsForPackage(int flags, int userId) { ThreadComputer current = live(); try { return current.mComputer.updateFlagsForPackage(flags, userId); } finally { current.release(); } } public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { ThreadComputer current = live(); try { return current.mComputer.updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc); } finally { current.release(); } } public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { ThreadComputer current = live(); try { return current.mComputer.updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, onlyExposedExplicitly, isImplicitImageCaptureIntentAndNotSetByDpc); } finally { current.release(); } } public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { ThreadComputer current = live(); try { current.mComputer.dump(type, fd, pw, dumpState); } finally { current.release(); } } public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { ThreadComputer current = live(); try { current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId, requireFullPermission, checkShell, message); } finally { current.release(); } } public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { ThreadComputer current = live(); try { current.mComputer.enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, message); } finally { current.release(); } } public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message) { ThreadComputer current = live(); try { current.mComputer.enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, requirePermissionWhenSameUser, message); } finally { current.release(); } } public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { ThreadComputer current = live(); try { return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags, query, always, removeMatches, debug, userId, queryMayBeFiltered); } finally { current.release(); } } public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId) { ThreadComputer current = live(); try { return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType, flags, query, debug, userId); } finally { current.release(); } } } // Compute read-only functions, based on live data. This attribute may be modified multiple // times during the PackageManagerService constructor but it should not be modified thereafter. private ComputerLocked mLiveComputer; // A lock-free cache for frequently called functions. private volatile Computer mSnapshotComputer; // A trampoline that directs callers to either the live or snapshot computer. private final ComputerTracker mComputer = new ComputerTracker(this); // If true, the snapshot is invalid (stale). The attribute is static since it may be // set from outside classes. The attribute may be set to true anywhere, although it // should only be set true while holding mLock. However, the attribute id guaranteed // to be set false only while mLock and mSnapshotLock are both held. private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true); // The package manager that is using snapshots. private static PackageManagerService sSnapshotConsumer = null; // If true, the snapshot is corked. Do not create a new snapshot but use the live // computer. This throttles snapshot creation during periods of churn in Package // Manager. private static AtomicInteger sSnapshotCorked = new AtomicInteger(0); /** * This class records the Computer being used by a thread and the Computer's reference * count. There is a thread-local copy of this class. */ private static class ThreadComputer { Computer mComputer = null; int mRefCount = 0; void acquire(Computer c) { if (mRefCount != 0 && mComputer != c) { throw new RuntimeException("computer mismatch, count = " + mRefCount); } mComputer = c; mRefCount++; } void acquire() { if (mRefCount == 0 || mComputer == null) { throw new RuntimeException("computer acquire on empty ref count"); } mRefCount++; } void release() { if (--mRefCount == 0) { mComputer = null; } } } private static ThreadLocal sThreadComputer = new ThreadLocal<>() { @Override protected ThreadComputer initialValue() { return new ThreadComputer(); }}; /** * This lock is used to make reads from {@link #sSnapshotInvalid} and * {@link #mSnapshotComputer} atomic inside {@code snapshotComputer()}. This lock is * not meant to be used outside that method. This lock must be taken before * {@link #mLock} is taken. */ private final Object mSnapshotLock = new Object(); /** * The snapshot statistics. These are collected to track performance and to identify * situations in which the snapshots are misbehaving. */ private final SnapshotStatistics mSnapshotStatistics; // The snapshot disable/enable switch. An image with the flag set true uses snapshots // and an image with the flag set false does not use snapshots. private static final boolean SNAPSHOT_ENABLED = true; // The default auto-cork delay for snapshots. This is 1s. private static final long SNAPSHOT_AUTOCORK_DELAY_MS = TimeUnit.SECONDS.toMillis(1); // The per-instance snapshot disable/enable flag. This is generally set to false in // test instances and set to SNAPSHOT_ENABLED in operational instances. private final boolean mSnapshotEnabled; /** * Return the live computer. */ private Computer liveComputer() { return mLiveComputer; } /** * Return the cached computer. The method will rebuild the cached computer if necessary. * The live computer will be returned if snapshots are disabled. */ private Computer snapshotComputer() { if (!mSnapshotEnabled) { return mLiveComputer; } if (Thread.holdsLock(mLock)) { // If the current thread holds mLock then it may have modified state but not // yet invalidated the snapshot. Always give the thread the live computer. return mLiveComputer; } else if (sSnapshotCorked.get() > 0) { // Snapshots are corked, which means new ones should not be built right now. mSnapshotStatistics.corked(); return mLiveComputer; } synchronized (mSnapshotLock) { // This synchronization block serializes access to the snapshot computer and // to the code that samples mSnapshotInvalid. Computer c = mSnapshotComputer; if (sSnapshotInvalid.getAndSet(false) || (c == null)) { // The snapshot is invalid if it is marked as invalid or if it is null. If it // is null, then it is currently being rebuilt by rebuildSnapshot(). synchronized (mLock) { // Rebuild the snapshot if it is invalid. Note that the snapshot might be // invalidated as it is rebuilt. However, the snapshot is still // self-consistent (the lock is being held) and is current as of the time // this function is entered. rebuildSnapshot(); // Guaranteed to be non-null. mSnapshotComputer is only be set to null // temporarily in rebuildSnapshot(), which is guarded by mLock(). Since // the mLock is held in this block and since rebuildSnapshot() is // complete, the attribute can not now be null. c = mSnapshotComputer; } } c.use(); return c; } } /** * Rebuild the cached computer. mSnapshotComputer is temporarily set to null to block other * threads from using the invalid computer until it is rebuilt. */ @GuardedBy({ "mLock", "mSnapshotLock"}) private void rebuildSnapshot() { final long now = SystemClock.currentTimeMicro(); final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed(); mSnapshotComputer = null; final Snapshot args = new Snapshot(Snapshot.SNAPPED); mSnapshotComputer = new ComputerEngine(args); final long done = SystemClock.currentTimeMicro(); mSnapshotStatistics.rebuild(now, done, hits); } /** * Create a new snapshot. Used for testing only. This does collect statistics or * update the snapshot used by other actors. It does not alter the invalidation * flag. This method takes the mLock internally. */ private Computer createNewSnapshot() { synchronized (mLock) { final Snapshot args = new Snapshot(Snapshot.SNAPPED); return new ComputerEngine(args); } } /** * Cork snapshots. This times out after the programmed delay. */ private void corkSnapshots(int multiplier) { int corking = sSnapshotCorked.getAndIncrement(); if (TRACE_SNAPSHOTS && corking == 0) { Log.i(TAG, "snapshot: corking goes positive"); } Message message = mHandler.obtainMessage(SNAPSHOT_UNCORK); mHandler.sendMessageDelayed(message, SNAPSHOT_AUTOCORK_DELAY_MS * multiplier); } /** * Create a live computer */ private ComputerLocked createLiveComputer() { return new ComputerLocked(new Snapshot(Snapshot.LIVE)); } /** * This method is called when the state of PackageManagerService changes so as to * invalidate the current snapshot. * @param what The {@link Watchable} that reported the change * @hide */ public static void onChange(@Nullable Watchable what) { if (TRACE_SNAPSHOTS) { Log.i(TAG, "snapshot: onChange(" + what + ")"); } sSnapshotInvalid.set(true); } /** * Report a locally-detected change to observers. The parameter is left null, * but it signifies that the change was detected by PackageManagerService itself. */ private static void onChanged() { onChange(null); } class PackageHandler extends Handler { PackageHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { try { doHandleMessage(msg); } finally { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } } void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; if (params != null) { if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params); Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(params)); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy"); params.startCopy(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } break; } case SEND_PENDING_BROADCAST: { String packages[]; ArrayList components[]; int size = 0; int uids[]; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { size = mPendingBroadcasts.size(); if (size <= 0) { // Nothing to be done. Just return return; } packages = new String[size]; components = new ArrayList[size]; uids = new int[size]; int i = 0; // filling out the above arrays for (int n = 0; n < mPendingBroadcasts.userIdCount(); n++) { final int packageUserId = mPendingBroadcasts.userIdAt(n); final ArrayMap> componentsToBroadcast = mPendingBroadcasts.packagesForUserId(packageUserId); final int numComponents = componentsToBroadcast.size(); for (int index = 0; i < size && index < numComponents; index++) { packages[i] = componentsToBroadcast.keyAt(index); components[i] = componentsToBroadcast.valueAt(index); final PackageSetting ps = mSettings.getPackageLPr(packages[i]); uids[i] = (ps != null) ? UserHandle.getUid(packageUserId, ps.appId) : -1; i++; } } size = i; mPendingBroadcasts.clear(); } // Send broadcasts for (int i = 0; i < size; i++) { sendPackageChangedBroadcast(packages[i], true /* dontKillApp */, components[i], uids[i], null /* reason */); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); break; } case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); final boolean didRestore = (msg.arg2 != 0); mRunningInstalls.delete(msg.arg1); if (data != null && data.res.freezer != null) { data.res.freezer.close(); } if (data != null && data.mPostInstallRunnable != null) { data.mPostInstallRunnable.run(); } else if (data != null && data.args != null) { InstallArgs args = data.args; PackageInstalledInfo parentRes = data.res; final boolean killApp = (args.installFlags & PackageManager.INSTALL_DONT_KILL_APP) == 0; final boolean virtualPreload = ((args.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); handlePackagePostInstall(parentRes, killApp, virtualPreload, didRestore, args.installSource.installerPackageName, args.observer, args.mDataLoaderType); // Log tracing if needed if (args.traceMethod != null) { Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod, args.traceCookie); } } else if (DEBUG_INSTALL) { // No post-install when we run restore from installExistingPackageForUser Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1); } Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1); } break; case DEFERRED_NO_KILL_POST_DELETE: { synchronized (mInstallLock) { InstallArgs args = (InstallArgs) msg.obj; if (args != null) { args.doPostDeleteLI(true); } } } break; case DEFERRED_NO_KILL_INSTALL_OBSERVER: { String packageName = (String) msg.obj; if (packageName != null) { notifyInstallObserver(packageName); } } break; case WRITE_SETTINGS: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_SETTINGS); removeMessages(WRITE_PACKAGE_RESTRICTIONS); writeSettingsLPrTEMP(); mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; case WRITE_PACKAGE_RESTRICTIONS: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_PACKAGE_RESTRICTIONS); for (int userId : mDirtyUsers) { mSettings.writePackageRestrictionsLPr(userId); } mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; case WRITE_PACKAGE_LIST: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { removeMessages(WRITE_PACKAGE_LIST); mSettings.writePackageListLPr(msg.arg1); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; case CHECK_PENDING_VERIFICATION: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if ((state != null) && !state.isVerificationComplete() && !state.timeoutExtended()) { final VerificationParams params = state.getVerificationParams(); final Uri originUri = Uri.fromFile(params.origin.resolvedFile); Slog.i(TAG, "Verification timed out for " + originUri); final UserHandle user = params.getUser(); if (getDefaultVerificationResponse(user) == PackageManager.VERIFICATION_ALLOW) { Slog.i(TAG, "Continuing with installation of " + originUri); state.setVerifierResponse(Binder.getCallingUid(), PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT); broadcastPackageVerified(verificationId, originUri, PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType, user); } else { broadcastPackageVerified(verificationId, originUri, PackageManager.VERIFICATION_REJECT, null, params.mDataLoaderType, user); params.setReturnCode( PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE); state.setVerifierResponse(Binder.getCallingUid(), PackageManager.VERIFICATION_REJECT); } if (state.areAllVerificationsComplete()) { mPendingVerification.remove(verificationId); } Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); params.handleVerificationFinished(); } break; } case CHECK_PENDING_INTEGRITY_VERIFICATION: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if (state != null && !state.isIntegrityVerificationComplete()) { final VerificationParams params = state.getVerificationParams(); final Uri originUri = Uri.fromFile(params.origin.resolvedFile); Slog.i(TAG, "Integrity verification timed out for " + originUri); state.setIntegrityVerificationResult( getDefaultIntegrityVerificationResponse()); if (getDefaultIntegrityVerificationResponse() == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) { Slog.i(TAG, "Integrity check times out, continuing with " + originUri); } else { params.setReturnCode( PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE); } if (state.areAllVerificationsComplete()) { mPendingVerification.remove(verificationId); } Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId); params.handleIntegrityVerificationFinished(); } break; } case PACKAGE_VERIFIED: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if (state == null) { Slog.w(TAG, "Verification with id " + verificationId + " not found." + " It may be invalid or overridden by integrity verification"); break; } final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; state.setVerifierResponse(response.callerUid, response.code); if (state.isVerificationComplete()) { final VerificationParams params = state.getVerificationParams(); final Uri originUri = Uri.fromFile(params.origin.resolvedFile); if (state.isInstallAllowed()) { broadcastPackageVerified(verificationId, originUri, response.code, null, params.mDataLoaderType, params.getUser()); } else { params.setReturnCode( PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE); } if (state.areAllVerificationsComplete()) { mPendingVerification.remove(verificationId); } Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); params.handleVerificationFinished(); } break; } case INTEGRITY_VERIFICATION_COMPLETE: { final int verificationId = msg.arg1; final PackageVerificationState state = mPendingVerification.get(verificationId); if (state == null) { Slog.w(TAG, "Integrity verification with id " + verificationId + " not found. It may be invalid or overridden by verifier"); break; } final int response = (Integer) msg.obj; final VerificationParams params = state.getVerificationParams(); final Uri originUri = Uri.fromFile(params.origin.resolvedFile); state.setIntegrityVerificationResult(response); if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) { Slog.i(TAG, "Integrity check passed for " + originUri); } else { params.setReturnCode( PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE); } if (state.areAllVerificationsComplete()) { mPendingVerification.remove(verificationId); } Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId); params.handleIntegrityVerificationFinished(); break; } case INSTANT_APP_RESOLUTION_PHASE_TWO: { InstantAppResolver.doInstantAppResolutionPhaseTwo(mContext, mInstantAppResolverConnection, (InstantAppRequest) msg.obj, mInstantAppInstallerActivity, mHandler); break; } case ENABLE_ROLLBACK_STATUS: { final int enableRollbackToken = msg.arg1; final int enableRollbackCode = msg.arg2; final VerificationParams params = mPendingEnableRollback.get(enableRollbackToken); if (params == null) { Slog.w(TAG, "Invalid rollback enabled token " + enableRollbackToken + " received"); break; } mPendingEnableRollback.remove(enableRollbackToken); if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) { final Uri originUri = Uri.fromFile(params.origin.resolvedFile); Slog.w(TAG, "Failed to enable rollback for " + originUri); Slog.w(TAG, "Continuing with installation of " + originUri); } Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); params.handleRollbackEnabled(); break; } case ENABLE_ROLLBACK_TIMEOUT: { final int enableRollbackToken = msg.arg1; final int sessionId = msg.arg2; final VerificationParams params = mPendingEnableRollback.get(enableRollbackToken); if (params != null) { final Uri originUri = Uri.fromFile(params.origin.resolvedFile); Slog.w(TAG, "Enable rollback timed out for " + originUri); mPendingEnableRollback.remove(enableRollbackToken); Slog.w(TAG, "Continuing with installation of " + originUri); Trace.asyncTraceEnd( TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); params.handleRollbackEnabled(); Intent rollbackTimeoutIntent = new Intent( Intent.ACTION_CANCEL_ENABLE_ROLLBACK); rollbackTimeoutIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, sessionId); rollbackTimeoutIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM, android.Manifest.permission.PACKAGE_ROLLBACK_AGENT); } break; } case DOMAIN_VERIFICATION: { int messageCode = msg.arg1; Object object = msg.obj; mDomainVerificationManager.runMessage(messageCode, object); break; } case SNAPSHOT_UNCORK: { int corking = sSnapshotCorked.decrementAndGet(); if (TRACE_SNAPSHOTS && corking == 0) { Log.e(TAG, "snapshot: corking goes to zero in message handler"); } break; } } } } private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp, boolean virtualPreload, boolean launchedForRestore, String installerPackage, IPackageInstallObserver2 installObserver, int dataLoaderType) { boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED; final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; final String packageName = res.name; final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null; final boolean removedBeforeUpdate = (pkgSetting == null) || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath())); if (succeeded && removedBeforeUpdate) { Slog.e(TAG, packageName + " was removed before handlePackagePostInstall " + "could be executed"); res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED; res.returnMsg = "Package was removed before install could complete."; // Remove the update failed package's older resources safely now InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null; if (args != null) { synchronized (mInstallLock) { args.doPostDeleteLI(true); } } notifyInstallObserver(res, installObserver); return; } if (succeeded) { // Clear the uid cache after we installed a new package. mPerUidReadTimeoutsCache = null; // Send the removed broadcasts if (res.removedInfo != null) { res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/); } final String installerPackageName = res.installerPackageName != null ? res.installerPackageName : res.removedInfo != null ? res.removedInfo.installerPackageName : null; synchronized (mLock) { mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); } // Determine the set of users who are adding this package for // the first time vs. those who are seeing an update. int[] firstUserIds = EMPTY_INT_ARRAY; int[] firstInstantUserIds = EMPTY_INT_ARRAY; int[] updateUserIds = EMPTY_INT_ARRAY; int[] instantUserIds = EMPTY_INT_ARRAY; final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0; final PackageSetting ps = pkgSetting; for (int newUser : res.newUsers) { final boolean isInstantApp = ps.getInstantApp(newUser); if (allNewUsers) { if (isInstantApp) { firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser); } else { firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser); } continue; } boolean isNew = true; for (int origUser : res.origUsers) { if (origUser == newUser) { isNew = false; break; } } if (isNew) { if (isInstantApp) { firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser); } else { firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser); } } else { if (isInstantApp) { instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser); } else { updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser); } } } // Send installed broadcasts if the package is not a static shared lib. if (res.pkg.getStaticSharedLibName() == null) { mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps int appId = UserHandle.getAppId(res.uid); boolean isSystem = res.pkg.isSystem(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds, dataLoaderType); // Send added for users that don't see the package for the first time Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType); // Send to all running apps. final SparseArray newBroadcastAllowList; synchronized (mLock) { newBroadcastAllowList = mAppsFilter.getVisibilityAllowList( getPackageSettingInternal(res.name, Process.SYSTEM_UID), updateUserIds, mSettings.getPackagesLocked()); } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 /*flags*/, null /*targetPackage*/, null /*finishedReceiver*/, updateUserIds, instantUserIds, newBroadcastAllowList, null); if (installerPackageName != null) { // Send to the installer, even if it's not running. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 /*flags*/, installerPackageName, null /*finishedReceiver*/, updateUserIds, instantUserIds, null /* broadcastAllowList */, null); } // if the required verifier is defined, but, is not the installer of record // for the package, it gets notified final boolean notifyVerifier = mRequiredVerifierPackage != null && !mRequiredVerifierPackage.equals(installerPackageName); if (notifyVerifier) { sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 /*flags*/, mRequiredVerifierPackage, null /*finishedReceiver*/, updateUserIds, instantUserIds, null /* broadcastAllowList */, null); } // If package installer is defined, notify package installer about new // app installed if (mRequiredInstallerPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/, mRequiredInstallerPackage, null /*finishedReceiver*/, firstUserIds, instantUserIds, null /* broadcastAllowList */, null); } // Send replaced for users that don't see the package for the first time if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, null /*targetPackage*/, null /*finishedReceiver*/, updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList, null); if (installerPackageName != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, installerPackageName, null /*finishedReceiver*/, updateUserIds, instantUserIds, null /*broadcastAllowList*/, null); } if (notifyVerifier) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, mRequiredVerifierPackage, null /*finishedReceiver*/, updateUserIds, instantUserIds, null /*broadcastAllowList*/, null); } sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null /*package*/, null /*extras*/, 0 /*flags*/, packageName /*targetPackage*/, null /*finishedReceiver*/, updateUserIds, instantUserIds, null /*broadcastAllowList*/, getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED) .toBundle()); } else if (launchedForRestore && !res.pkg.isSystem()) { // First-install and we did a restore, so we're responsible for the // first-launch broadcast. if (DEBUG_BACKUP) { Slog.i(TAG, "Post-restore of " + packageName + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds)); } sendFirstLaunchBroadcast(packageName, installerPackage, firstUserIds, firstInstantUserIds); } // Send broadcast package appeared if external for all users if (res.pkg.isExternalStorage()) { if (!update) { final StorageManager storage = mInjector.getSystemService( StorageManager.class); VolumeInfo volume = storage.findVolumeByUuid( res.pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, res.pkg.isExternalStorage()); // If the package was installed externally, log it. if (packageExternalStorageType != StorageEnums.UNKNOWN) { FrameworkStatsLog.write( FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED, packageExternalStorageType, packageName); } } if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + res.pkg + " is external"); } final int[] uidArray = new int[]{res.pkg.getUid()}; ArrayList pkgList = new ArrayList<>(1); pkgList.add(packageName); sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null); } } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib int[] allUsers = mInjector.getUserManagerService().getUserIds(); for (int i = 0; i < res.libraryConsumers.size(); i++) { AndroidPackage pkg = res.libraryConsumers.get(i); // send broadcast that all consumers of the static shared library have changed sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */, new ArrayList<>(Collections.singletonList(pkg.getPackageName())), pkg.getUid(), null); } } // Work that needs to happen on first install within each user if (firstUserIds != null && firstUserIds.length > 0) { for (int userId : firstUserIds) { restorePermissionsAndUpdateRolesForNewUserInstall(packageName, pkgSetting.getInstallReason(userId), userId); } } if (allNewUsers && !update) { notifyPackageAdded(packageName, res.uid); } else { notifyPackageChanged(packageName, res.uid); } // Log current value of "unknown sources" setting EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED, getUnknownSourcesSettings()); // Remove the replaced package's older resources safely now InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null; if (args != null) { if (!killApp) { // If we didn't kill the app, defer the deletion of code/resource files, since // they may still be in use by the running application. This mitigates problems // in cases where resources or code is loaded by a new Activity before // ApplicationInfo changes have propagated to all application threads. scheduleDeferredNoKillPostDelete(args); } else { synchronized (mInstallLock) { args.doPostDeleteLI(true); } } } else { // Force a gc to clear up things. Ask for a background one, it's fine to go on // and not block here. VMRuntime.getRuntime().requestConcurrentGC(); } // Notify DexManager that the package was installed for new users. // The updated users should already be indexed and the package code paths // should not change. // Don't notify the manager for ephemeral apps as they are not expected to // survive long enough to benefit of background optimizations. for (int userId : firstUserIds) { PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId); // There's a race currently where some install events may interleave with an // uninstall. This can lead to package info being null (b/36642664). if (info != null) { mDexManager.notifyPackageInstalled(info, userId); } } } final boolean deferInstallObserver = succeeded && update && !killApp; if (deferInstallObserver) { scheduleDeferredNoKillInstallObserver(res, installObserver); } else { notifyInstallObserver(res, installObserver); } } @Override public void notifyPackagesReplacedReceived(String[] packages) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); for (String packageName : packages) { final boolean filterApp; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); filterApp = shouldFilterApplicationLocked(ps, callingUid, callingUserId); } if (!filterApp) { notifyInstallObserver(packageName); } } } private void notifyInstallObserver(String packageName) { Pair pair = mNoKillInstallObservers.remove(packageName); if (pair != null) { notifyInstallObserver(pair.first, pair.second); } } private void notifyInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 installObserver) { if (installObserver != null) { try { Bundle extras = extrasForInstallResult(info); installObserver.onPackageInstalled(info.name, info.returnCode, info.returnMsg, extras); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } private void scheduleDeferredNoKillPostDelete(InstallArgs args) { Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args); mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS); } private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 observer) { String packageName = info.pkg.getPackageName(); mNoKillInstallObservers.put(packageName, Pair.create(info, observer)); Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName); mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS); } @Override public void requestChecksums(@NonNull String packageName, boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required, @Nullable List trustedInstallers, @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) { requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers, onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(), mInjector.getBackgroundHandler()); } private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required, @Nullable List trustedInstallers, @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId, @NonNull Executor executor, @NonNull Handler handler) { Objects.requireNonNull(packageName); Objects.requireNonNull(onChecksumsReadyListener); Objects.requireNonNull(executor); Objects.requireNonNull(handler); final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0, Binder.getCallingUid(), userId); if (applicationInfo == null) { throw new ParcelableException(new PackageManager.NameNotFoundException(packageName)); } final InstallSourceInfo installSourceInfo = getInstallSourceInfo(packageName); final String installerPackageName = installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null; List> filesToChecksum = new ArrayList<>(); // Adding base split. filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir))); // Adding other splits. if (includeSplits && applicationInfo.splitNames != null) { for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) { filesToChecksum.add(Pair.create(applicationInfo.splitNames[i], new File(applicationInfo.splitSourceDirs[i]))); } } final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates( trustedInstallers) : null; executor.execute(() -> { ApkChecksums.Injector injector = new ApkChecksums.Injector( () -> mContext, () -> handler, () -> mInjector.getIncrementalManager(), () -> mPmInternal); ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName, trustedCerts, onChecksumsReadyListener, injector); }); } private static @NonNull Certificate[] decodeCertificates(@NonNull List certs) { try { final CertificateFactory cf = CertificateFactory.getInstance("X.509"); final Certificate[] result = new Certificate[certs.size()]; for (int i = 0, size = certs.size(); i < size; ++i) { final InputStream is = new ByteArrayInputStream((byte[]) certs.get(i)); final X509Certificate cert = (X509Certificate) cf.generateCertificate(is); result[i] = cert; } return result; } catch (CertificateException e) { throw ExceptionUtils.propagate(e); } } /** * Gets the type of the external storage a package is installed on. * @param packageVolume The storage volume of the package. * @param packageIsExternal true if the package is currently installed on * external/removable/unprotected storage. * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the * corresponding {@link StorageEnums} storage type value if it is. * corresponding {@link StorageEnums} storage type value if it is. */ private static int getPackageExternalStorageType(VolumeInfo packageVolume, boolean packageIsExternal) { if (packageVolume != null) { DiskInfo disk = packageVolume.getDisk(); if (disk != null) { if (disk.isSd()) { return StorageEnums.SD_CARD; } if (disk.isUsb()) { return StorageEnums.USB; } if (packageIsExternal) { return StorageEnums.OTHER; } } } return StorageEnums.UNKNOWN; } private StorageEventListener mStorageListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { if (vol.type == VolumeInfo.TYPE_PRIVATE) { if (vol.state == VolumeInfo.STATE_MOUNTED) { final String volumeUuid = vol.getFsUuid(); // Clean up any users or apps that were removed or recreated // while this volume was missing mUserManager.reconcileUsers(volumeUuid); reconcileApps(volumeUuid); // Clean up any install sessions that expired or were // cancelled while this volume was missing mInstallerService.onPrivateVolumeMounted(volumeUuid); loadPrivatePackages(vol); } else if (vol.state == VolumeInfo.STATE_EJECTING) { unloadPrivatePackages(vol); } } } @Override public void onVolumeForgotten(String fsUuid) { if (TextUtils.isEmpty(fsUuid)) { Slog.e(TAG, "Forgetting internal storage is probably a mistake; ignoring"); return; } // Remove any apps installed on the forgotten volume synchronized (mLock) { final List packages = mSettings.getVolumePackagesLPr(fsUuid); for (PackageSetting ps : packages) { Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten"); deletePackageVersioned(new VersionedPackage(ps.name, PackageManager.VERSION_CODE_HIGHEST), new LegacyPackageDeleteObserver(null).getBinder(), UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS); // Try very hard to release any references to this package // so we don't risk the system server being killed due to // open FDs AttributeCache.instance().removePackage(ps.name); } mSettings.onVolumeForgotten(fsUuid); writeSettingsLPrTEMP(); } } }; Bundle extrasForInstallResult(PackageInstalledInfo res) { Bundle extras = null; switch (res.returnCode) { case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: { extras = new Bundle(); extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION, res.origPermission); extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE, res.origPackage); break; } case PackageManager.INSTALL_SUCCEEDED: { extras = new Bundle(); extras.putBoolean(Intent.EXTRA_REPLACING, res.removedInfo != null && res.removedInfo.removedPackage != null); break; } } return extras; } void scheduleWriteSettingsLocked() { // We normally invalidate when we write settings, but in cases where we delay and // coalesce settings writes, this strategy would have us invalidate the cache too late. // Invalidating on schedule addresses this problem. invalidatePackageInfoCache(); if (!mHandler.hasMessages(WRITE_SETTINGS)) { mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); } } void scheduleWritePackageListLocked(int userId) { invalidatePackageInfoCache(); if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) { Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST); msg.arg1 = userId; mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); } } void scheduleWritePackageRestrictionsLocked(UserHandle user) { final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); scheduleWritePackageRestrictionsLocked(userId); } void scheduleWritePackageRestrictionsLocked(int userId) { invalidatePackageInfoCache(); final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[]{userId}; for (int nextUserId : userIds) { if (!mUserManager.exists(nextUserId)) return; mDirtyUsers.add(nextUserId); if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); } } } public static PackageManagerService main(Context context, Installer installer, @NonNull DomainVerificationService domainVerificationService, boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); t.traceBegin("create package manager"); final PackageManagerTracedLock lock = new PackageManagerTracedLock(); final Object installLock = new Object(); HandlerThread backgroundThread = new HandlerThread("PackageManagerBg"); backgroundThread.start(); Handler backgroundHandler = new Handler(backgroundThread.getLooper()); Injector injector = new Injector( context, lock, installer, installLock, new PackageAbiHelperImpl(), backgroundHandler, SYSTEM_PARTITIONS, (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock), (i, pm) -> PermissionManagerService.create(context, i.getSystemConfig().getAvailableFeatures()), (i, pm) -> new UserManagerService(context, pm, new UserDataPreparer(installer, installLock, context, onlyCore), lock), (i, pm) -> new Settings(Environment.getDataDirectory(), RuntimePermissionsPersistence.createInstance(), i.getPermissionManagerServiceInternal(), domainVerificationService, lock), (i, pm) -> AppsFilter.create(pm.mPmInternal, i), (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"), (i, pm) -> SystemConfig.getInstance(), (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(), i.getContext(), "*dexopt*"), (i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(), i.getInstaller(), i.getInstallLock()), (i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(), i.getInstallLock()), (i, pm) -> ApexManager.getInstance(), (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()), (i, pm) -> (IncrementalManager) i.getContext().getSystemService(Context.INCREMENTAL_SERVICE), (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class), () -> LocalServices.getService(UserManagerInternal.class)), (i, pm) -> new DisplayMetrics(), (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore, i.getDisplayMetrics(), pm.mCacheDir, pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */, (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore, i.getDisplayMetrics(), null, pm.mPackageParserCallback) /* scanningPackageParserProducer */, (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(), null, pm.mPackageParserCallback) /* preparingPackageParserProducer */, // Prepare a supplier of package parser for the staging manager to parse apex file // during the staging installation. (i, pm) -> new PackageInstallerService( i.getContext(), pm, i::getScanningPackageParser), (i, pm, cn) -> new InstantAppResolverConnection( i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE), (i, pm) -> new ModuleInfoProvider(i.getContext(), pm), (i, pm) -> LegacyPermissionManagerService.create(i.getContext()), (i, pm) -> domainVerificationService, (i, pm) -> { HandlerThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); thread.start(); return pm.new PackageHandler(thread.getLooper()); }, new DefaultSystemWrapper(), LocalServices::getService, context::getSystemService); if (Build.VERSION.SDK_INT <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); } PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest, Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL); t.traceEnd(); // "create package manager" final CompatChange.ChangeListener selinuxChangeListener = packageName -> { synchronized (m.mInstallLock) { final AndroidPackage pkg; final PackageSetting ps; final SharedUserSetting sharedUser; final String oldSeInfo; synchronized (m.mLock) { ps = m.mSettings.getPackageLPr(packageName); if (ps == null) { Slog.e(TAG, "Failed to find package setting " + packageName); return; } pkg = ps.pkg; sharedUser = ps.getSharedUser(); oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps); } if (pkg == null) { Slog.e(TAG, "Failed to find package " + packageName); return; } final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser, m.mInjector.getCompatibility()); if (!newSeInfo.equals(oldSeInfo)) { Slog.i(TAG, "Updating seInfo for package " + packageName + " from: " + oldSeInfo + " to: " + newSeInfo); ps.getPkgState().setOverrideSeInfo(newSeInfo); m.prepareAppDataAfterInstallLIF(pkg); } } }; injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES, selinuxChangeListener); injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES, selinuxChangeListener); m.installWhitelistedSystemPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); ServiceManager.addService("package_native", pmn); return m; } /** Install/uninstall system packages for all users based on their user-type, as applicable. */ private void installWhitelistedSystemPackages() { synchronized (mLock) { final boolean scheduleWrite = mUserManager.installWhitelistedSystemPackages( isFirstBoot(), isDeviceUpgrading(), mExistingPackages); if (scheduleWrite) { scheduleWritePackageRestrictionsLocked(UserHandle.USER_ALL); scheduleWriteSettingsLocked(); } } } /** * Requests that files preopted on a secondary system partition be copied to the data partition * if possible. Note that the actual copying of the files is accomplished by init for security * reasons. This simply requests that the copy takes place and awaits confirmation of its * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy. */ private static void requestCopyPreoptedFiles(Injector injector) { final int WAIT_TIME_MS = 100; final String CP_PREOPT_PROPERTY = "sys.cppreopt"; if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) { SystemProperties.set(CP_PREOPT_PROPERTY, "requested"); // We will wait for up to 100 seconds. final long timeStart = SystemClock.uptimeMillis(); final long timeEnd = timeStart + 100 * 1000; long timeNow = timeStart; while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) { try { Thread.sleep(WAIT_TIME_MS); } catch (InterruptedException e) { // Do nothing } timeNow = SystemClock.uptimeMillis(); if (timeNow > timeEnd) { SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out"); Slog.wtf(TAG, "cppreopt did not finish!"); break; } } Slog.i(TAG, "cppreopts took " + (timeNow - timeStart) + " ms"); } } @VisibleForTesting public static class ScanPartition extends SystemPartition { @ScanFlags public final int scanFlag; public ScanPartition(@NonNull SystemPartition partition) { super(partition); scanFlag = scanFlagForPartition(partition); } /** * Creates a partition containing the same folders as the original partition but with a * different root folder. The new partition will include the scan flags of the original * partition along with any specified additional scan flags. */ public ScanPartition(@NonNull File folder, @NonNull ScanPartition original, @ScanFlags int additionalScanFlag) { super(folder, original); this.scanFlag = original.scanFlag | additionalScanFlag; } private static int scanFlagForPartition(PackagePartitions.SystemPartition partition) { switch (partition.type) { case PackagePartitions.PARTITION_SYSTEM: return 0; case PackagePartitions.PARTITION_VENDOR: return SCAN_AS_VENDOR; case PackagePartitions.PARTITION_ODM: return SCAN_AS_ODM; case PackagePartitions.PARTITION_OEM: return SCAN_AS_OEM; case PackagePartitions.PARTITION_PRODUCT: return SCAN_AS_PRODUCT; case PackagePartitions.PARTITION_SYSTEM_EXT: return SCAN_AS_SYSTEM_EXT; default: throw new IllegalStateException("Unable to determine scan flag for " + partition.getFolder()); } } @Override public String toString() { return getFolder().getAbsolutePath() + ":" + scanFlag; } } // Link watchables to the class private void registerObserver() { mPackages.registerObserver(mWatcher); mSharedLibraries.registerObserver(mWatcher); mStaticLibsByDeclaringPackage.registerObserver(mWatcher); mInstrumentation.registerObserver(mWatcher); mWebInstantAppsDisabled.registerObserver(mWatcher); mAppsFilter.registerObserver(mWatcher); mInstantAppRegistry.registerObserver(mWatcher); mSettings.registerObserver(mWatcher); mIsolatedOwners.registerObserver(mWatcher); mComponentResolver.registerObserver(mWatcher); // If neither "build" attribute is true then this may be a mockito test, and verification // can fail as a false positive. Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild)); } /** * A extremely minimal constructor designed to start up a PackageManagerService instance for * testing. * * It is assumed that all methods under test will mock the internal fields and thus * none of the initialization is needed. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public PackageManagerService(@NonNull Injector injector, @NonNull TestParams testParams) { mInjector = injector; mInjector.bootstrap(this); mAppsFilter = injector.getAppsFilter(); mComponentResolver = injector.getComponentResolver(); mContext = injector.getContext(); mInstaller = injector.getInstaller(); mInstallLock = injector.getInstallLock(); mLock = injector.getLock(); mPermissionManager = injector.getPermissionManagerServiceInternal(); mSettings = injector.getSettings(); mUserManager = injector.getUserManagerService(); mDomainVerificationManager = injector.getDomainVerificationManagerInternal(); mHandler = injector.getHandler(); mApexManager = testParams.apexManager; mArtManagerService = testParams.artManagerService; mAvailableFeatures = testParams.availableFeatures; mDefParseFlags = testParams.defParseFlags; mDefaultAppProvider = testParams.defaultAppProvider; mLegacyPermissionManager = testParams.legacyPermissionManagerInternal; mDexManager = testParams.dexManager; mDirsToScanAsSystem = testParams.dirsToScanAsSystem; mFactoryTest = testParams.factoryTest; mIncrementalManager = testParams.incrementalManager; mInstallerService = testParams.installerService; mInstantAppRegistry = testParams.instantAppRegistry; mInstantAppResolverConnection = testParams.instantAppResolverConnection; mInstantAppResolverSettingsComponent = testParams.instantAppResolverSettingsComponent; mIsPreNMR1Upgrade = testParams.isPreNmr1Upgrade; mIsPreNUpgrade = testParams.isPreNupgrade; mIsPreQUpgrade = testParams.isPreQupgrade; mIsUpgrade = testParams.isUpgrade; mMetrics = testParams.Metrics; mModuleInfoProvider = testParams.moduleInfoProvider; mMoveCallbacks = testParams.moveCallbacks; mOnlyCore = testParams.onlyCore; mOverlayConfig = testParams.overlayConfig; mPackageDexOptimizer = testParams.packageDexOptimizer; mPackageParserCallback = testParams.packageParserCallback; mPendingBroadcasts = testParams.pendingPackageBroadcasts; mPmInternal = testParams.pmInternal; mTestUtilityService = testParams.testUtilityService; mProcessLoggingHandler = testParams.processLoggingHandler; mProtectedPackages = testParams.protectedPackages; mSeparateProcesses = testParams.separateProcesses; mViewCompiler = testParams.viewCompiler; mRequiredVerifierPackage = testParams.requiredVerifierPackage; mRequiredInstallerPackage = testParams.requiredInstallerPackage; mRequiredUninstallerPackage = testParams.requiredUninstallerPackage; mRequiredPermissionControllerPackage = testParams.requiredPermissionControllerPackage; mSetupWizardPackage = testParams.setupWizardPackage; mStorageManagerPackage = testParams.storageManagerPackage; mDefaultTextClassifierPackage = testParams.defaultTextClassifierPackage; mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage; mRetailDemoPackage = testParams.retailDemoPackage; mRecentsPackage = testParams.recentsPackage; mDocumenterPackage = testParams.documenterPackage; mConfiguratorPackage = testParams.configuratorPackage; mAppPredictionServicePackage = testParams.appPredictionServicePackage; mIncidentReportApproverPackage = testParams.incidentReportApproverPackage; mServicesExtensionPackageName = testParams.servicesExtensionPackageName; mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName; mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage; mResolveComponentName = testParams.resolveComponentName; // Disable snapshots in this instance of PackageManagerService, which is only used // for testing. The instance still needs a live computer. The snapshot computer // is set to null since it must never be used by this instance. mSnapshotEnabled = false; mLiveComputer = createLiveComputer(); mSnapshotComputer = null; mSnapshotStatistics = null; mPackages.putAll(testParams.packages); mEnableFreeCacheV2 = testParams.enableFreeCacheV2; mSdkVersion = testParams.sdkVersion; mSystemWrapper = testParams.systemWrapper; mAppInstallDir = testParams.appInstallDir; mAppLib32InstallDir = testParams.appLib32InstallDir; mIsEngBuild = testParams.isEngBuild; mIsUserDebugBuild = testParams.isUserDebugBuild; mIncrementalVersion = testParams.incrementalVersion; invalidatePackageInfoCache(); } public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest, final String buildFingerprint, final boolean isEngBuild, final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) { mIsEngBuild = isEngBuild; mIsUserDebugBuild = isUserDebugBuild; mSdkVersion = sdkVersion; mIncrementalVersion = incrementalVersion; mInjector = injector; mInjector.getSystemWrapper().disablePackageCaches(); final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); mPendingBroadcasts = new PendingPackageBroadcasts(); mInjector.bootstrap(this); mLock = injector.getLock(); mInstallLock = injector.getInstallLock(); LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); mSystemWrapper = injector.getSystemWrapper(); mContext = injector.getContext(); mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = injector.getDisplayMetrics(); mInstaller = injector.getInstaller(); mEnableFreeCacheV2 = SystemProperties.getBoolean("fw.free_cache_v2", true); // Create sub-components that provide services / data. Order here is important. t.traceBegin("createSubComponents"); // Expose private service for system components to use. mPmInternal = new PackageManagerInternalImpl(); LocalServices.addService(TestUtilityService.class, this); mTestUtilityService = LocalServices.getService(TestUtilityService.class); LocalServices.addService(PackageManagerInternal.class, mPmInternal); mUserManager = injector.getUserManagerService(); mComponentResolver = injector.getComponentResolver(); mPermissionManager = injector.getPermissionManagerServiceInternal(); mSettings = injector.getSettings(); mIncrementalManager = mInjector.getIncrementalManager(); mDefaultAppProvider = mInjector.getDefaultAppProvider(); mLegacyPermissionManager = mInjector.getLegacyPermissionManagerInternal(); PlatformCompat platformCompat = mInjector.getCompatibility(); mPackageParserCallback = new PackageParser2.Callback() { @Override public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) { return platformCompat.isChangeEnabled(changeId, appInfo); } @Override public boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); } }; // CHECKSTYLE:ON IndentationCheck t.traceEnd(); t.traceBegin("addSharedUsers"); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.se", SE_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); t.traceEnd(); String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { mDefParseFlags = ParsingPackageUtils.PARSE_IGNORE_PROCESSES; mSeparateProcesses = null; Slog.w(TAG, "Running with debug.separate_processes: * (ALL)"); } else { mDefParseFlags = 0; mSeparateProcesses = separateProcesses.split(","); Slog.w(TAG, "Running with debug.separate_processes: " + separateProcesses); } } else { mDefParseFlags = 0; mSeparateProcesses = null; } mPackageDexOptimizer = injector.getPackageDexOptimizer(); mDexManager = injector.getDexManager(); mArtManagerService = injector.getArtManagerService(); mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper()); mViewCompiler = injector.getViewCompiler(); mContext.getSystemService(DisplayManager.class) .getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics); t.traceBegin("get system config"); SystemConfig systemConfig = injector.getSystemConfig(); mAvailableFeatures = systemConfig.getAvailableFeatures(); t.traceEnd(); mProtectedPackages = new ProtectedPackages(mContext); mApexManager = injector.getApexManager(); mAppsFilter = mInjector.getAppsFilter(); final List scanPartitions = new ArrayList<>(); final List activeApexInfos = mApexManager.getActiveApexInfos(); for (int i = 0; i < activeApexInfos.size(); i++) { final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i)); if (scanPartition != null) { scanPartitions.add(scanPartition); } } mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager); mDirsToScanAsSystem = new ArrayList<>(); mDirsToScanAsSystem.addAll(injector.getSystemPartitions()); mDirsToScanAsSystem.addAll(scanPartitions); Slog.d(TAG, "Directories scanned as system partitions: " + mDirsToScanAsSystem); mAppInstallDir = new File(Environment.getDataDirectory(), "app"); mAppLib32InstallDir = getAppLib32InstallDir(); mDomainVerificationManager = injector.getDomainVerificationManagerInternal(); mDomainVerificationManager.setConnection(mDomainVerificationConnection); synchronized (mLock) { // Create the computer as soon as the state objects have been installed. The // cached computer is the same as the live computer until the end of the // constructor, at which time the invalidation method updates it. The cache is // corked initially to ensure a cached computer is not built until the end of the // constructor. mSnapshotStatistics = new SnapshotStatistics(); sSnapshotConsumer = this; sSnapshotCorked.set(1); sSnapshotInvalid.set(true); mLiveComputer = createLiveComputer(); mSnapshotComputer = null; mSnapshotEnabled = SNAPSHOT_ENABLED; registerObserver(); } // CHECKSTYLE:OFF IndentationCheck synchronized (mInstallLock) { // writer synchronized (mLock) { mHandler = injector.getHandler(); mProcessLoggingHandler = new ProcessLoggingHandler(); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); ArrayMap libConfig = systemConfig.getSharedLibraries(); final int builtInLibCount = libConfig.size(); for (int i = 0; i < builtInLibCount; i++) { addBuiltInSharedLibraryLocked(libConfig.valueAt(i)); } // Now that we have added all the libraries, iterate again to add dependency // information IFF their dependencies are added. long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED; for (int i = 0; i < builtInLibCount; i++) { String name = libConfig.keyAt(i); SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i); final int dependencyCount = entry.dependencies.length; for (int j = 0; j < dependencyCount; j++) { final SharedLibraryInfo dependency = getSharedLibraryInfoLPr(entry.dependencies[j], undefinedVersion); if (dependency != null) { getSharedLibraryInfoLPr(name, undefinedVersion).addDependency(dependency); } } } SELinuxMMAC.readInstallPolicy(); t.traceBegin("loadFallbacks"); FallbackCategoryProvider.loadFallbacks(); t.traceEnd(); t.traceBegin("read user settings"); mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers( /* excludePartial= */ true, /* excludeDying= */ false, /* excludePreCreated= */ false)); t.traceEnd(); mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); mPermissionManager.readLegacyPermissionStateTEMP(); if (!mOnlyCore && mFirstBoot) { requestCopyPreoptedFiles(mInjector); } String customResolverActivityName = Resources.getSystem().getString( R.string.config_customResolverActivity); if (!TextUtils.isEmpty(customResolverActivityName)) { mCustomResolverComponentName = ComponentName.unflattenFromString( customResolverActivityName); } long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); final String bootClassPath = System.getenv("BOOTCLASSPATH"); final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH"); if (bootClassPath == null) { Slog.w(TAG, "No BOOTCLASSPATH found!"); } if (systemServerClassPath == null) { Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!"); } File frameworkDir = new File(Environment.getRootDirectory(), "framework"); final VersionInfo ver = mSettings.getInternalVersion(); mIsUpgrade = !buildFingerprint.equals(ver.fingerprint); if (mIsUpgrade) { PackageManagerServiceUtils.logCriticalInfo(Log.INFO, "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT); } // when upgrading from pre-M, promote system app permissions from install to runtime mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1; // When upgrading from pre-N, we need to handle package extraction like first boot, // as there is no profiling data available. mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N; mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1; mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q; final WatchedArrayMap packageSettings = mSettings.getPackagesLocked(); // Save the names of pre-existing packages prior to scanning, so we can determine // which system packages are completely new due to an upgrade. if (isDeviceUpgrading()) { mExistingPackages = new ArraySet<>(packageSettings.size()); for (PackageSetting ps : packageSettings.values()) { mExistingPackages.add(ps.name); } } mCacheDir = preparePackageParserCache(mIsEngBuild); // Set flag to monitor and not change apk file paths when // scanning install directories. int scanFlags = SCAN_BOOTING | SCAN_INITIAL; if (mIsUpgrade || mFirstBoot) { scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } final int systemParseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR; final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; PackageParser2 packageParser = injector.getScanningCachingPackageParser(); ExecutorService executorService = ParallelPackageParser.makeExecutorService(); // Prepare apex package info before scanning APKs, these information are needed when // scanning apk in apex. mApexManager.scanApexPackagesTraced(packageParser, executorService); // Collect vendor/product/system_ext overlay packages. (Do this before scanning // any apps.) // For security and version matching reason, only consider overlay packages if they // reside in the right directory. for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { final ScanPartition partition = mDirsToScanAsSystem.get(i); if (partition.getOverlayFolder() == null) { continue; } scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags, systemScanFlags | partition.scanFlag, 0, packageParser, executorService); } scanDirTracedLI(frameworkDir, systemParseFlags, systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0, packageParser, executorService); if (!mPackages.containsKey("android")) { throw new IllegalStateException( "Failed to load frameworks package; check log for warnings"); } for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) { final ScanPartition partition = mDirsToScanAsSystem.get(i); if (partition.getPrivAppFolder() != null) { scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags, systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0, packageParser, executorService); } scanDirTracedLI(partition.getAppFolder(), systemParseFlags, systemScanFlags | partition.scanFlag, 0, packageParser, executorService); } // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. mOverlayConfig = OverlayConfig.initializeSystemInstance( consumer -> mPmInternal.forEachPackage( pkg -> consumer.accept(pkg, pkg.isSystem()))); // Prune any system packages that no longer exist. final List possiblyDeletedUpdatedSystemApps = new ArrayList<>(); // Stub packages must either be replaced with full versions in the /data // partition or be disabled. final List stubSystemApps = new ArrayList<>(); final int[] userIds = mUserManager.getUserIds(); if (!mOnlyCore) { // do this first before mucking with mPackages for the "expecting better" case final int numPackages = mPackages.size(); for (int index = 0; index < numPackages; index++) { final AndroidPackage pkg = mPackages.valueAt(index); if (pkg.isStub()) { stubSystemApps.add(pkg.getPackageName()); } } // Iterates PackageSettings in reversed order because the item could be removed // during the iteration. for (int index = packageSettings.size() - 1; index >= 0; index--) { final PackageSetting ps = packageSettings.valueAt(index); /* * If this is not a system app, it can't be a * disable system app. */ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } /* * If the package is scanned, it's not erased. */ final AndroidPackage scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. */ if (mSettings.isDisabledSystemPackageLPr(ps.name)) { logCriticalInfo(Log.WARN, "Expecting better updated system app for " + ps.name + "; removing system app. Last known" + " codePath=" + ps.getPathString() + ", versionCode=" + ps.versionCode + "; scanned versionCode=" + scannedPkg.getLongVersionCode()); removePackageLI(scannedPkg, true); mExpectingBetter.put(ps.name, ps.getPath()); } continue; } if (!mSettings.isDisabledSystemPackageLPr(ps.name)) { logCriticalInfo(Log.WARN, "System package " + ps.name + " no longer exists; it's data will be wiped"); removePackageDataLIF(ps, userIds, null, 0, false); } else { // we still have a disabled system package, but, it still might have // been removed. check the code path still exists and check there's // still a package. the latter can happen if an OTA keeps the same // code path, but, changes the package name. final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name); if (disabledPs.getPath() == null || !disabledPs.getPath().exists() || disabledPs.pkg == null) { possiblyDeletedUpdatedSystemApps.add(ps.name); } else { // We're expecting that the system app should remain disabled, but add // it to expecting better to recover in case the data version cannot // be scanned. mExpectingBetter.put(disabledPs.name, disabledPs.getPath()); } } } } final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get(); // Remove any shared userIDs that have no associated packages mSettings.pruneSharedUsersLPw(); final long systemScanTime = SystemClock.uptimeMillis() - startTime; final int systemPackagesCount = mPackages.size(); Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime + " ms, packageCount: " + systemPackagesCount + " , timePerPackage: " + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount) + " , cached: " + cachedSystemApps); if (mIsUpgrade && systemPackagesCount > 0) { //CHECKSTYLE:OFF IndentationCheck FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME, systemScanTime / systemPackagesCount); //CHECKSTYLE:ON IndentationCheck } if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, packageParser, executorService); } packageParser.close(); List unfinishedTasks = executorService.shutdownNow(); if (!unfinishedTasks.isEmpty()) { throw new IllegalStateException("Not all tasks finished before calling close: " + unfinishedTasks); } if (!mOnlyCore) { // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) { final String packageName = possiblyDeletedUpdatedSystemApps.get(i); final AndroidPackage pkg = mPackages.get(packageName); final String msg; // remove from the disabled system list; do this first so any future // scans of this package are performed without this state mSettings.removeDisabledSystemPackageLPw(packageName); if (pkg == null) { // should have found an update, but, we didn't; remove everything msg = "Updated system package " + packageName + " no longer exists; removing its data"; // Actual deletion of code and data will be handled by later // reconciliation step } else { // found an update; revoke system privileges msg = "Updated system package " + packageName + " no longer exists; rescanning package on data"; // NOTE: We don't do anything special if a stub is removed from the // system image. But, if we were [like removing the uncompressed // version from the /data partition], this is where it'd be done. // remove the package from the system and re-scan it without any // special privileges removePackageLI(pkg, true); try { final File codePath = new File(pkg.getPath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " + e.getMessage()); } } // one final check. if we still have a package setting [ie. it was // previously scanned and known to the system], but, we don't have // a package [ie. there was an error scanning it from the /data // partition], completely remove the package data. final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && mPackages.get(packageName) == null) { removePackageDataLIF(ps, userIds, null, 0, false); } logCriticalInfo(Log.WARN, msg); } /* * Make sure all system apps that we expected to appear on * the userdata partition actually showed up. If they never * appeared, crawl back and revive the system version. */ for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i); if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i); logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system"); @ParseFlags int reparseFlags = 0; @ScanFlags int rescanFlags = 0; for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) { final ScanPartition partition = mDirsToScanAsSystem.get(i1); if (partition.containsPrivApp(scanFile)) { reparseFlags = systemParseFlags; rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag; break; } if (partition.containsApp(scanFile)) { reparseFlags = systemParseFlags; rescanFlags = systemScanFlags | partition.scanFlag; break; } } if (rescanFlags == 0) { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; } mSettings.enableSystemPackageLPw(packageName); try { final AndroidPackage newPkg = scanPackageTracedLI( scanFile, reparseFlags, rescanFlags, 0, null); // We rescanned a stub, add it to the list of stubbed system packages if (newPkg.isStub()) { stubSystemApps.add(packageName); } } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse original system package: " + e.getMessage()); } } } // Uncompress and install any stubbed system applications. // This must be done last to ensure all stubs are replaced or disabled. installSystemStubPackages(stubSystemApps, scanFlags); final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get() - cachedSystemApps; final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime; final int dataPackagesCount = mPackages.size() - systemPackagesCount; Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime + " ms, packageCount: " + dataPackagesCount + " , timePerPackage: " + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount) + " , cached: " + cachedNonSystemApps); if (mIsUpgrade && dataPackagesCount > 0) { //CHECKSTYLE:OFF IndentationCheck FrameworkStatsLog.write( FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME, dataScanTime / dataPackagesCount); //CHECKSTYLE:OFF IndentationCheck } } mExpectingBetter.clear(); // Resolve the storage manager. mStorageManagerPackage = getStorageManagerPackageName(); // Resolve protected action filters. Only the setup wizard is allowed to // have a high priority filter for these actions. mSetupWizardPackage = getSetupWizardPackageNameImpl(); mComponentResolver.fixProtectedFilterPriorities(); mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName(); mSystemTextClassifierPackageName = getSystemTextClassifierPackageName(); mDocumenterPackage = getDocumenterPackageName(); mConfiguratorPackage = getDeviceConfiguratorPackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); mRetailDemoPackage = getRetailDemoPackageName(); mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName(); mRecentsPackage = getRecentsPackageName(); // Now that we know all of the shared libraries, update all clients to have // the correct library paths. updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages)); for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { // NOTE: We ignore potential failures here during a system scan (like // the rest of the commands above) because there's precious little we // can do about it. A settings error is reported, though. final List changedAbiCodePath = applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/, mInjector.getAbiHelper().getAdjustedAbiForSharedUser( setting.packages, null /*scannedPackage*/)); if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { final String codePathString = changedAbiCodePath.get(i); try { mInstaller.rmdex(codePathString, getDexCodeInstructionSet(getPreferredInstructionSet())); } catch (InstallerException ignored) { } } } // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same // SELinux domain. setting.fixSeInfoLocked(); setting.updateProcesses(); } // Now that we know all the packages we are keeping, // read and update their last usage times. mPackageUsage.read(packageSettings); mCompilerStats.read(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); // If the build fingerprint has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some // cases get permissions that the user didn't initially explicitly // allow... it would be nice to have some better way to handle // this situation. if (mIsUpgrade) { Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to " + Build.FINGERPRINT + "; regranting permissions for internal storage"); } mPermissionManager.onStorageVolumeMounted( StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade); ver.sdkVersion = mSdkVersion; // If this is the first boot or an update from pre-M, and it is a normal // boot, then we need to initialize the default preferred apps across // all defined users. if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) { for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) { mSettings.applyDefaultPreferredAppsLPw(user.id); } } // Prepare storage for system user really early during boot, // since core system apps like SettingsProvider and SystemUI // can't wait for user to start final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated()) { storageFlags = StorageManager.FLAG_STORAGE_DE; } else { storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } List deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, true /* onlyCoreApps */); mPrepareAppDataFuture = SystemServerInitThreadPool.submit(() -> { TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync", Trace.TRACE_TAG_PACKAGE_MANAGER); traceLog.traceBegin("AppDataFixup"); try { mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE); } catch (InstallerException e) { Slog.w(TAG, "Trouble fixing GIDs", e); } traceLog.traceEnd(); traceLog.traceBegin("AppDataPrepare"); if (deferPackages == null || deferPackages.isEmpty()) { return; } int count = 0; final Installer.Batch batch = new Installer.Batch(); for (String pkgName : deferPackages) { AndroidPackage pkg = null; synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) { pkg = ps.pkg; } } if (pkg != null) { prepareAppDataAndMigrate(batch, pkg, UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */); count++; } } synchronized (mInstallLock) { executeBatchLI(batch); } traceLog.traceEnd(); Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages"); }, "prepareAppData"); // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. // Note that we do *not* clear the application profiles. These remain valid // across OTAs and are used to drive profile verification (post OTA) and // profile compilation (without waiting to collect a fresh set of profiles). if (mIsUpgrade && !mOnlyCore) { Slog.i(TAG, "Build fingerprint changed; clearing code caches"); for (int i = 0; i < packageSettings.size(); i++) { final PackageSetting ps = packageSettings.valueAt(i); if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) { // No apps are running this early, so no need to freeze clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); } } ver.fingerprint = Build.FINGERPRINT; } // Legacy existing (installed before Q) non-system apps to hide // their icons in launcher. if (!mOnlyCore && mIsPreQUpgrade) { Slog.i(TAG, "Whitelisting all existing apps to hide their icons"); int size = packageSettings.size(); for (int i = 0; i < size; i++) { final PackageSetting ps = packageSettings.valueAt(i); if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { continue; } ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME, UserHandle.USER_SYSTEM); } } // clear only after permissions and other defaults have been updated mPromoteSystemApps = false; // All the changes are done during package scanning. ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION; // can downgrade to reader t.traceBegin("write settings"); writeSettingsLPrTEMP(); t.traceEnd(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); if (!mOnlyCore) { mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(); mRequiredInstallerPackage = getRequiredInstallerLPr(); mRequiredUninstallerPackage = getRequiredUninstallerLPr(); ComponentName intentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); ComponentName domainVerificationAgent = getDomainVerificationAgentComponentNameLPr(); DomainVerificationProxy domainVerificationProxy = DomainVerificationProxy.makeProxy( intentFilterVerifierComponent, domainVerificationAgent, mContext, mDomainVerificationManager, mDomainVerificationManager.getCollector(), mDomainVerificationConnection); mDomainVerificationManager.setProxy(domainVerificationProxy); mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(); mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr( PackageManager.SYSTEM_SHARED_LIBRARY_SHARED, SharedLibraryInfo.VERSION_UNDEFINED); } else { mRequiredVerifierPackage = null; mRequiredInstallerPackage = null; mRequiredUninstallerPackage = null; mServicesExtensionPackageName = null; mSharedSystemSharedLibraryPackageName = null; } // PermissionController hosts default permission granting and role management, so it's a // critical part of the core system. mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(); mSettings.setPermissionControllerVersion( getPackageInfo(mRequiredPermissionControllerPackage, 0, UserHandle.USER_SYSTEM).getLongVersionCode()); // Initialize InstantAppRegistry's Instant App list for all users. for (AndroidPackage pkg : mPackages.values()) { if (pkg.isSystem()) { continue; } for (int userId : userIds) { final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) { continue; } mInstantAppRegistry.addInstantAppLPw(userId, ps.appId); } } mInstallerService = mInjector.getPackageInstallerService(); final ComponentName instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { if (DEBUG_INSTANT) { Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent); } mInstantAppResolverConnection = mInjector.getInstantAppResolverConnection(instantAppResolverComponent); mInstantAppResolverSettingsComponent = getInstantAppResolverSettingsLPr(instantAppResolverComponent); } else { mInstantAppResolverConnection = null; mInstantAppResolverSettingsComponent = null; } updateInstantAppInstallerLocked(null); // Read and update the usage of dex files. // Do this at the end of PM init so that all the packages have their // data directory reconciled. // At this point we know the code paths of the packages, so we can validate // the disk file and build the internal cache. // The usage file is expected to be small so loading and verifying it // should take a fairly small time compare to the other activities (e.g. package // scanning). final Map> userPackages = new HashMap<>(); for (int userId : userIds) { userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList()); } mDexManager.load(userPackages); if (mIsUpgrade) { FrameworkStatsLog.write( FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME, SystemClock.uptimeMillis() - startTime); } // Rebild the live computer since some attributes have been rebuilt. mLiveComputer = createLiveComputer(); } // synchronized (mLock) } // synchronized (mInstallLock) // CHECKSTYLE:ON IndentationCheck mModuleInfoProvider = mInjector.getModuleInfoProvider(); mInjector.getSystemWrapper().enablePackageCaches(); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and // tidy. t.traceBegin("GC"); VMRuntime.getRuntime().requestConcurrentGC(); t.traceEnd(); // The initial scanning above does many calls into installd while // holding the mPackages lock, but we're mostly interested in yelling // once we have a booted system. mInstaller.setWarnIfHeld(mLock); ParsingPackageUtils.readConfigUseRoundIcon(mContext.getResources()); mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L); Slog.i(TAG, "Fix for b/169414761 is applied"); } /** * Uncompress and install stub applications. *

    In order to save space on the system partition, some applications are shipped in a * compressed form. In addition the compressed bits for the full application, the * system image contains a tiny stub comprised of only the Android manifest. *

    During the first boot, attempt to uncompress and install the full application. If * the application can't be installed for any reason, disable the stub and prevent * uncompressing the full application during future boots. *

    In order to forcefully attempt an installation of a full application, go to app * settings and enable the application. */ private void installSystemStubPackages(@NonNull List systemStubPackageNames, @ScanFlags int scanFlags) { for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) { final String packageName = systemStubPackageNames.get(i); // skip if the system package is already disabled if (mSettings.isDisabledSystemPackageLPr(packageName)) { systemStubPackageNames.remove(i); continue; } // skip if the package isn't installed (?!); this should never happen final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { systemStubPackageNames.remove(i); continue; } // skip if the package has been disabled by the user final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM); if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { systemStubPackageNames.remove(i); continue; } } // install the package to replace the stub on /system try { installStubPackageLI(pkg, 0, scanFlags); ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, UserHandle.USER_SYSTEM, "android"); systemStubPackageNames.remove(i); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage()); } // any failed attempt to install the package will be cleaned up later } // disable any stub still left; these failed to install the full application for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) { final String pkgName = systemStubPackageNames.get(i); final PackageSetting ps = mSettings.getPackageLPr(pkgName); ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName); } } /** * Extract, install and enable a stub package. *

    If the compressed file can not be extracted / installed for any reason, the stub * APK will be installed and the package will be disabled. To recover from this situation, * the user will need to go into system settings and re-enable the package. */ private boolean enableCompressedPackage(AndroidPackage stubPkg, @NonNull PackageSetting stubPkgSetting) { final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; synchronized (mInstallLock) { final AndroidPackage pkg; try (PackageFreezer freezer = freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/); synchronized (mLock) { prepareAppDataAfterInstallLIF(pkg); try { updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null, Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e); } mPermissionManager.onPackageInstalled(pkg, PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, UserHandle.USER_ALL); writeSettingsLPrTEMP(); } } catch (PackageManagerException e) { // Whoops! Something went very wrong; roll back to the stub and disable the package try (PackageFreezer freezer = freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { synchronized (mLock) { // NOTE: Ensure the system package is enabled; even for a compressed stub. // If we don't, installing the system package fails during scan enableSystemPackageLPw(stubPkg); } installPackageFromSystemLIF(stubPkg.getPath(), mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/, true /*writeSettings*/); } catch (PackageManagerException pme) { // Serious WTF; we have to be able to install the stub Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(), pme); } finally { // Disable the package; the stub by itself is not runnable synchronized (mLock) { final PackageSetting stubPs = mSettings.getPackageLPr( stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); } writeSettingsLPrTEMP(); } } return false; } clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); mDexManager.notifyPackageUpdated(pkg.getPackageName(), pkg.getBaseApkPath(), pkg.getSplitCodePaths()); } return true; } private AndroidPackage installStubPackageLI(AndroidPackage stubPkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags) throws PackageManagerException { if (DEBUG_COMPRESSION) { Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName()); } // uncompress the binary to its eventual destination on /data final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath()); if (scanFile == null) { throw new PackageManagerException( "Unable to decompress stub at " + stubPkg.getPath()); } synchronized (mLock) { mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/); } removePackageLI(stubPkg, true /*chatty*/); try { return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(), e); // Remove the failed install removeCodePathLI(scanFile); throw e; } } /** * Decompresses the given package on the system image onto * the /data partition. * @return The directory the package was decompressed into. Otherwise, {@code null}. */ private File decompressPackage(String packageName, String codePath) { final File[] compressedFiles = getCompressedFiles(codePath); if (compressedFiles == null || compressedFiles.length == 0) { if (DEBUG_COMPRESSION) { Slog.i(TAG, "No files to decompress: " + codePath); } return null; } final File dstCodePath = getNextCodePath(Environment.getDataAppDirectory(null), packageName); int ret = PackageManager.INSTALL_SUCCEEDED; try { makeDirRecursive(dstCodePath, 0755); for (File srcFile : compressedFiles) { final String srcFileName = srcFile.getName(); final String dstFileName = srcFileName.substring( 0, srcFileName.length() - COMPRESSED_EXTENSION.length()); final File dstFile = new File(dstCodePath, dstFileName); ret = decompressFile(srcFile, dstFile); if (ret != PackageManager.INSTALL_SUCCEEDED) { logCriticalInfo(Log.ERROR, "Failed to decompress" + "; pkg: " + packageName + ", file: " + dstFileName); break; } } } catch (ErrnoException e) { logCriticalInfo(Log.ERROR, "Failed to decompress" + "; pkg: " + packageName + ", err: " + e.errno); } if (ret == PackageManager.INSTALL_SUCCEEDED) { final File libraryRoot = new File(dstCodePath, LIB_DIR_NAME); NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(dstCodePath); ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, null /*abiOverride*/, false /*isIncremental*/); } catch (IOException e) { logCriticalInfo(Log.ERROR, "Failed to extract native libraries" + "; pkg: " + packageName); ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } finally { IoUtils.closeQuietly(handle); } } if (ret == PackageManager.INSTALL_SUCCEEDED) { // NOTE: During boot, we have to delay releasing cblocks for no other reason than // we cannot retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. // When we no longer need to read that setting, cblock release can occur always // occur here directly if (!mSystemReady) { if (mReleaseOnSystemReady == null) { mReleaseOnSystemReady = new ArrayList<>(); } mReleaseOnSystemReady.add(dstCodePath); } else { final ContentResolver resolver = mContext.getContentResolver(); F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath); } } if (ret != PackageManager.INSTALL_SUCCEEDED) { if (!dstCodePath.exists()) { return null; } removeCodePathLI(dstCodePath); return null; } return dstCodePath; } @GuardedBy("mLock") private void updateInstantAppInstallerLocked(String modifiedPackage) { // we're only interested in updating the installer appliction when 1) it's not // already set or 2) the modified package is the installer if (mInstantAppInstallerActivity != null && !mInstantAppInstallerActivity.getComponentName().getPackageName() .equals(modifiedPackage)) { return; } setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr()); } private @Nullable File preparePackageParserCache(boolean forEngBuild) { if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) { if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) { return null; } // Disable package parsing on eng builds to allow for faster incremental development. if (forEngBuild) { return null; } if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) { Slog.i(TAG, "Disabling package parser cache due to system property."); return null; } } // The base directory for the package parser cache lives under /data/system/. final File cacheBaseDir = Environment.getPackageCacheDirectory(); if (!FileUtils.createDir(cacheBaseDir)) { return null; } // There are several items that need to be combined together to safely // identify cached items. In particular, changing the value of certain // feature flags should cause us to invalidate any caches. final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug" : SystemProperties.digestOf("ro.build.fingerprint"); // Reconcile cache directories, keeping only what we'd actually use. for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) { if (Objects.equals(cacheName, cacheDir.getName())) { Slog.d(TAG, "Keeping known cache " + cacheDir.getName()); } else { Slog.d(TAG, "Destroying unknown cache " + cacheDir.getName()); FileUtils.deleteContentsAndDir(cacheDir); } } // Return the versioned package cache directory. File cacheDir = FileUtils.createDir(cacheBaseDir, cacheName); if (cacheDir == null) { // Something went wrong. Attempt to delete everything and return. Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir); FileUtils.deleteContentsAndDir(cacheBaseDir); return null; } // The following is a workaround to aid development on non-numbered userdebug // builds or cases where "adb sync" is used on userdebug builds. If we detect that // the system partition is newer. // // NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build // that starts with "eng." to signify that this is an engineering build and not // destined for release. if (mIsUserDebugBuild && mIncrementalVersion.startsWith("eng.")) { Slog.w(TAG, "Wiping cache directory because the system partition changed."); // Heuristic: If the /system directory has been modified recently due to an "adb sync" // or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable // in general and should not be used for production changes. In this specific case, // we know that they will work. File frameworkDir = new File(Environment.getRootDirectory(), "framework"); if (cacheDir.lastModified() < frameworkDir.lastModified()) { FileUtils.deleteContents(cacheBaseDir); cacheDir = FileUtils.createDir(cacheBaseDir, cacheName); } } return cacheDir; } @Override public boolean isFirstBoot() { // allow instant applications return mFirstBoot; } @Override public boolean isOnlyCoreApps() { // allow instant applications return mOnlyCore; } @Override public boolean isDeviceUpgrading() { // allow instant applications // The system property allows testing ota flow when upgraded to the same image. return mIsUpgrade || SystemProperties.getBoolean( "persist.pm.mock-upgrade", false /* default */); } private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() { final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); final List matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/); if (matches.size() == 1) { return matches.get(0).getComponentInfo().packageName; } else if (matches.size() == 0) { Log.w(TAG, "There should probably be a verifier, but, none were found"); return null; } throw new RuntimeException("There must be exactly one verifier; found " + matches); } private @NonNull String getRequiredSharedLibraryLPr(String name, int version) { synchronized (mLock) { SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version); if (libraryInfo == null) { throw new IllegalStateException("Missing required shared library:" + name); } String packageName = libraryInfo.getPackageName(); if (packageName == null) { throw new IllegalStateException("Expected a package for shared library " + name); } return packageName; } } @NonNull private String getRequiredServicesExtensionPackageLPr() { String servicesExtensionPackage = ensureSystemPackageName( mContext.getString(R.string.config_servicesExtensionPackage)); if (TextUtils.isEmpty(servicesExtensionPackage)) { throw new RuntimeException( "Required services extension package is missing, check " + "config_servicesExtensionPackage."); } return servicesExtensionPackage; } private @NonNull String getRequiredInstallerLPr() { final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setDataAndType(Uri.parse("content://com.example/foo.apk"), PACKAGE_MIME_TYPE); final List matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM); if (matches.size() == 1) { ResolveInfo resolveInfo = matches.get(0); if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) { throw new RuntimeException("The installer must be a privileged app"); } return matches.get(0).getComponentInfo().packageName; } else { throw new RuntimeException("There must be exactly one installer; found " + matches); } } private @NonNull String getRequiredUninstallerLPr() { final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null)); final ResolveInfo resolveInfo = resolveIntent(intent, null, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM); if (resolveInfo == null || mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) { throw new RuntimeException("There must be exactly one uninstaller; found " + resolveInfo); } return resolveInfo.getComponentInfo().packageName; } private @NonNull String getRequiredPermissionControllerLPr() { final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS); intent.addCategory(Intent.CATEGORY_DEFAULT); final List matches = queryIntentActivitiesInternal(intent, null, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM); if (matches.size() == 1) { ResolveInfo resolveInfo = matches.get(0); if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) { throw new RuntimeException("The permissions manager must be a privileged app"); } return matches.get(0).getComponentInfo().packageName; } else { throw new RuntimeException("There must be exactly one permissions manager; found " + matches); } } private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() { final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); final List matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/); ResolveInfo best = null; final int N = matches.size(); for (int i = 0; i < N; i++) { final ResolveInfo cur = matches.get(i); final String packageName = cur.getComponentInfo().packageName; if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { continue; } if (best == null || cur.priority > best.priority) { best = cur; } } if (best != null) { return best.getComponentInfo().getComponentName(); } Slog.w(TAG, "Intent filter verifier not found"); return null; } @Nullable private ComponentName getDomainVerificationAgentComponentNameLPr() { Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION); List matches = queryIntentReceiversInternal(intent, null, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/); ResolveInfo best = null; final int N = matches.size(); for (int i = 0; i < N; i++) { final ResolveInfo cur = matches.get(i); final String packageName = cur.getComponentInfo().packageName; if (checkPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { Slog.w(TAG, "Domain verification agent found but does not hold permission: " + packageName); continue; } if (best == null || cur.priority > best.priority) { if (isComponentEffectivelyEnabled(cur.getComponentInfo(), UserHandle.USER_SYSTEM)) { best = cur; } else { Slog.w(TAG, "Domain verification agent found but not enabled"); } } } if (best != null) { return best.getComponentInfo().getComponentName(); } Slog.w(TAG, "Domain verification agent not found"); return null; } @Override public @Nullable ComponentName getInstantAppResolverComponent() { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } synchronized (mLock) { final ComponentName instantAppResolver = getInstantAppResolverLPr(); if (instantAppResolver == null) { return null; } return instantAppResolver; } } private @Nullable ComponentName getInstantAppResolverLPr() { final String[] packageArray = mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage); if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) { if (DEBUG_INSTANT) { Slog.d(TAG, "Ephemeral resolver NOT found; empty package list"); } return null; } final int callingUid = Binder.getCallingUid(); final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0); final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE); List resolvers = queryIntentServicesInternal(resolverIntent, null, resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/); final int N = resolvers.size(); if (N == 0) { if (DEBUG_INSTANT) { Slog.d(TAG, "Ephemeral resolver NOT found; no matching intent filters"); } return null; } final Set possiblePackages = new ArraySet<>(Arrays.asList(packageArray)); for (int i = 0; i < N; i++) { final ResolveInfo info = resolvers.get(i); if (info.serviceInfo == null) { continue; } final String packageName = info.serviceInfo.packageName; if (!possiblePackages.contains(packageName) && !Build.IS_DEBUGGABLE) { if (DEBUG_INSTANT) { Slog.d(TAG, "Ephemeral resolver not in allowed package list;" + " pkg: " + packageName + ", info:" + info); } continue; } if (DEBUG_INSTANT) { Slog.v(TAG, "Ephemeral resolver found;" + " pkg: " + packageName + ", info:" + info); } return new ComponentName(packageName, info.serviceInfo.name); } if (DEBUG_INSTANT) { Slog.v(TAG, "Ephemeral resolver NOT found"); } return null; } @GuardedBy("mLock") private @Nullable ActivityInfo getInstantAppInstallerLPr() { String[] orderedActions = mIsEngBuild ? new String[]{ Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST", Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE} : new String[]{ Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE}; final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | Intent.FLAG_IGNORE_EPHEMERAL | (mIsEngBuild ? 0 : MATCH_SYSTEM_ONLY); final Intent intent = new Intent(); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); List matches = null; for (String action : orderedActions) { intent.setAction(action); matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE, resolveFlags, UserHandle.USER_SYSTEM); if (matches.isEmpty()) { if (DEBUG_INSTANT) { Slog.d(TAG, "Instant App installer not found with " + action); } } else { break; } } Iterator iter = matches.iterator(); while (iter.hasNext()) { final ResolveInfo rInfo = iter.next(); if (checkPermission( Manifest.permission.INSTALL_PACKAGES, rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) { continue; } iter.remove(); } if (matches.size() == 0) { return null; } else if (matches.size() == 1) { return (ActivityInfo) matches.get(0).getComponentInfo(); } else { throw new RuntimeException( "There must be at most one ephemeral installer; found " + matches); } } private @Nullable ComponentName getInstantAppResolverSettingsLPr( @NonNull ComponentName resolver) { final Intent intent = new Intent(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS) .addCategory(Intent.CATEGORY_DEFAULT) .setPackage(resolver.getPackageName()); final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; List matches = queryIntentActivitiesInternal(intent, null, resolveFlags, UserHandle.USER_SYSTEM); if (matches.isEmpty()) { return null; } return matches.get(0).getComponentInfo().getComponentName(); } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { try { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) { Slog.wtf(TAG, "Package Manager Crash", e); } throw e; } } /** * Returns whether or not a full application can see an instant application. *

    * Currently, there are four cases in which this can occur: *

      *
    1. The calling application is a "special" process. Special processes * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.
    2. *
    3. The calling application has the permission * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.
    4. *
    5. The calling application is the default launcher on the * system partition.
    6. *
    7. The calling application is the default app prediction service.
    8. *
    */ private boolean canViewInstantApps(int callingUid, int userId) { return mComputer.canViewInstantApps(callingUid, userId); } private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { return mComputer.generatePackageInfo(ps, flags, userId); } @Override public void checkPackageStartable(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant applications don't have access to this method"); } if (!mUserManager.exists(userId)) { throw new SecurityException("User doesn't exist"); } enforceCrossUserPermission(callingUid, userId, false, false, "checkPackageStartable"); switch (getPackageStartability(packageName, callingUid, userId)) { case PACKAGE_STARTABILITY_NOT_FOUND: throw new SecurityException("Package " + packageName + " was not found!"); case PACKAGE_STARTABILITY_NOT_SYSTEM: throw new SecurityException("Package " + packageName + " not a system app!"); case PACKAGE_STARTABILITY_FROZEN: throw new SecurityException("Package " + packageName + " is currently frozen!"); case PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED: throw new SecurityException("Package " + packageName + " is not encryption aware!"); case PACKAGE_STARTABILITY_OK: default: return; } } private @PackageStartability int getPackageStartability(String packageName, int callingUid, int userId) { final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId); synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId) || !ps.getInstalled(userId)) { return PACKAGE_STARTABILITY_NOT_FOUND; } if (mSafeMode && !ps.isSystem()) { return PACKAGE_STARTABILITY_NOT_SYSTEM; } if (mFrozenPackages.contains(packageName)) { return PACKAGE_STARTABILITY_FROZEN; } if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) { return PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED; } } return PACKAGE_STARTABILITY_OK; } @Override public boolean isPackageAvailable(String packageName, int userId) { if (!mUserManager.exists(userId)) return false; final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "is package available"); synchronized (mLock) { AndroidPackage p = mPackages.get(packageName); if (p != null) { final PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return false; } if (ps != null) { final PackageUserState state = ps.readUserState(userId); if (state != null) { return PackageParser.isAvailable(state); } } } } return false; } @Override public PackageInfo getPackageInfo(String packageName, int flags, int userId) { return mComputer.getPackageInfo(packageName, flags, userId); } @Override public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags, int userId) { return getPackageInfoInternal(versionedPackage.getPackageName(), versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out packages * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ private PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { return mComputer.getPackageInfoInternal(packageName, versionCode, flags, filterCallingUid, userId); } private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { return mComputer.isComponentVisibleToInstantApp(component); } private boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { return mComputer.isComponentVisibleToInstantApp( component, type); } /** * Returns whether or not access to the application should be filtered. *

    * Access may be limited based upon whether the calling or target applications * are instant applications. * * @see #canViewInstantApps(int, int) */ @GuardedBy("mLock") private boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId) { return mComputer.shouldFilterApplicationLocked(ps, callingUid, component, componentType, userId); } /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ @GuardedBy("mLock") private boolean shouldFilterApplicationLocked( @Nullable PackageSetting ps, int callingUid, int userId) { return mComputer.shouldFilterApplicationLocked( ps, callingUid, userId); } /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ @GuardedBy("mLock") private boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, int userId) { return mComputer.shouldFilterApplicationLocked(sus, callingUid, userId); } @GuardedBy("mLock") private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags) { return mComputer.filterSharedLibPackageLPr(ps, uid, userId, flags); } @Override public String[] currentToCanonicalPackageNames(String[] names) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return names; } final String[] out = new String[names.length]; // reader synchronized (mLock) { final int callingUserId = UserHandle.getUserId(callingUid); final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId); for (int i=names.length-1; i>=0; i--) { final PackageSetting ps = mSettings.getPackageLPr(names[i]); boolean translateName = false; if (ps != null && ps.realName != null) { final boolean targetIsInstantApp = ps.getInstantApp(callingUserId); translateName = !targetIsInstantApp || canViewInstantApps || mInstantAppRegistry.isInstantAccessGranted(callingUserId, UserHandle.getAppId(callingUid), ps.appId); } out[i] = translateName ? ps.realName : names[i]; } } return out; } @Override public String[] canonicalToCurrentPackageNames(String[] names) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return names; } final String[] out = new String[names.length]; // reader synchronized (mLock) { final int callingUserId = UserHandle.getUserId(callingUid); final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId); for (int i=names.length-1; i>=0; i--) { final String cur = mSettings.getRenamedPackageLPr(names[i]); boolean translateName = false; if (cur != null) { final PackageSetting ps = mSettings.getPackageLPr(names[i]); final boolean targetIsInstantApp = ps != null && ps.getInstantApp(callingUserId); translateName = !targetIsInstantApp || canViewInstantApps || mInstantAppRegistry.isInstantAccessGranted(callingUserId, UserHandle.getAppId(callingUid), ps.appId); } out[i] = translateName ? cur : names[i]; } } return out; } @Override public int getPackageUid(String packageName, int flags, int userId) { if (!mUserManager.exists(userId)) return -1; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForPackage(flags, userId); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid"); return getPackageUidInternal(packageName, flags, userId, callingUid); } private int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid); } @Override public int[] getPackageGids(String packageName, int flags, int userId) { if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForPackage(flags, userId); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getPackageGids"); // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; } // TODO: Shouldn't this be checking for package installed state for userId and // return null? return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && ps.isMatch(flags) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId)); } } } return null; } // NOTE: Can't remove due to unsupported app usage @Override public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) { // Because this is accessed via the package manager service AIDL, // go through the permission manager service AIDL return mContext.getSystemService(PermissionManager.class) .getPermissionGroupInfo(groupName, flags); } @GuardedBy("mLock") private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId) { return mComputer.generateApplicationInfoFromSettingsLPw(packageName, flags, filterCallingUid, userId); } @Override public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { return mComputer.getApplicationInfo(packageName, flags, userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out applications * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ private ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId) { return mComputer.getApplicationInfoInternal(packageName, flags, filterCallingUid, userId); } @GuardedBy("mLock") private String normalizePackageNameLPr(String packageName) { String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName); return normalizedPackageName != null ? normalizedPackageName : packageName; } @Override public void deletePreloadsFileCache() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE, "deletePreloadsFileCache"); File dir = Environment.getDataPreloadsFileCacheDirectory(); Slog.i(TAG, "Deleting preloaded file cache " + dir); FileUtils.deleteContents(dir); } @Override public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize, final int storageFlags, final IPackageDataObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, null); mHandler.post(() -> { boolean success = false; try { freeStorage(volumeUuid, freeStorageSize, storageFlags); success = true; } catch (IOException e) { Slog.w(TAG, e); } if (observer != null) { try { observer.onRemoveCompleted(null, success); } catch (RemoteException e) { Slog.w(TAG, e); } } }); } @Override public void freeStorage(final String volumeUuid, final long freeStorageSize, final int storageFlags, final IntentSender pi) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, TAG); mHandler.post(() -> { boolean success = false; try { freeStorage(volumeUuid, freeStorageSize, storageFlags); success = true; } catch (IOException e) { Slog.w(TAG, e); } if (pi != null) { try { pi.sendIntent(null, success ? 1 : 0, null, null, null); } catch (SendIntentException e) { Slog.w(TAG, e); } } }); } /** * Blocking call to clear various types of cached data across the system * until the requested bytes are available. */ public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException { final StorageManager storage = mInjector.getSystemService(StorageManager.class); final File file = storage.findPathForUuid(volumeUuid); if (file.getUsableSpace() >= bytes) return; if (mEnableFreeCacheV2) { final boolean internalVolume = Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid); final boolean aggressive = (storageFlags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0; final long reservedBytes = storage.getStorageCacheBytes(file, storageFlags); // 1. Pre-flight to determine if we have any chance to succeed // 2. Consider preloaded data (after 1w honeymoon, unless aggressive) if (internalVolume && (aggressive || SystemProperties .getBoolean("persist.sys.preloads.file_cache_expired", false))) { deletePreloadsFileCache(); if (file.getUsableSpace() >= bytes) return; } // 3. Consider parsed APK data (aggressive only) if (internalVolume && aggressive) { FileUtils.deleteContents(mCacheDir); if (file.getUsableSpace() >= bytes) return; } // 4. Consider cached app data (above quotas) try { mInstaller.freeCache(volumeUuid, bytes, reservedBytes, Installer.FLAG_FREE_CACHE_V2); } catch (InstallerException ignored) { } if (file.getUsableSpace() >= bytes) return; // 5. Consider shared libraries with refcount=0 and age>min cache period if (internalVolume && pruneUnusedStaticSharedLibraries(bytes, android.provider.Settings.Global.getLong(mContext.getContentResolver(), Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD, DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) { return; } // 6. Consider dexopt output (aggressive only) // TODO: Implement // 7. Consider installed instant apps unused longer than min cache period if (internalVolume && mInstantAppRegistry.pruneInstalledInstantApps(bytes, android.provider.Settings.Global.getLong(mContext.getContentResolver(), Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, InstantAppRegistry.DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } // 8. Consider cached app data (below quotas) try { mInstaller.freeCache(volumeUuid, bytes, reservedBytes, Installer.FLAG_FREE_CACHE_V2 | Installer.FLAG_FREE_CACHE_V2_DEFY_QUOTA); } catch (InstallerException ignored) { } if (file.getUsableSpace() >= bytes) return; // 9. Consider DropBox entries // TODO: Implement // 10. Consider instant meta-data (uninstalled apps) older that min cache period if (internalVolume && mInstantAppRegistry.pruneUninstalledInstantApps(bytes, android.provider.Settings.Global.getLong(mContext.getContentResolver(), Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD, InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } // 11. Free storage service cache StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); long freeBytesRequired = bytes - file.getUsableSpace(); if (freeBytesRequired > 0) { smInternal.freeCache(volumeUuid, freeBytesRequired); } // 12. Clear temp install session files mInstallerService.freeStageDirs(volumeUuid); if (file.getUsableSpace() >= bytes) return; } else { try { mInstaller.freeCache(volumeUuid, bytes, 0, 0); } catch (InstallerException ignored) { } if (file.getUsableSpace() >= bytes) return; } throw new IOException("Failed to free " + bytes + " on storage device at " + file); } private boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod) throws IOException { final StorageManager storage = mInjector.getSystemService(StorageManager.class); final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL); List packagesToDelete = null; final long now = System.currentTimeMillis(); synchronized (mLock) { final int[] allUsers = mUserManager.getUserIds(); final int libCount = mSharedLibraries.size(); for (int i = 0; i < libCount; i++) { final WatchedLongSparseArray versionedLib = mSharedLibraries.valueAt(i); if (versionedLib == null) { continue; } final int versionCount = versionedLib.size(); for (int j = 0; j < versionCount; j++) { SharedLibraryInfo libInfo = versionedLib.valueAt(j); // Skip packages that are not static shared libs. if (!libInfo.isStatic()) { break; } // Important: We skip static shared libs used for some user since // in such a case we need to keep the APK on the device. The check for // a lib being used for any user is performed by the uninstall call. final VersionedPackage declaringPackage = libInfo.getDeclaringPackage(); // Resolve the package name - we use synthetic package names internally final String internalPackageName = resolveInternalPackageNameLPr( declaringPackage.getPackageName(), declaringPackage.getLongVersionCode()); final PackageSetting ps = mSettings.getPackageLPr(internalPackageName); // Skip unused static shared libs cached less than the min period // to prevent pruning a lib needed by a subsequently installed package. if (ps == null || now - ps.lastUpdateTime < maxCachePeriod) { continue; } if (ps.pkg.isSystem()) { continue; } if (packagesToDelete == null) { packagesToDelete = new ArrayList<>(); } packagesToDelete.add(new VersionedPackage(internalPackageName, declaringPackage.getLongVersionCode())); } } } if (packagesToDelete != null) { final int packageCount = packagesToDelete.size(); for (int i = 0; i < packageCount; i++) { final VersionedPackage pkgToDelete = packagesToDelete.get(i); // Delete the package synchronously (will fail of the lib used for any user). if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) { if (volume.getUsableSpace() >= neededSpace) { return true; } } } } return false; } /** * Update given flags when being used to request {@link PackageInfo}. */ private int updateFlagsForPackage(int flags, int userId) { return mComputer.updateFlagsForPackage(flags, userId); } /** * Update given flags when being used to request {@link ApplicationInfo}. */ private int updateFlagsForApplication(int flags, int userId) { return mComputer.updateFlagsForApplication(flags, userId); } /** * Update given flags when being used to request {@link ComponentInfo}. */ private int updateFlagsForComponent(int flags, int userId) { return mComputer.updateFlagsForComponent(flags, userId); } /** * Update given intent when being used to request {@link ResolveInfo}. */ private static Intent updateIntentForResolve(Intent intent) { if (intent.getSelector() != null) { intent = intent.getSelector(); } if (DEBUG_PREFERRED) { intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); } return intent; } /** * Update given flags when being used to request {@link ResolveInfo}. *

    Instant apps are resolved specially, depending upon context. Minimally, * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT} * flag set. However, this flag is only honoured in three circumstances: *

      *
    • when called from a system process
    • *
    • when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}
    • *
    • when resolution occurs to start an activity with a {@code android.intent.action.VIEW} * action and a {@code android.intent.category.BROWSABLE} category
    • *
    */ private int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { return mComputer.updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc); } private int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { return mComputer.updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, onlyExposedExplicitly, isImplicitImageCaptureIntentAndNotSetByDpc); } @Override public int getTargetSdkVersion(String packageName) { synchronized (mLock) { final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { return -1; } final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (shouldFilterApplicationLocked(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) { return -1; } return pkg.getTargetSdkVersion(); } } @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { return mComputer.getActivityInfo(component, flags, userId); } /** * Important: The provided filterCallingUid is used exclusively to filter out activities * that can be seen based on user state. It's typically the original caller uid prior * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ private ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) { return mComputer.getActivityInfoInternal(component, flags, filterCallingUid, userId); } @Override public boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) { synchronized (mLock) { if (component.equals(mResolveComponentName)) { // The resolver supports EVERYTHING! return true; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); ParsedActivity a = mComponentResolver.getActivity(component); if (a == null) { return false; } PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); if (ps == null) { return false; } if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) { return false; } for (int i=0; i< a.getIntents().size(); i++) { if (a.getIntents().get(i).match(intent.getAction(), resolvedType, intent.getScheme(), intent.getData(), intent.getCategories(), TAG) >= 0) { return true; } } return false; } } @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId); enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get receiver info"); synchronized (mLock) { ParsedActivity a = mComponentResolver.getReceiver(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); if (a == null) { return null; } AndroidPackage pkg = mPackages.get(a.getPackageName()); if (pkg == null) { return null; } if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_RECEIVER, userId)) { return null; } return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId, ps); } } return null; } @Override public ParceledListSlice getSharedLibraries(String packageName, int flags, int userId) { if (!mUserManager.exists(userId)) return null; Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0"); final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return null; } flags = updateFlagsForPackage(flags, userId); final boolean canSeeStaticLibraries = mContext.checkCallingOrSelfPermission(INSTALL_PACKAGES) == PERMISSION_GRANTED || mContext.checkCallingOrSelfPermission(DELETE_PACKAGES) == PERMISSION_GRANTED || canRequestPackageInstallsInternal(packageName, callingUid, userId, false /* throwIfPermNotDeclared*/) || mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES) == PERMISSION_GRANTED || mContext.checkCallingOrSelfPermission( Manifest.permission.ACCESS_SHARED_LIBRARIES) == PERMISSION_GRANTED; synchronized (mLock) { List result = null; final int libCount = mSharedLibraries.size(); for (int i = 0; i < libCount; i++) { WatchedLongSparseArray versionedLib = mSharedLibraries.valueAt(i); if (versionedLib == null) { continue; } final int versionCount = versionedLib.size(); for (int j = 0; j < versionCount; j++) { SharedLibraryInfo libInfo = versionedLib.valueAt(j); if (!canSeeStaticLibraries && libInfo.isStatic()) { break; } final long identity = Binder.clearCallingIdentity(); try { PackageInfo packageInfo = getPackageInfoVersioned( libInfo.getDeclaringPackage(), flags | PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId); if (packageInfo == null) { continue; } } finally { Binder.restoreCallingIdentity(identity); } SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(), libInfo.getPackageName(), libInfo.getAllCodePaths(), libInfo.getName(), libInfo.getLongVersion(), libInfo.getType(), libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo, flags, callingUid, userId), (libInfo.getDependencies() == null ? null : new ArrayList<>(libInfo.getDependencies())), libInfo.isNative()); if (result == null) { result = new ArrayList<>(); } result.add(resLibInfo); } } return result != null ? new ParceledListSlice<>(result) : null; } } @Nullable @Override public ParceledListSlice getDeclaredSharedLibraries( @NonNull String packageName, int flags, @NonNull int userId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES, "getDeclaredSharedLibraries"); int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "getDeclaredSharedLibraries"); Preconditions.checkNotNull(packageName, "packageName cannot be null"); Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0"); if (!mUserManager.exists(userId)) { return null; } if (getInstantAppPackageName(callingUid) != null) { return null; } synchronized (mLock) { List result = null; int libraryCount = mSharedLibraries.size(); for (int i = 0; i < libraryCount; i++) { WatchedLongSparseArray versionedLibrary = mSharedLibraries.valueAt(i); if (versionedLibrary == null) { continue; } int versionCount = versionedLibrary.size(); for (int j = 0; j < versionCount; j++) { SharedLibraryInfo libraryInfo = versionedLibrary.valueAt(j); VersionedPackage declaringPackage = libraryInfo.getDeclaringPackage(); if (!Objects.equals(declaringPackage.getPackageName(), packageName)) { continue; } final long identity = Binder.clearCallingIdentity(); try { PackageInfo packageInfo = getPackageInfoVersioned(declaringPackage, flags | PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId); if (packageInfo == null) { continue; } } finally { Binder.restoreCallingIdentity(identity); } SharedLibraryInfo resultLibraryInfo = new SharedLibraryInfo( libraryInfo.getPath(), libraryInfo.getPackageName(), libraryInfo.getAllCodePaths(), libraryInfo.getName(), libraryInfo.getLongVersion(), libraryInfo.getType(), libraryInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr( libraryInfo, flags, callingUid, userId), libraryInfo.getDependencies() == null ? null : new ArrayList<>(libraryInfo.getDependencies()), libraryInfo.isNative()); if (result == null) { result = new ArrayList<>(); } result.add(resultLibraryInfo); } } return result != null ? new ParceledListSlice<>(result) : null; } } @GuardedBy("mLock") private List getPackagesUsingSharedLibraryLPr( SharedLibraryInfo libInfo, int flags, int callingUid, int userId) { List versionedPackages = null; final int packageCount = mSettings.getPackagesLocked().size(); for (int i = 0; i < packageCount; i++) { PackageSetting ps = mSettings.getPackagesLocked().valueAt(i); if (ps == null) { continue; } if (!ps.readUserState(userId).isAvailable(flags)) { continue; } final String libName = libInfo.getName(); if (libInfo.isStatic()) { final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName); if (libIdx < 0) { continue; } if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } if (versionedPackages == null) { versionedPackages = new ArrayList<>(); } // If the dependent is a static shared lib, use the public package name String dependentPackageName = ps.name; if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) { dependentPackageName = ps.pkg.getManifestPackageName(); } versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode)); } else if (ps.pkg != null) { if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName) || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) { if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } if (versionedPackages == null) { versionedPackages = new ArrayList<>(); } versionedPackages.add(new VersionedPackage(ps.name, ps.versionCode)); } } } return versionedPackages; } @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { return mComputer.getServiceInfo(component, flags, userId); } @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId); enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get provider info"); synchronized (mLock) { ParsedProvider p = mComponentResolver.getProvider(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); if (p == null) { return null; } AndroidPackage pkg = mPackages.get(p.getPackageName()); if (pkg == null) { return null; } if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) { PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_PROVIDER, userId)) { return null; } PackageUserState state = ps.readUserState(userId); final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo( pkg, flags, state, userId, ps); if (appInfo == null) { return null; } return PackageInfoUtils.generateProviderInfo( pkg, p, flags, state, appInfo, userId, ps); } } return null; } @Override public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags) { return mModuleInfoProvider.getModuleInfo(packageName, flags); } @Override public List getInstalledModules(int flags) { return mModuleInfoProvider.getInstalledModules(flags); } @Override public String[] getSystemSharedLibraryNames() { // allow instant applications synchronized (mLock) { Set libs = null; final int libCount = mSharedLibraries.size(); for (int i = 0; i < libCount; i++) { WatchedLongSparseArray versionedLib = mSharedLibraries.valueAt(i); if (versionedLib == null) { continue; } final int versionCount = versionedLib.size(); for (int j = 0; j < versionCount; j++) { SharedLibraryInfo libraryInfo = versionedLib.valueAt(j); if (!libraryInfo.isStatic()) { if (libs == null) { libs = new ArraySet<>(); } libs.add(libraryInfo.getName()); break; } PackageSetting ps = mSettings.getPackageLPr(libraryInfo.getPackageName()); if (ps != null && !filterSharedLibPackageLPr(ps, Binder.getCallingUid(), UserHandle.getUserId(Binder.getCallingUid()), PackageManager.MATCH_STATIC_SHARED_LIBRARIES)) { if (libs == null) { libs = new ArraySet<>(); } libs.add(libraryInfo.getName()); break; } } } if (libs != null) { String[] libsArray = new String[libs.size()]; libs.toArray(libsArray); return libsArray; } return null; } } @Override public @NonNull String getServicesSystemSharedLibraryPackageName() { // allow instant applications synchronized (mLock) { return mServicesExtensionPackageName; } } @Override public @NonNull String getSharedSystemSharedLibraryPackageName() { // allow instant applications synchronized (mLock) { return mSharedSystemSharedLibraryPackageName; } } @GuardedBy("mLock") private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) { for (int i = userList.length - 1; i >= 0; --i) { final int userId = userList[i]; SparseArray changedPackages = mChangedPackages.get(userId); if (changedPackages == null) { changedPackages = new SparseArray<>(); mChangedPackages.put(userId, changedPackages); } Map sequenceNumbers = mChangedPackagesSequenceNumbers.get(userId); if (sequenceNumbers == null) { sequenceNumbers = new HashMap<>(); mChangedPackagesSequenceNumbers.put(userId, sequenceNumbers); } final Integer sequenceNumber = sequenceNumbers.get(pkgSetting.name); if (sequenceNumber != null) { changedPackages.remove(sequenceNumber); } changedPackages.put(mChangedPackagesSequenceNumber, pkgSetting.name); sequenceNumbers.put(pkgSetting.name, mChangedPackagesSequenceNumber); } mChangedPackagesSequenceNumber++; } @Override public ChangedPackages getChangedPackages(int sequenceNumber, int userId) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return null; } if (!mUserManager.exists(userId)) { return null; } enforceCrossUserPermission(callingUid, userId, false, false, "getChangedPackages"); synchronized (mLock) { if (sequenceNumber >= mChangedPackagesSequenceNumber) { return null; } final SparseArray changedPackages = mChangedPackages.get(userId); if (changedPackages == null) { return null; } final List packageNames = new ArrayList<>(mChangedPackagesSequenceNumber - sequenceNumber); for (int i = sequenceNumber; i < mChangedPackagesSequenceNumber; i++) { final String packageName = changedPackages.get(i); if (packageName != null) { // Filter out the changes if the calling package should not be able to see it. final PackageSetting ps = mSettings.getPackageLPr(packageName); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } packageNames.add(packageName); } } return packageNames.isEmpty() ? null : new ChangedPackages(mChangedPackagesSequenceNumber, packageNames); } } @Override public @NonNull ParceledListSlice getSystemAvailableFeatures() { // allow instant applications ArrayList 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 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 @Override public int checkPermission(String permName, String pkgName, int userId) { return mPermissionManager.checkPermission(pkgName, permName, userId); } // NOTE: Can't remove without a major refactor. Keep around for now. @Override public int checkUidPermission(String permName, int uid) { return mComputer.checkUidPermission(permName, uid); } @Override public String getPermissionControllerPackageName() { synchronized (mLock) { if (mRequiredPermissionControllerPackage != null) { final PackageSetting ps = getPackageSetting(mRequiredPermissionControllerPackage); if (ps != null) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (!shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return mRequiredPermissionControllerPackage; } } } throw new IllegalStateException("PermissionController is not found"); } } String getPackageInstallerPackageName() { synchronized (mLock) { return mRequiredInstallerPackage; } } // NOTE: Can't remove due to unsupported app usage @Override public boolean addPermission(PermissionInfo info) { // Because this is accessed via the package manager service AIDL, // go through the permission manager service AIDL return mContext.getSystemService(PermissionManager.class).addPermission(info, false); } // NOTE: Can't remove due to unsupported app usage @Override public boolean addPermissionAsync(PermissionInfo info) { // Because this is accessed via the package manager service AIDL, // go through the permission manager service AIDL return mContext.getSystemService(PermissionManager.class).addPermission(info, true); } // NOTE: Can't remove due to unsupported app usage @Override public void removePermission(String permName) { // Because this is accessed via the package manager service AIDL, // go through the permission manager service AIDL mContext.getSystemService(PermissionManager.class).removePermission(permName); } // NOTE: Can't remove due to unsupported app usage @Override public void grantRuntimePermission(String packageName, String permName, final int userId) { // Because this is accessed via the package manager service AIDL, // go through the permission manager service AIDL mContext.getSystemService(PermissionManager.class) .grantRuntimePermission(packageName, permName, UserHandle.of(userId)); } @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); } } @Override public int checkSignatures(String pkg1, String pkg2) { synchronized (mLock) { final AndroidPackage p1 = mPackages.get(pkg1); final AndroidPackage p2 = mPackages.get(pkg2); final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName()); final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName()); if (p1 == null || ps1 == null || p2 == null || ps2 == null) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId) || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } return checkSignaturesInternal(p1.getSigningDetails(), p2.getSigningDetails()); } } @Override public int checkUidSignatures(int uid1, int uid2) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); // Map to base uids. final int appId1 = UserHandle.getAppId(uid1); final int appId2 = UserHandle.getAppId(uid2); // reader synchronized (mLock) { SigningDetails p1SigningDetails; SigningDetails p2SigningDetails; Object obj = mSettings.getSettingLPr(appId1); if (obj != null) { if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } p1SigningDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } p1SigningDetails = ps.signatures.mSigningDetails; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } obj = mSettings.getSettingLPr(appId2); if (obj != null) { if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } p2SigningDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } p2SigningDetails = ps.signatures.mSigningDetails; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } return checkSignaturesInternal(p1SigningDetails, p2SigningDetails); } } private int checkSignaturesInternal(SigningDetails p1SigningDetails, SigningDetails p2SigningDetails) { if (p1SigningDetails == null) { return p2SigningDetails == null ? PackageManager.SIGNATURE_NEITHER_SIGNED : PackageManager.SIGNATURE_FIRST_NOT_SIGNED; } if (p2SigningDetails == null) { return PackageManager.SIGNATURE_SECOND_NOT_SIGNED; } int result = compareSignatures(p1SigningDetails.signatures, p2SigningDetails.signatures); if (result == PackageManager.SIGNATURE_MATCH) { return result; } // To support backwards compatibility with clients of this API expecting pre-key // rotation results if either of the packages has a signing lineage the oldest signer // in the lineage is used for signature verification. if (p1SigningDetails.hasPastSigningCertificates() || p2SigningDetails.hasPastSigningCertificates()) { Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates() ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]} : p1SigningDetails.signatures; Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates() ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]} : p2SigningDetails.signatures; result = compareSignatures(p1Signatures, p2Signatures); } return result; } @Override public boolean hasSigningCertificate( String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) { synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); if (p == null) { return false; } final PackageSetting ps = getPackageSetting(p.getPackageName()); if (ps == null) { return false; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return false; } switch (type) { case CERT_INPUT_RAW_X509: return p.getSigningDetails().hasCertificate(certificate); case CERT_INPUT_SHA256: return p.getSigningDetails().hasSha256Certificate(certificate); default: return false; } } } @Override public boolean hasUidSigningCertificate( int uid, byte[] certificate, @PackageManager.CertificateInputType int type) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); // Map to base uids. final int appId = UserHandle.getAppId(uid); // reader synchronized (mLock) { final PackageParser.SigningDetails signingDetails; final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return false; } signingDetails = sus.signatures.mSigningDetails; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return false; } signingDetails = ps.signatures.mSigningDetails; } else { return false; } } else { return false; } switch (type) { case CERT_INPUT_RAW_X509: return signingDetails.hasCertificate(certificate); case CERT_INPUT_SHA256: return signingDetails.hasSha256Certificate(certificate); default: return false; } } } /** * If the database version for this type of package (internal storage or * external storage) is less than the version where package signatures * were updated, return true. */ private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) { return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) { return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY; } private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) { return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) { return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER; } @Override public List getAllPackages() { // Allow iorapd to call this method. if (Binder.getCallingUid() != Process.IORAPD_UID) { enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers"); } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { if (canViewInstantApps(callingUid, callingUserId)) { return new ArrayList<>(mPackages.keySet()); } final String instantAppPkgName = getInstantAppPackageName(callingUid); final List result = new ArrayList<>(); if (instantAppPkgName != null) { // caller is an instant application; filter unexposed applications for (AndroidPackage pkg : mPackages.values()) { if (!pkg.isVisibleToInstantApps()) { continue; } result.add(pkg.getPackageName()); } } else { // caller is a normal application; filter instant applications for (AndroidPackage pkg : mPackages.values()) { final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null && ps.getInstantApp(callingUserId) && !mInstantAppRegistry.isInstantAccessGranted( callingUserId, UserHandle.getAppId(callingUid), ps.appId)) { continue; } result.add(pkg.getPackageName()); } } return result; } } /** * IMPORTANT: Not all packages returned by this method may be known * to the system. There are two conditions in which this may occur: *
      *
    1. The package is on adoptable storage and the device has been removed
    2. *
    3. The package is being removed and the internal structures are partially updated
    4. *
    * The second is an artifact of the current data structures and should be fixed. See * b/111075456 for one such instance. * This binder API is cached. If the algorithm in this method changes, * or if the underlying objecs (as returned by getSettingLPr()) change * then the logic that invalidates the cache must be revisited. See * calls to invalidateGetPackagesForUidCache() to locate the points at * which the cache is invalidated. */ @Override public String[] getPackagesForUid(int uid) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(uid); enforceCrossUserOrProfilePermission(callingUid, userId, /* requireFullPermission */ false, /* checkShell */ false, "getPackagesForUid"); return mComputer.getPackagesForUid(uid); } @Override public String getNameForUid(int uid) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return null; } final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return null; } return sus.name + ":" + sus.userId; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return null; } return ps.name; } return null; } } @Override public String[] getNamesForUids(int[] uids) { if (uids == null || uids.length == 0) { return null; } final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return null; } final int callingUserId = UserHandle.getUserId(callingUid); final String[] names = new String[uids.length]; synchronized (mLock) { for (int i = uids.length - 1; i >= 0; i--) { final int appId = UserHandle.getAppId(uids[i]); final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { names[i] = null; } else { names[i] = "shared:" + sus.name; } } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { names[i] = null; } else { names[i] = ps.name; } } else { names[i] = null; } } } return names; } @Override public int getUidForSharedUser(String sharedUserName) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return -1; } if (sharedUserName == null) { return -1; } // reader synchronized (mLock) { SharedUserSetting suid; try { suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false); if (suid != null) { return suid.userId; } } catch (PackageManagerException ignore) { // can't happen, but, still need to catch it } return -1; } } @Override public int getFlagsForUid(int uid) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return 0; } final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return 0; } return sus.pkgFlags; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return 0; } return ps.pkgFlags; } } return 0; } @Override public int getPrivateFlagsForUid(int uid) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return 0; } final int callingUserId = UserHandle.getUserId(callingUid); final int appId = UserHandle.getAppId(uid); synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; if (shouldFilterApplicationLocked(sus, callingUid, callingUserId)) { return 0; } return sus.pkgPrivateFlags; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return 0; } return ps.pkgPrivateFlags; } } return 0; } @Override public boolean isUidPrivileged(int uid) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return false; } final int appId = UserHandle.getAppId(uid); // reader synchronized (mLock) { final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; final int numPackages = sus.packages.size(); for (int index = 0; index < numPackages; index++) { final PackageSetting ps = sus.packages.valueAt(index); if (ps.isPrivileged()) { return true; } } } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; return ps.isPrivileged(); } } return false; } // NOTE: Can't remove due to unsupported app usage @NonNull @Override public String[] getAppOpPermissionPackages(String permissionName) { if (permissionName == null) { return EmptyArray.STRING; } if (getInstantAppPackageName(getCallingUid()) != null) { return EmptyArray.STRING; } return mPermissionManager.getAppOpPermissionPackages(permissionName); } @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { return resolveIntentInternal(intent, resolvedType, flags, 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid()); } /** * Normally instant apps can only be resolved when they're visible to the caller. * However, if {@code resolveForStart} is {@code true}, all instant apps are visible * since we need to allow the system to start any installed application. */ private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "resolve intent"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, privateResolveFlags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); final boolean queryMayBeFiltered = UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID && !resolveForStart; final ResolveInfo bestChoice = chooseBestActivity( intent, resolvedType, flags, privateResolveFlags, query, userId, queryMayBeFiltered); final boolean nonBrowserOnly = (privateResolveFlags & PackageManagerInternal.RESOLVE_NON_BROWSER_ONLY) != 0; if (nonBrowserOnly && bestChoice != null && bestChoice.handleAllWebDataURI) { return null; } return bestChoice; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @Override public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) { if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) { throw new SecurityException( "findPersistentPreferredActivity can only be run by the system"); } if (!mUserManager.exists(userId)) { return null; } final int callingUid = Binder.getCallingUid(); intent = updateIntentForResolve(intent); final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver()); final int flags = updateFlagsForResolve( 0, userId, callingUid, false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, 0)); final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); synchronized (mLock) { return findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false, userId); } } @Override public void setLastChosenActivity(Intent intent, String resolvedType, int flags, IntentFilter filter, int match, ComponentName activity) { setLastChosenActivity(intent, resolvedType, flags, new WatchedIntentFilter(filter), match, activity); } /** * Variant that takes a {@link WatchedIntentFilter} */ public void setLastChosenActivity(Intent intent, String resolvedType, int flags, WatchedIntentFilter filter, int match, ComponentName activity) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } final int userId = UserHandle.getCallingUserId(); if (DEBUG_PREFERRED) { Log.v(TAG, "setLastChosenActivity intent=" + intent + " resolvedType=" + resolvedType + " flags=" + flags + " filter=" + filter + " match=" + match + " activity=" + activity); filter.dump(new PrintStreamPrinter(System.out), " "); } intent.setComponent(null); final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivityNotLocked( intent, resolvedType, flags, query, 0, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivity(filter, match, null, activity, false, userId, "Setting last chosen", false); } @Override public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } final int userId = UserHandle.getCallingUserId(); if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent); final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); return findPreferredActivityNotLocked( intent, resolvedType, flags, query, 0, false, false, false, userId); } private 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); } private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, int privateResolveFlags, List query, int userId, boolean queryMayBeFiltered) { if (query != null) { final int N = query.size(); if (N == 1) { return query.get(0); } else if (N > 1) { final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); // If there is more than one activity with the same priority, // then let the user decide between them. ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); if (DEBUG_INTENT_MATCHING || debug) { Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " + r1.activityInfo.name + "=" + r1.priority); } // If the first activity has a higher priority, or a different // default, then it is always desirable to pick it. if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder || r0.isDefault != r1.isDefault) { return query.get(0); } // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } int browserCount = 0; for (int i = 0; i < N; i++) { ri = query.get(i); if (ri.handleAllWebDataURI) { browserCount++; } // If we have an ephemeral app, use it if (ri.activityInfo.applicationInfo.isInstantApp()) { final String packageName = ri.activityInfo.packageName; final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags, userId)) { return ri; } } } if ((privateResolveFlags & PackageManagerInternal.RESOLVE_NON_RESOLVER_ONLY) != 0) { return null; } ri = new ResolveInfo(mResolveInfo); // if all resolve options are browsers, mark the resolver's info as if it were // also a browser. ri.handleAllWebDataURI = browserCount == N; ri.activityInfo = new ActivityInfo(ri.activityInfo); ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); // If all of the options come from the same package, show the application's // label and icon instead of the generic resolver's. // Some calls like Intent.resolveActivityInfo query the ResolveInfo from here // and then throw away the ResolveInfo itself, meaning that the caller loses // the resolvePackageName. Therefore the activityInfo.labelRes above provides // a fallback for this case; we only set the target package's resources on // the ResolveInfo, not the ActivityInfo. final String intentPackage = intent.getPackage(); if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) { final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo; ri.resolvePackageName = intentPackage; if (userNeedsBadging(userId)) { ri.noResourceId = true; } else { ri.icon = appi.icon; } ri.iconResourceId = appi.icon; ri.labelRes = appi.labelRes; } ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); if (userId != 0) { ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); } // Make sure that the resolver is displayable in car mode if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle(); ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true); return ri; } } return null; } /** * Do NOT use for intent resolution filtering. That should be done with * {@link DomainVerificationManagerInternal#filterToApprovedApp(Intent, List, int, Function)}. * * @return if the package is approved at any non-zero level for the domain in the intent */ private static boolean hasAnyDomainApproval( @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting, @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) { return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId) > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE; } /** * Return true if the given list is not empty and all of its contents have * an activityInfo with the given package name. */ private boolean allHavePackage(List list, String packageName) { if (ArrayUtils.isEmpty(list)) { return false; } for (int i = 0, N = list.size(); i < N; i++) { final ResolveInfo ri = list.get(i); final ActivityInfo ai = ri != null ? ri.activityInfo : null; if (ai == null || !packageName.equals(ai.packageName)) { return false; } } return true; } /** * From Android R, camera intents have to match system apps. The only exception to this is if * the DPC has set the camera persistent preferred activity. This case was introduced * because it is important that the DPC has the ability to set both system and non-system * camera persistent preferred activities. * * @return {@code true} if the intent is a camera intent and the persistent preferred * activity was not set by the DPC. */ @GuardedBy("mLock") private boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, String resolvedType, int flags) { return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags); } @GuardedBy("mLock") private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId) { return mComputer.findPersistentPreferredActivityLP(intent, resolvedType, flags, query, debug, userId); } private static boolean isHomeIntent(Intent intent) { return ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(CATEGORY_HOME) && intent.hasCategory(CATEGORY_DEFAULT); } // findPreferredActivityBody returns two items: a "things changed" flag and a // ResolveInfo, which is the preferred activity itself. private static class FindPreferredActivityBodyResult { boolean mChanged; ResolveInfo mPreferredResolveInfo; } private FindPreferredActivityBodyResult findPreferredActivityInternal( Intent intent, String resolvedType, int flags, List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { return mComputer.findPreferredActivityInternal( intent, resolvedType, flags, query, always, removeMatches, debug, userId, queryMayBeFiltered); } ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, List query, int priority, boolean always, boolean removeMatches, boolean debug, int userId) { return findPreferredActivityNotLocked( intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId, UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID); } // TODO: handle preferred activities missing while user has amnesia /** must not hold {@link #mLock} */ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, List query, int priority, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mLock", new Throwable()); } if (!mUserManager.exists(userId)) return null; FindPreferredActivityBodyResult body = findPreferredActivityInternal( intent, resolvedType, flags, query, always, removeMatches, debug, userId, queryMayBeFiltered); if (body.mChanged) { if (DEBUG_PREFERRED) { Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); } synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) { Slog.v(TAG, "No preferred activity to return"); } return body.mPreferredResolveInfo; } /* * Returns if intent can be forwarded from the sourceUserId to the targetUserId */ @Override public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId, int targetUserId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); List matches = getMatchingCrossProfileIntentFilters(intent, resolvedType, sourceUserId); if (matches != null) { int size = matches.size(); for (int i = 0; i < size; i++) { if (matches.get(i).getTargetUserId() == targetUserId) return true; } } if (intent.hasWebURI()) { // cross-profile app linking works only towards the parent. final int callingUid = Binder.getCallingUid(); final UserInfo parent = getProfileParent(sourceUserId); if (parent == null) { return false; } synchronized (mLock) { int flags = updateFlagsForResolve(0, parent.id, callingUid, false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id, resolvedType, 0)); flags |= PackageManager.MATCH_DEFAULT_ONLY; CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr( intent, resolvedType, flags, sourceUserId, parent.id); return xpDomainInfo != null; } } return false; } private UserInfo getProfileParent(int userId) { return mComputer.getProfileParent(userId); } private List getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId) { return mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); } @Override public @NonNull ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); return new ParceledListSlice<>( queryIntentActivitiesInternal(intent, resolvedType, flags, userId)); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Returns the package name of the calling Uid if it's an instant app. If it isn't * instant, returns {@code null}. */ private String getInstantAppPackageName(int callingUid) { return mComputer.getInstantAppPackageName(callingUid); } private @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId) { return mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags, userId); } // Collect the results of queryIntentActivitiesInternalBody into a single class private static class QueryIntentActivitiesResult { public boolean sortResult = false; public boolean addInstant = false; public List result = null; public List answer = null; QueryIntentActivitiesResult(List l) { answer = l; } QueryIntentActivitiesResult(boolean s, boolean a, List l) { sortResult = s; addInstant = a; result = l; } } private @NonNull List queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { return mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags, privateResolveFlags, filterCallingUid, userId, resolveForStart, allowDynamicSplits); } private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName) { return mComputer.queryIntentActivitiesInternalBody( intent, resolvedType, flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName); } private static class CrossProfileDomainInfo { /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */ ResolveInfo resolveInfo; int highestApprovalLevel; CrossProfileDomainInfo(ResolveInfo resolveInfo, int highestApprovalLevel) { this.resolveInfo = resolveInfo; this.highestApprovalLevel = highestApprovalLevel; } @Override public String toString() { return "CrossProfileDomainInfo{" + "resolveInfo=" + resolveInfo + ", highestApprovalLevel=" + highestApprovalLevel + '}'; } } private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { return mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, sourceUserId, parentUserId); } /** * Filters out ephemeral activities. *

    When resolving for an ephemeral app, only activities that 1) are defined in the * ephemeral app or 2) marked with {@code visibleToEphemeral} are returned. * * @param resolveInfos The pre-filtered list of resolved activities * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering * is performed. * @param intent * @return A filtered list of resolved activities. */ private List applyPostResolutionFilter(@NonNull List resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { return mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); } @Override public @NonNull ParceledListSlice queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { return new ParceledListSlice<>(queryIntentActivityOptionsInternal(caller, specifics, specificTypes, intent, resolvedType, flags, userId)); } private @NonNull List queryIntentActivityOptionsInternal(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "query intent activity options"); final String resultsAction = intent.getAction(); final List results = queryIntentActivitiesInternal(intent, resolvedType, flags | PackageManager.GET_RESOLVED_FILTER, userId); if (DEBUG_INTENT_MATCHING) { Log.v(TAG, "Query " + intent + ": " + results); } int specificsPos = 0; int N; // todo: note that the algorithm used here is O(N^2). This // isn't a problem in our current environment, but if we start running // into situations where we have more than 5 or 10 matches then this // should probably be changed to something smarter... // First we go through and resolve each of the specific items // that were supplied, taking care of removing any corresponding // duplicate items in the generic resolve list. if (specifics != null) { for (int i=0; i it = rii.filter.actionsIterator(); if (it == null) { continue; } while (it.hasNext()) { final String action = it.next(); if (resultsAction != null && resultsAction.equals(action)) { // If this action was explicitly requested, then don't // remove things that have it. continue; } for (int j=i+1; j queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { return new ParceledListSlice<>( queryIntentReceiversInternal(intent, resolvedType, flags, userId, false /*allowDynamicSplits*/)); } private @NonNull List queryIntentReceiversInternal(Intent intent, String resolvedType, int flags, int userId, boolean allowDynamicSplits) { if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "query intent receivers"); final String instantAppPkgName = getInstantAppPackageName(callingUid); flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, flags)); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList<>(1); final ActivityInfo ai = getReceiverInfo(comp, flags, userId); if (ai != null) { // When specifying an explicit component, we prevent the activity from being // used when either 1) the calling package is normal and the activity is within // an instant application or 2) the calling package is ephemeral and the // activity is not visible to instant applications. final boolean matchInstantApp = (flags & PackageManager.MATCH_INSTANT) != 0; final boolean matchVisibleToInstantAppOnly = (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; final boolean matchExplicitlyVisibleOnly = (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; final boolean isCallerInstantApp = instantAppPkgName != null; final boolean isTargetSameInstantApp = comp.getPackageName().equals(instantAppPkgName); final boolean isTargetInstantApp = (ai.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetVisibleToInstantApp = (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean isTargetExplicitlyVisibleToInstantApp = isTargetVisibleToInstantApp && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; final boolean isTargetHiddenFromInstantApp = !isTargetVisibleToInstantApp || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp); final boolean blockResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); if (!blockResolution) { ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } } return applyPostResolutionFilter( list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } // reader synchronized (mLock) { String pkgName = intent.getPackage(); if (pkgName == null) { final List result = mComponentResolver.queryReceivers(intent, resolvedType, flags, userId); if (result == null) { return Collections.emptyList(); } return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List result = mComponentResolver.queryReceivers( intent, resolvedType, flags, pkg.getReceivers(), userId); if (result == null) { return Collections.emptyList(); } return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } return Collections.emptyList(); } } @Override public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { final int callingUid = Binder.getCallingUid(); return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid); } private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); List query = queryIntentServicesInternal( intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/); if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, // just arbitrarily pick the first one. return query.get(0); } } return null; } @Override public @NonNull ParceledListSlice queryIntentServices(Intent intent, String resolvedType, int flags, int userId) { final int callingUid = Binder.getCallingUid(); return new ParceledListSlice<>(queryIntentServicesInternal( intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/)); } private @NonNull List queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps) { return mComputer.queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid, includeInstantApps); } @Override public @NonNull ParceledListSlice queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) { return new ParceledListSlice<>( queryIntentContentProvidersInternal(intent, resolvedType, flags, userId)); } private @NonNull List queryIntentContentProvidersInternal( Intent intent, String resolvedType, int flags, int userId) { if (!mUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); final String instantAppPkgName = getInstantAppPackageName(callingUid); flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } if (comp != null) { final List list = new ArrayList<>(1); final ProviderInfo pi = getProviderInfo(comp, flags, userId); if (pi != null) { // When specifying an explicit component, we prevent the provider from being // used when either 1) the provider is in an instant application and the // caller is not the same instant application or 2) the calling package is an // instant application and the provider is not visible to instant applications. final boolean matchInstantApp = (flags & PackageManager.MATCH_INSTANT) != 0; final boolean matchVisibleToInstantAppOnly = (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; final boolean isCallerInstantApp = instantAppPkgName != null; final boolean isTargetSameInstantApp = comp.getPackageName().equals(instantAppPkgName); final boolean isTargetInstantApp = (pi.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetHiddenFromInstantApp = (pi.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0; final boolean blockResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp && shouldFilterApplicationLocked( getPackageSettingInternal(pi.applicationInfo.packageName, Process.SYSTEM_UID), callingUid, userId); if (!blockResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.providerInfo = pi; list.add(ri); } } return list; } // reader synchronized (mLock) { String pkgName = intent.getPackage(); if (pkgName == null) { final List resolveInfos = mComponentResolver.queryProviders(intent, resolvedType, flags, userId); if (resolveInfos == null) { return Collections.emptyList(); } return applyPostContentProviderResolutionFilter( resolveInfos, instantAppPkgName, userId, callingUid); } final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List resolveInfos = mComponentResolver.queryProviders(intent, resolvedType, flags, pkg.getProviders(), userId); if (resolveInfos == null) { return Collections.emptyList(); } return applyPostContentProviderResolutionFilter( resolveInfos, instantAppPkgName, userId, callingUid); } return Collections.emptyList(); } } private List applyPostContentProviderResolutionFilter( List resolveInfos, String instantAppPkgName, @UserIdInt int userId, int callingUid) { for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); if (instantAppPkgName == null) { SettingBase callingSetting = mSettings.getSettingLPr(UserHandle.getAppId(callingUid)); PackageSetting resolvedSetting = getPackageSettingInternal(info.providerInfo.packageName, 0); if (!mAppsFilter.shouldFilterApplication( callingUid, callingSetting, resolvedSetting, userId)) { continue; } } final boolean isEphemeralApp = info.providerInfo.applicationInfo.isInstantApp(); // allow providers that are defined in the provided package if (isEphemeralApp && instantAppPkgName.equals(info.providerInfo.packageName)) { if (info.providerInfo.splitName != null && !ArrayUtils.contains(info.providerInfo.applicationInfo.splitNames, info.providerInfo.splitName)) { if (mInstantAppInstallerActivity == null) { if (DEBUG_INSTANT) { Slog.v(TAG, "No installer - not adding it to the ResolveInfo list"); } resolveInfos.remove(i); continue; } // requested provider is defined in a split that hasn't been installed yet. // add the installer to the resolve list if (DEBUG_INSTANT) { Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); } final ResolveInfo installerInfo = new ResolveInfo( mInstantAppInstallerInfo); installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo( null /*failureActivity*/, info.providerInfo.packageName, info.providerInfo.applicationInfo.longVersionCode, info.providerInfo.splitName); // add a non-generic filter installerInfo.filter = new IntentFilter(); // load resources from the correct package installerInfo.resolvePackageName = info.getComponentInfo().packageName; resolveInfos.set(i, installerInfo); } continue; } // allow providers that have been explicitly exposed to instant applications if (!isEphemeralApp && ((info.providerInfo.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) { continue; } resolveInfos.remove(i); } return resolveInfos; } @Override public ParceledListSlice getInstalledPackages(int flags, int userId) { return mComputer.getInstalledPackages(flags, userId); } private void addPackageHoldingPermissions(ArrayList list, PackageSetting ps, String[] permissions, boolean[] tmp, int flags, int userId) { int numMatch = 0; for (int i=0; i getPackagesHoldingPermissions( String[] permissions, int flags, int userId) { if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId); enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "get packages holding permissions"); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; // writer synchronized (mLock) { ArrayList list = new ArrayList<>(); boolean[] tmpBools = new boolean[permissions.length]; if (listUninstalled) { for (PackageSetting ps : mSettings.getPackagesLocked().values()) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); } } else { for (AndroidPackage pkg : mPackages.values()) { PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); } } } return new ParceledListSlice<>(list); } } @Override public ParceledListSlice getInstalledApplications(int flags, int userId) { final int callingUid = Binder.getCallingUid(); return new ParceledListSlice<>( getInstalledApplicationsListInternal(flags, userId, callingUid)); } private List getInstalledApplicationsListInternal(int flags, int userId, int callingUid) { if (getInstantAppPackageName(callingUid) != null) { return Collections.emptyList(); } if (!mUserManager.exists(userId)) return Collections.emptyList(); flags = updateFlagsForApplication(flags, userId); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; enforceCrossUserPermission( callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get installed application info"); // writer synchronized (mLock) { ArrayList list; if (listUninstalled) { list = new ArrayList<>(mSettings.getPackagesLocked().size()); for (PackageSetting ps : mSettings.getPackagesLocked().values()) { ApplicationInfo ai; int effectiveFlags = flags; if (ps.isSystem()) { effectiveFlags |= PackageManager.MATCH_ANY_USER; } if (ps.pkg != null) { if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } } else { // Shared lib filtering done in generateApplicationInfoFromSettingsLPw // and already converts to externally visible package name ai = generateApplicationInfoFromSettingsLPw(ps.name, effectiveFlags, callingUid, userId); } if (ai != null) { list.add(ai); } } } else { list = new ArrayList<>(mPackages.size()); for (AndroidPackage p : mPackages.values()) { final PackageSetting ps = getPackageSetting(p.getPackageName()); if (ps != null) { if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId, ps); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); list.add(ai); } } } } return list; } } @Override public ParceledListSlice getInstantApps(int userId) { if (HIDE_EPHEMERAL_APIS) { return null; } if (!canViewInstantApps(Binder.getCallingUid(), userId)) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS, "getEphemeralApplications"); } enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getEphemeralApplications"); synchronized (mLock) { List instantApps = mInstantAppRegistry .getInstantAppsLPr(userId); if (instantApps != null) { return new ParceledListSlice<>(instantApps); } } return null; } @Override public boolean isInstantApp(String packageName, int userId) { return mComputer.isInstantApp(packageName, userId); } private boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid) { return mComputer.isInstantAppInternal(packageName, userId, callingUid); } @Override public byte[] getInstantAppCookie(String packageName, int userId) { if (HIDE_EPHEMERAL_APIS) { return null; } enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getInstantAppCookie"); if (!isCallerSameApp(packageName, Binder.getCallingUid())) { return null; } synchronized (mLock) { return mInstantAppRegistry.getInstantAppCookieLPw( packageName, userId); } } @Override public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) { if (HIDE_EPHEMERAL_APIS) { return true; } enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, true /* checkShell */, "setInstantAppCookie"); if (!isCallerSameApp(packageName, Binder.getCallingUid())) { return false; } synchronized (mLock) { return mInstantAppRegistry.setInstantAppCookieLPw( packageName, cookie, userId); } } @Override public Bitmap getInstantAppIcon(String packageName, int userId) { if (HIDE_EPHEMERAL_APIS) { return null; } if (!canViewInstantApps(Binder.getCallingUid(), userId)) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS, "getInstantAppIcon"); } enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getInstantAppIcon"); synchronized (mLock) { return mInstantAppRegistry.getInstantAppIconLPw( packageName, userId); } } private boolean isCallerSameApp(String packageName, int uid) { return mComputer.isCallerSameApp(packageName, uid); } @Override public @NonNull ParceledListSlice getPersistentApplications(int flags) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return ParceledListSlice.emptyList(); } return new ParceledListSlice<>(getPersistentApplicationsInternal(flags)); } private @NonNull List getPersistentApplicationsInternal(int flags) { final ArrayList finalList = new ArrayList<>(); // reader synchronized (mLock) { final int numPackages = mPackages.size(); final int userId = UserHandle.getCallingUserId(); for (int index = 0; index < numPackages; index++) { final AndroidPackage p = mPackages.valueAt(index); final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0) && !p.isDirectBootAware(); final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) && p.isDirectBootAware(); if (p.isPersistent() && (!mSafeMode || p.isSystem()) && (matchesUnaware || matchesAware)) { PackageSetting ps = mSettings.getPackageLPr(p.getPackageName()); if (ps != null) { ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId, ps); if (ai != null) { finalList.add(ai); } } } } } return finalList; } @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId) { return resolveContentProviderInternal(name, flags, userId); } public ProviderInfo resolveContentProvider(String name, int flags, int userId, int callingUid) { return resolveContentProviderInternal(name, flags, userId, callingUid); } private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) { return resolveContentProviderInternal(name, flags, userId, Binder.getCallingUid()); } private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId, int callingUid) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId); final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); boolean checkedGrants = false; if (providerInfo != null) { // Looking for cross-user grants before enforcing the typical cross-users permissions if (userId != UserHandle.getUserId(callingUid)) { final UriGrantsManagerInternal ugmInternal = mInjector.getLocalService(UriGrantsManagerInternal.class); checkedGrants = ugmInternal.checkAuthorityGrants(callingUid, providerInfo, userId, true); } } if (!checkedGrants) { enforceCrossUserPermission(callingUid, userId, false, false, "resolveContentProvider"); } if (providerInfo == null) { return null; } synchronized (mLock) { if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) { return null; } final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName); final ComponentName component = new ComponentName(providerInfo.packageName, providerInfo.name); if (shouldFilterApplicationLocked(ps, callingUid, component, TYPE_PROVIDER, userId)) { return null; } return providerInfo; } } /** * @deprecated */ @Deprecated public void querySyncProviders(List outNames, List outInfo) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } final List names = new ArrayList<>(); final List infos = new ArrayList<>(); final int callingUserId = UserHandle.getCallingUserId(); mComponentResolver.querySyncProviders( names, infos, mSafeMode, callingUserId); synchronized (mLock) { for (int i = infos.size() - 1; i >= 0; i--) { final ProviderInfo providerInfo = infos.get(i); final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName); final ComponentName component = new ComponentName(providerInfo.packageName, providerInfo.name); if (!shouldFilterApplicationLocked(ps, Binder.getCallingUid(), component, TYPE_PROVIDER, callingUserId)) { continue; } infos.remove(i); names.remove(i); } } if (!names.isEmpty()) { outNames.addAll(names); } if (!infos.isEmpty()) { outInfo.addAll(infos); } } @Override public @NonNull ParceledListSlice queryContentProviders(String processName, int uid, int flags, String metaDataKey) { final int callingUid = Binder.getCallingUid(); final int userId = processName != null ? UserHandle.getUserId(uid) : UserHandle.getCallingUserId(); if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForComponent(flags, userId); ArrayList finalList = null; final List matchList = mComponentResolver.queryProviders(processName, metaDataKey, uid, flags, userId); final int listSize = (matchList == null ? 0 : matchList.size()); synchronized (mLock) { for (int i = 0; i < listSize; i++) { final ProviderInfo providerInfo = matchList.get(i); if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) { continue; } final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName); final ComponentName component = new ComponentName(providerInfo.packageName, providerInfo.name); if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_PROVIDER, userId)) { continue; } if (finalList == null) { finalList = new ArrayList<>(listSize - i); } finalList.add(providerInfo); } } if (finalList != null) { finalList.sort(sProviderInitOrderSorter); return new ParceledListSlice<>(finalList); } return ParceledListSlice.emptyList(); } @Override public InstrumentationInfo getInstrumentationInfo(ComponentName component, int flags) { // reader synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); String packageName = component.getPackageName(); final PackageSetting ps = mSettings.getPackageLPr(packageName); AndroidPackage pkg = mPackages.get(packageName); if (ps == null || pkg == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) { return null; } final ParsedInstrumentation i = mInstrumentation.get(component); return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId, ps); } } @Override public @NonNull ParceledListSlice queryInstrumentation( String targetPackage, int flags) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(targetPackage); if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } } return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags, callingUserId)); } private @NonNull List queryInstrumentationInternal(String targetPackage, int flags, int userId) { ArrayList finalList = new ArrayList<>(); // reader synchronized (mLock) { final int numInstrumentations = mInstrumentation.size(); for (int index = 0; index < numInstrumentations; index++) { final ParsedInstrumentation p = mInstrumentation.valueAt(index); if (targetPackage == null || targetPackage.equals(p.getTargetPackage())) { String packageName = p.getPackageName(); AndroidPackage pkg = mPackages.get(packageName); PackageSetting pkgSetting = getPackageSetting(packageName); if (pkg != null) { InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p, pkg, flags, userId, pkgSetting); if (ii != null) { finalList.add(ii); } } } } } return finalList; } private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); try { scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, PackageParser2 packageParser, ExecutorService executorService) { final File[] files = scanDir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + scanDir); return; } if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags + " flags=0x" + Integer.toHexString(parseFlags)); } ParallelPackageParser parallelPackageParser = new ParallelPackageParser(packageParser, executorService); // Submit files for parsing in parallel int fileCount = 0; for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } parallelPackageParser.submit(file, parseFlags); fileCount++; } // Process results one by one for (; fileCount > 0; fileCount--) { ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); Throwable throwable = parseResult.throwable; int errorCode = PackageManager.INSTALL_SUCCEEDED; String errorMsg = null; if (throwable == null) { // TODO(toddke): move lower in the scan chain // Static shared libraries have synthetic package names if (parseResult.parsedPackage.isStaticSharedLibrary()) { renameStaticSharedLibraryPackage(parseResult.parsedPackage); } try { addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime, null); } catch (PackageManagerException e) { errorCode = e.error; errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage(); Slog.w(TAG, errorMsg); } } else if (throwable instanceof PackageParserException) { PackageParserException e = (PackageParserException) throwable; errorCode = e.error; errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage(); Slog.w(TAG, errorMsg); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " + parseResult.scanFile, throwable); } if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) { mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg); } // Delete invalid userdata apps if ((scanFlags & SCAN_AS_SYSTEM) == 0 && errorCode != PackageManager.INSTALL_SUCCEEDED) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + parseResult.scanFile); removeCodePathLI(parseResult.scanFile); } } } public static void reportSettingsProblem(int priority, String msg) { logCriticalInfo(priority, msg); } private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage, boolean forceCollect, boolean skipVerify) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade ? new File(parsedPackage.getPath()).lastModified() : getLastModifiedTime(parsedPackage); final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage); if (ps != null && !forceCollect && ps.getPathString().equals(parsedPackage.getPath()) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(settingsVersionForPackage) && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) { if (ps.signatures.mSigningDetails.signatures != null && ps.signatures.mSigningDetails.signatures.length != 0 && ps.signatures.mSigningDetails.signatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. parsedPackage.setSigningDetails( new PackageParser.SigningDetails(ps.signatures.mSigningDetails)); return; } Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs" + (forceCollect ? " (forced)" : "")); } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); parsedPackage.setSigningDetails( ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify)); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Clear the package profile if this was an upgrade and the package * version was updated. */ private void maybeClearProfilesForUpgradesLI( @Nullable PackageSetting originalPkgSetting, @NonNull AndroidPackage pkg) { if (originalPkgSetting == null || !isDeviceUpgrading()) { return; } if (originalPkgSetting.versionCode == pkg.getVersionCode()) { return; } clearAppProfilesLIF(pkg, UserHandle.USER_ALL); if (DEBUG_INSTALL) { Slog.d(TAG, originalPkgSetting.name + " clear profile due to version change " + originalPkgSetting.versionCode + " != " + pkg.getVersionCode()); } } /** * Traces a package scan. * @see #scanPackageLI(File, int, int, long, UserHandle) */ @GuardedBy({"mInstallLock", "mLock"}) private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]"); try { return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Scans a package and returns the newly parsed package. * Returns {@code null} in case of errors and the error code is stored in mLastScanError */ @GuardedBy({"mInstallLock", "mLock"}) private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final ParsedPackage parsedPackage; try (PackageParser2 pp = mInjector.getScanningPackageParser()) { parsedPackage = pp.parsePackage(scanFile, parseFlags, false); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Static shared libraries have synthetic package names if (parsedPackage.isStaticSharedLibrary()) { renameStaticSharedLibraryPackage(parsedPackage); } return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user); } /** * Returns if forced apk verification can be skipped for the whole package, including splits. */ private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) { return false; } // TODO: Allow base and splits to be verified individually. String[] splitCodePaths = pkg.getSplitCodePaths(); if (!ArrayUtils.isEmpty(splitCodePaths)) { for (int i = 0; i < splitCodePaths.length; i++) { if (!canSkipForcedApkVerification(splitCodePaths[i])) { return false; } } } return true; } /** * Returns if forced apk verification can be skipped, depending on current FSVerity setup and * whether the apk contains signed root hash. Note that the signer's certificate still needs to * match one in a trusted source, and should be done separately. */ private boolean canSkipForcedApkVerification(String apkPath) { if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) { return VerityUtils.hasFsverity(apkPath); } try { final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath); if (rootHashObserved == null) { return false; // APK does not contain Merkle tree root hash. } synchronized (mInstallLock) { // Returns whether the observed root hash matches what kernel has. mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved); return true; } } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e); } return false; } /** * Adds a new package to the internal data structures during platform initialization. *

    After adding, the package is known to the system and available for querying. *

    For packages located on the device ROM [eg. packages located in /system, /vendor, * etc...], additional checks are performed. Basic verification [such as ensuring * matching signatures, checking version codes, etc...] occurs if the package is * identical to a previously known package. If the package fails a signature check, * the version installed on /data will be removed. If the version of the new package * is less than or equal than the version on /data, it will be ignored. *

    Regardless of the package location, the results are applied to the internal * structures and the package is made available to the rest of the system. *

    NOTE: The return value should be removed. It's the passed in package object. */ @GuardedBy({"mInstallLock", "mLock"}) private AndroidPackage addForInitLI(ParsedPackage parsedPackage, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { final boolean scanSystemPartition = (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0; final String renamedPkgName; final PackageSetting disabledPkgSetting; final boolean isSystemPkgUpdated; final boolean pkgAlreadyExists; PackageSetting pkgSetting; synchronized (mLock) { renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage()); final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { ensurePackageRenamed(parsedPackage, renamedPkgName); } final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, renamedPkgName); final PackageSetting installedPkgSetting = mSettings.getPackageLPr( parsedPackage.getPackageName()); pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting; pkgAlreadyExists = pkgSetting != null; final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : parsedPackage.getPackageName(); if (scanSystemPartition && !pkgAlreadyExists && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) { // The updated-package data for /system apk remains inconsistently // after the package data for /data apk is lost accidentally. // To recover it, enable /system apk and install it as non-updated system app. Slog.w(TAG, "Inconsistent package setting of updated system app for " + disabledPkgName + ". To recover it, enable the system app" + "and install it as non-updated system app."); mSettings.removeDisabledSystemPackageLPw(disabledPkgName); } disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName); isSystemPkgUpdated = disabledPkgSetting != null; if (DEBUG_INSTALL && isSystemPkgUpdated) { Slog.d(TAG, "updatedPkg = " + disabledPkgSetting); } final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null) ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true) : null; if (DEBUG_PACKAGE_SCANNING && (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 && sharedUserSetting != null) { Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } if (scanSystemPartition) { if (isSystemPkgUpdated) { // we're updating the disabled package, so, scan it as the package setting boolean isPlatformPackage = mPlatformPackage != null && Objects.equals(mPlatformPackage.getPackageName(), parsedPackage.getPackageName()); final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, null, disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, null /* originalPkgSetting */, null, parseFlags, scanFlags, isPlatformPackage, user, null); applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true); final ScanResult scanResult = scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L); if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) { scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting); } } } } final boolean newPkgChangedPaths = pkgAlreadyExists && !pkgSetting.getPathString().equals(parsedPackage.getPath()); final boolean newPkgVersionGreater = pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode; final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated && newPkgChangedPaths && newPkgVersionGreater; if (isSystemPkgBetter) { // The version of the application on /system is greater than the version on // /data. Switch back to the application on /system. // It's safe to assume the application on /system will correctly scan. If not, // there won't be a working copy of the application. synchronized (mLock) { // just remove the loaded entries from package lists mPackages.remove(pkgSetting.name); } logCriticalInfo(Log.WARN, "System package updated;" + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() + "; " + pkgSetting.getPathString() + " --> " + parsedPackage.getPath()); final InstallArgs args = createInstallArgsForExisting( pkgSetting.getPathString(), getAppDexInstructionSets( pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); args.cleanUpResourcesLI(); synchronized (mLock) { mSettings.enableSystemPackageLPw(pkgSetting.name); } } // The version of the application on the /system partition is less than or // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) { // In the case of a skipped package, commitReconciledScanResultLocked is not called to // add the object to the "live" data structures, so this is the final mutation step // for the package. Which means it needs to be finalized here to cache derived fields. // This is relevant for cases where the disabled system package is used for flags or // other metadata. ((ParsedPackage) parsedPackage).hideAsFinal(); throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName() + " at " + parsedPackage.getPath() + " ignored: updated version " + pkgSetting.versionCode + " better than this " + parsedPackage.getLongVersionCode()); } // Verify certificates against what was last scanned. Force re-collecting certificate in two // special cases: // 1) when scanning system, force re-collect only if system is upgrading. // 2) when scannning /data, force re-collect only if the app is privileged (updated from // preinstall, or treated as privileged, e.g. due to shared user ID). final boolean forceCollect = scanSystemPartition ? mIsUpgrade : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting); if (DEBUG_VERIFY && forceCollect) { Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // Full APK verification can be skipped during certificate collection, only if the file is // in verified partition, or can be verified on access (when apk verity is enabled). In both // cases, only data in Signing Block is verified instead of the whole file. // TODO(b/136132412): skip for Incremental installation final boolean skipVerify = scanSystemPartition || (forceCollect && canSkipForcedPackageVerification(parsedPackage)); collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify); // Reset profile if the application version is changed maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage); /* * A new system app appeared, but we already had a non-system one of the * same name installed earlier. */ boolean shouldHideSystemApp = false; // A new application appeared on /system, but, we already have a copy of // the application installed on /data. if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { if (!parsedPackage.getSigningDetails() .checkCapability(pkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) && !pkgSetting.signatures.mSigningDetails.checkCapability( parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) { logCriticalInfo(Log.WARN, "System package signature mismatch;" + " name: " + pkgSetting.name); try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage( parsedPackage.getPackageName(), "scanPackageInternalLI")) { deletePackageLIF(parsedPackage.getPackageName(), null, true, mUserManager.getUserIds(), 0, null, false, null); } pkgSetting = null; } else if (newPkgVersionGreater) { // The application on /system is newer than the application on /data. // Simply remove the application on /data [keeping application data] // and replace it with the version on /system. logCriticalInfo(Log.WARN, "System package enabled;" + " name: " + pkgSetting.name + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() + "; " + pkgSetting.getPathString() + " --> " + parsedPackage.getPath()); InstallArgs args = createInstallArgsForExisting( pkgSetting.getPathString(), getAppDexInstructionSets( pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } } else { // The application on /system is older than the application on /data. Hide // the application on /system and the version on /data will be scanned later // and re-added like an update. shouldHideSystemApp = true; logCriticalInfo(Log.INFO, "System package disabled;" + " name: " + pkgSetting.name + "; old: " + pkgSetting.getPathString() + " @ " + pkgSetting.versionCode + "; new: " + parsedPackage.getPath() + " @ " + parsedPackage.getPath()); } } final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null); if (scanResult.success) { synchronized (mLock) { boolean appIdCreated = false; try { final String pkgName = scanResult.pkgSetting.name; final Map reconcileResult = reconcilePackagesLocked( new ReconcileRequest( Collections.singletonMap(pkgName, scanResult), mSharedLibraries, mPackages, Collections.singletonMap( pkgName, getSettingsVersionForPackage(parsedPackage)), Collections.singletonMap(pkgName, getSharedLibLatestVersionSetting(scanResult))), mSettings.getKeySetManagerService(), mInjector); appIdCreated = optimisticallyRegisterAppId(scanResult); commitReconciledScanResultLocked( reconcileResult.get(pkgName), mUserManager.getUserIds()); } catch (PackageManagerException e) { if (appIdCreated) { cleanUpAppIdCreation(scanResult); } throw e; } } } if (shouldHideSystemApp) { synchronized (mLock) { mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true); } } if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) { if (pkgSetting != null && pkgSetting.isPackageLoading()) { // Continue monitoring loading progress of active incremental packages final IncrementalStatesCallback incrementalStatesCallback = new IncrementalStatesCallback(parsedPackage.getPackageName(), UserHandle.getUid(UserHandle.USER_ALL, pkgSetting.appId), getInstalledUsers(pkgSetting, UserHandle.USER_ALL)); pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback); mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(), new IncrementalProgressListener(parsedPackage.getPackageName())); } } return scanResult.pkgSetting.pkg; } // TODO:(b/135203078): Move to parsing private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { // Derive the new package synthetic package name parsedPackage.setPackageName(toStaticSharedLibraryPackageName( parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibVersion())); } private static String toStaticSharedLibraryPackageName( String packageName, long libraryVersion) { return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion; } static String fixProcessName(String defProcessName, String processName) { if (processName == null) { return defProcessName; } return processName; } /** * Enforces that only the system UID or root's UID can call a method exposed * via Binder. * * @param message used as message if SecurityException is thrown * @throws SecurityException if the caller is not system or root */ private static void enforceSystemOrRoot(String message) { final int uid = Binder.getCallingUid(); if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID) { throw new SecurityException(message); } } /** * Enforces that only the system UID or root's UID or shell's UID can call * a method exposed via Binder. * * @param message used as message if SecurityException is thrown * @throws SecurityException if the caller is not system or shell */ private static void enforceSystemOrRootOrShell(String message) { final int uid = Binder.getCallingUid(); if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID && uid != Process.SHELL_UID) { throw new SecurityException(message); } } /** * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller. * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { mComputer.enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, message); } /** * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller. * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param requirePermissionWhenSameUser When {@code true}, still require the cross user * permission to be held even if the callingUid and userId * reference the same user. * @param message the message to log on security exception */ private void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message) { mComputer.enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, requirePermissionWhenSameUser, message); } /** * Checks if the request is from the system or an app that has the appropriate cross-user * permissions defined as follows: *

      *
    • INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.
    • *
    • INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group * to the caller.
    • *
    • Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile * group as the caller.
    • *
    * * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { mComputer.enforceCrossUserOrProfilePermission(callingUid, userId, requireFullPermission, checkShell, message); } private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { return mComputer.isSameProfileGroup(callerUserId, userId); } private static String buildInvalidCrossUserPermissionMessage(int callingUid, @UserIdInt int userId, String message, boolean requireFullPermission) { StringBuilder builder = new StringBuilder(); if (message != null) { builder.append(message); builder.append(": "); } builder.append("UID "); builder.append(callingUid); builder.append(" requires "); builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); if (!requireFullPermission) { builder.append(" or "); builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS); } builder.append(" to access user "); builder.append(userId); builder.append("."); return builder.toString(); } private static String buildInvalidCrossUserOrProfilePermissionMessage(int callingUid, @UserIdInt int userId, String message, boolean requireFullPermission, boolean isSameProfileGroup) { StringBuilder builder = new StringBuilder(); if (message != null) { builder.append(message); builder.append(": "); } builder.append("UID "); builder.append(callingUid); builder.append(" requires "); builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); if (!requireFullPermission) { builder.append(" or "); builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS); if (isSameProfileGroup) { builder.append(" or "); builder.append(android.Manifest.permission.INTERACT_ACROSS_PROFILES); } } builder.append(" to access user "); builder.append("."); return builder.toString(); } @Override public void performFstrimIfNeeded() { enforceSystemOrRoot("Only the system can request fstrim"); // Before everything else, see whether we need to fstrim. try { IStorageManager sm = PackageHelper.getStorageManager(); if (sm != null) { boolean doTrim = false; final long interval = android.provider.Settings.Global.getLong( mContext.getContentResolver(), android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL, DEFAULT_MANDATORY_FSTRIM_INTERVAL); if (interval > 0) { final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance(); if (timeSinceLast > interval) { doTrim = true; Slog.w(TAG, "No disk maintenance in " + timeSinceLast + "; running immediately"); } } if (doTrim) { final boolean dexOptDialogShown; synchronized (mLock) { dexOptDialogShown = mDexOptDialogShown; } if (!isFirstBoot() && dexOptDialogShown) { try { ActivityManager.getService().showBootMessage( mContext.getResources().getString( R.string.android_upgrading_fstrim), true); } catch (RemoteException e) { } } sm.runMaintenance(); } } else { Slog.e(TAG, "storageManager service unavailable!"); } } catch (RemoteException e) { // Can't happen; StorageManagerService is local } } @Override public void updatePackagesIfNeeded() { enforceSystemOrRoot("Only the system can request package update"); // We need to re-extract after an OTA. boolean causeUpgrade = isDeviceUpgrading(); // First boot or factory reset. // Note: we also handle devices that are upgrading to N right now as if it is their // first boot, as they do not have profile data. boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade; if (!causeUpgrade && !causeFirstBoot) { return; } List pkgSettings; synchronized (mLock) { pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt( mSettings.getPackagesLocked().values(), this); } List pkgs = new ArrayList<>(pkgSettings.size()); for (int index = 0; index < pkgSettings.size(); index++) { pkgs.add(pkgSettings.get(index).pkg); } final long startTime = System.nanoTime(); final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */, causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT_AFTER_OTA, false /* bootComplete */); final int elapsedTimeSeconds = (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime); MetricsLogger.histogram(mContext, "opt_dialog_num_dexopted", stats[0]); MetricsLogger.histogram(mContext, "opt_dialog_num_skipped", stats[1]); MetricsLogger.histogram(mContext, "opt_dialog_num_failed", stats[2]); MetricsLogger.histogram(mContext, "opt_dialog_num_total", getOptimizablePackages().size()); MetricsLogger.histogram(mContext, "opt_dialog_time_s", elapsedTimeSeconds); } /* * Return the prebuilt profile path given a package base code path. */ private static String getPrebuildProfilePath(AndroidPackage pkg) { return pkg.getBaseApkPath() + ".prof"; } /** * Performs dexopt on the set of packages in {@code packages} and returns an int array * containing statistics about the invocation. The array consists of three elements, * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped} * and {@code numberOfPackagesFailed}. */ private int[] performDexOptUpgrade(List pkgs, boolean showDialog, final int compilationReason, boolean bootComplete) { int numberOfPackagesVisited = 0; int numberOfPackagesOptimized = 0; int numberOfPackagesSkipped = 0; int numberOfPackagesFailed = 0; final int numberOfPackagesToDexopt = pkgs.size(); for (AndroidPackage pkg : pkgs) { numberOfPackagesVisited++; boolean useProfileForDexopt = false; if ((isFirstBoot() || isDeviceUpgrading()) && pkg.isSystem()) { // Copy over initial preopt profiles since we won't get any JIT samples for methods // that are already compiled. File profileFile = new File(getPrebuildProfilePath(pkg)); // Copy profile if it exists. if (profileFile.exists()) { try { // We could also do this lazily before calling dexopt in // PackageDexOptimizer to prevent this happening on first boot. The issue // is that we don't have a good way to say "do this only once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Installer failed to copy system profile!"); } else { // Disabled as this causes speed-profile compilation during first boot // even if things are already compiled. // useProfileForDexopt = true; } } catch (Exception e) { Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); } } else { PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr( pkg.getPackageName()); // Handle compressed APKs in this path. Only do this for stubs with profiles to // minimize the number off apps being speed-profile compiled during first boot. // The other paths will not change the filter. if (disabledPs != null && disabledPs.pkg.isStub()) { // The package is the stub one, remove the stub suffix to get the normal // package and APK names. String systemProfilePath = getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, ""); profileFile = new File(systemProfilePath); // If we have a profile for a compressed APK, copy it to the reference // location. // Note that copying the profile here will cause it to override the // reference profile every OTA even though the existing reference profile // may have more data. We can't copy during decompression since the // directories are not set up at that point. if (profileFile.exists()) { try { // We could also do this lazily before calling dexopt in // PackageDexOptimizer to prevent this happening on first boot. The // issue is that we don't have a good way to say "do this only // once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Failed to copy system profile for stub package!"); } else { useProfileForDexopt = true; } } catch (Exception e) { Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); } } } } } if (!mPackageDexOptimizer.canOptimizePackage(pkg)) { if (DEBUG_DEXOPT) { Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName()); } numberOfPackagesSkipped++; continue; } if (DEBUG_DEXOPT) { Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " + numberOfPackagesToDexopt + ": " + pkg.getPackageName()); } if (showDialog) { try { ActivityManager.getService().showBootMessage( mContext.getResources().getString(R.string.android_upgrading_apk, numberOfPackagesVisited, numberOfPackagesToDexopt), true); } catch (RemoteException e) { } synchronized (mLock) { mDexOptDialogShown = true; } } int pkgCompilationReason = compilationReason; if (useProfileForDexopt) { // Use background dexopt mode to try and use the profile. Note that this does not // guarantee usage of the profile. pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; } if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { mArtManagerService.compileLayouts(pkg); } // checkProfiles is false to avoid merging profiles during boot which // might interfere with background compilation (b/28612421). // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a // trade-off worth doing to save boot time work. int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; if (compilationReason == REASON_FIRST_BOOT) { // TODO: This doesn't cover the upgrade case, we should check for this too. dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; } int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( pkg.getPackageName(), pkgCompilationReason, dexoptFlags)); switch (primaryDexOptStaus) { case PackageDexOptimizer.DEX_OPT_PERFORMED: numberOfPackagesOptimized++; break; case PackageDexOptimizer.DEX_OPT_SKIPPED: numberOfPackagesSkipped++; break; case PackageDexOptimizer.DEX_OPT_FAILED: numberOfPackagesFailed++; break; default: Log.e(TAG, "Unexpected dexopt return code " + primaryDexOptStaus); break; } } return new int[] { numberOfPackagesOptimized, numberOfPackagesSkipped, numberOfPackagesFailed }; } @Override public void notifyPackageUse(String packageName, int reason) { synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (getInstantAppPackageName(callingUid) != null) { if (!isCallerSameApp(packageName, callingUid)) { return; } } else { if (isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID)) { return; } } notifyPackageUseLocked(packageName, reason); } } @GuardedBy("mLock") private void notifyPackageUseLocked(String packageName, int reason) { final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null) { return; } pkgSetting.getPkgState().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis()); } @Override public void notifyDexLoad(String loadingPackageName, Map classLoaderContextMap, String loaderIsa) { int callingUid = Binder.getCallingUid(); if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) { Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid=" + callingUid); // Do not record dex loads from processes pretending to be system server. // Only the system server should be assigned the package "android", so reject calls // that don't satisfy the constraint. // // notifyDexLoad is a PM API callable from the app process. So in theory, apps could // craft calls to this API and pretend to be system server. Doing so poses no particular // danger for dex load reporting or later dexopt, however it is a sensible check to do // in order to verify the expectations. return; } int userId = UserHandle.getCallingUserId(); ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId); if (ai == null) { Slog.w(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 registerDexModule(String packageName, String dexModulePath, boolean isSharedModule, IDexModuleRegisterCallback callback) { int userId = UserHandle.getCallingUserId(); ApplicationInfo ai = getApplicationInfo(packageName, /*flags*/ 0, userId); DexManager.RegisterDexModuleResult result; if (ai == null) { Slog.w(TAG, "Registering a dex module for a package that does not exist for the" + " calling user. package=" + packageName + ", user=" + userId); result = new DexManager.RegisterDexModuleResult(false, "Package not installed"); } else { result = mDexManager.registerDexModule(ai, dexModulePath, isSharedModule, userId); } if (callback != null) { mHandler.post(() -> { try { callback.onDexModuleRegistered(dexModulePath, result.success, result.message); } catch (RemoteException e) { Slog.w(TAG, "Failed to callback after module registration " + dexModulePath, e); } }); } } /** * Ask the package manager to perform a dex-opt with the given compiler filter. * * Note: exposed only for the shell command to allow moving packages explicitly to a * definite state. */ @Override public boolean performDexOptMode(String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { enforceSystemOrRootOrShell("performDexOptMode"); int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0); return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE, targetCompilerFilter, splitName, flags)); } /** * Ask the package manager to perform a dex-opt with the given compiler filter on the * secondary dex files belonging to the given package. * * Note: exposed only for the shell command to allow moving packages explicitly to a * definite state. */ @Override public boolean performDexOptSecondary(String packageName, String compilerFilter, boolean force) { int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX | DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES | DexoptOptions.DEXOPT_BOOT_COMPLETE | (force ? DexoptOptions.DEXOPT_FORCE : 0); return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags)); } /*package*/ boolean performDexOpt(DexoptOptions options) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return false; } else if (isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) { return false; } if (options.isDexoptOnlySecondaryDex()) { return mDexManager.dexoptSecondaryDex(options); } else { int dexoptStatus = performDexOptWithStatus(options); return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED; } } /** * Perform dexopt on the given package and return one of following result: * {@link PackageDexOptimizer#DEX_OPT_SKIPPED} * {@link PackageDexOptimizer#DEX_OPT_PERFORMED} * {@link PackageDexOptimizer#DEX_OPT_FAILED} */ /* package */ int performDexOptWithStatus(DexoptOptions options) { return performDexOptTraced(options); } private int performDexOptTraced(DexoptOptions options) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); try { return performDexOptInternal(options); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } // Run dexopt on a given package. Returns true if dexopt did not fail, i.e. // if the package can now be considered up to date for the given filter. private int performDexOptInternal(DexoptOptions options) { AndroidPackage p; PackageSetting pkgSetting; synchronized (mLock) { p = mPackages.get(options.getPackageName()); pkgSetting = mSettings.getPackageLPr(options.getPackageName()); if (p == null || pkgSetting == null) { // Package could not be found. Report failure. return PackageDexOptimizer.DEX_OPT_FAILED; } mPackageUsage.maybeWriteAsync(mSettings.getPackagesLocked()); mCompilerStats.maybeWriteAsync(); } final long callingId = Binder.clearCallingIdentity(); try { synchronized (mInstallLock) { return performDexOptInternalWithDependenciesLI(p, pkgSetting, options); } } finally { Binder.restoreCallingIdentity(callingId); } } public ArraySet getOptimizablePackages() { ArraySet pkgs = new ArraySet<>(); synchronized (mLock) { for (AndroidPackage p : mPackages.values()) { if (mPackageDexOptimizer.canOptimizePackage(p)) { pkgs.add(p.getPackageName()); } } } return pkgs; } private int performDexOptInternalWithDependenciesLI(AndroidPackage p, @NonNull PackageSetting pkgSetting, DexoptOptions options) { // System server gets a special path. if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) { return mDexManager.dexoptSystemServer(options); } // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to // allocate an object here. PackageDexOptimizer pdo = options.isForce() ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer) : mPackageDexOptimizer; // Dexopt all dependencies first. Note: we ignore the return value and march on // on errors. // Note that we are going to call performDexOpt on those libraries as many times as // they are referenced in packages. When we do a batch of performDexOpt (for example // at boot, or background job), the passed 'targetCompilerFilter' stays the same, // and the first package that uses the library will dexopt it. The // others will see that the compiled code for the library is up to date. Collection deps = findSharedLibraries(pkgSetting); final String[] instructionSets = getAppDexInstructionSets( AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting), AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting)); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), options.getCompilationReason(), options.getCompilerFilter(), options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (SharedLibraryInfo info : deps) { AndroidPackage depPackage = null; PackageSetting depPackageSetting = null; synchronized (mLock) { depPackage = mPackages.get(info.getPackageName()); depPackageSetting = mSettings.getPackageLPr(info.getPackageName()); } if (depPackage != null && depPackageSetting != null) { // TODO: Analyze and investigate if we (should) profile libraries. pdo.performDexOpt(depPackage, depPackageSetting, instructionSets, getOrCreateCompilerPackageStats(depPackage), mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()), libraryOptions); } else { // TODO(ngeoffray): Support dexopting system shared libraries. } } } return pdo.performDexOpt(p, pkgSetting, instructionSets, getOrCreateCompilerPackageStats(p), mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options); } /** * Reconcile the information we have about the secondary dex files belonging to * {@code packageName} and the actual dex files. For all dex files that were * deleted, update the internal records and delete the generated oat files. */ @Override public void reconcileSecondaryDexFiles(String packageName) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } else if (isInstantApp(packageName, UserHandle.getCallingUserId())) { return; } mDexManager.reconcileSecondaryDexFiles(packageName); } // TODO(calin): this is only needed for BackgroundDexOptService. Find a cleaner way to inject // a reference there. /*package*/ DexManager getDexManager() { return mDexManager; } /** * Execute the background dexopt job immediately. */ @Override public boolean runBackgroundDexoptJob(@Nullable List packageNames) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return false; } enforceSystemOrRootOrShell("runBackgroundDexoptJob"); final long identity = Binder.clearCallingIdentity(); try { return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames); } finally { Binder.restoreCallingIdentity(identity); } } private static List findSharedLibraries(PackageSetting pkgSetting) { if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) { ArrayList retValue = new ArrayList<>(); Set collectedNames = new HashSet<>(); for (SharedLibraryInfo info : pkgSetting.getPkgState().getUsesLibraryInfos()) { findSharedLibrariesRecursive(info, retValue, collectedNames); } return retValue; } else { return Collections.emptyList(); } } private static void findSharedLibrariesRecursive(SharedLibraryInfo info, ArrayList collected, Set collectedNames) { if (!collectedNames.contains(info.getName())) { collectedNames.add(info.getName()); collected.add(info); if (info.getDependencies() != null) { for (SharedLibraryInfo dep : info.getDependencies()) { findSharedLibrariesRecursive(dep, collected, collectedNames); } } } } List findSharedNonSystemLibraries(PackageSetting pkgSetting) { List deps = findSharedLibraries(pkgSetting); if (!deps.isEmpty()) { List retValue = new ArrayList<>(); synchronized (mLock) { for (SharedLibraryInfo info : deps) { PackageSetting depPackageSetting = mSettings.getPackageLPr(info.getPackageName()); if (depPackageSetting != null && depPackageSetting.pkg != null) { retValue.add(depPackageSetting); } } } return retValue; } else { return Collections.emptyList(); } } @Nullable private SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) { return mComputer.getSharedLibraryInfoLPr(name, version); } @Nullable private static SharedLibraryInfo getSharedLibraryInfo(String name, long version, Map> existingLibraries, @Nullable Map> newLibraries) { if (newLibraries != null) { final WatchedLongSparseArray versionedLib = newLibraries.get(name); SharedLibraryInfo info = null; if (versionedLib != null) { info = versionedLib.get(version); } if (info != null) { return info; } } final WatchedLongSparseArray versionedLib = existingLibraries.get(name); if (versionedLib == null) { return null; } return versionedLib.get(version); } private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) { WatchedLongSparseArray versionedLib = mSharedLibraries.get( pkg.getStaticSharedLibName()); if (versionedLib == null) { return null; } long previousLibVersion = -1; final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { final long libVersion = versionedLib.keyAt(i); if (libVersion < pkg.getStaticSharedLibVersion()) { previousLibVersion = Math.max(previousLibVersion, libVersion); } } if (previousLibVersion >= 0) { return versionedLib.get(previousLibVersion); } return null; } @Nullable private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) { PackageSetting sharedLibPackage = null; synchronized (mLock) { final SharedLibraryInfo latestSharedLibraVersionLPr = getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage); if (latestSharedLibraVersionLPr != null) { sharedLibPackage = mSettings.getPackageLPr( latestSharedLibraVersionLPr.getPackageName()); } } return sharedLibPackage; } public void shutdown() { mCompilerStats.writeNow(); mDexManager.writePackageDexUsageNow(); PackageWatchdog.getInstance(mContext).writeNow(); synchronized (mLock) { mPackageUsage.writeNow(mSettings.getPackagesLocked()); // This is the last chance to write out pending restriction settings if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS); for (int userId : mDirtyUsers) { mSettings.writePackageRestrictionsLPr(userId); } mDirtyUsers.clear(); } } } @Override public void dumpProfiles(String packageName) { /* Only the shell, root, or the app user should be able to dump profiles. */ final int callingUid = Binder.getCallingUid(); final String[] callerPackageNames = getPackagesForUid(callingUid); if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID && !ArrayUtils.contains(callerPackageNames, packageName)) { throw new SecurityException("dumpProfiles"); } AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } } synchronized (mInstallLock) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles"); mArtManagerService.dumpProfiles(pkg); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @Override public void forceDexOpt(String packageName) { enforceSystemOrRoot("forceDexOpt"); AndroidPackage pkg; PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); pkgSetting = mSettings.getPackageLPr(packageName); if (pkg == null || pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } } synchronized (mInstallLock) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Whoever is calling forceDexOpt wants a compiled package. // Don't use profiles since that may cause compilation to be skipped. final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting, new DexoptOptions(packageName, getDefaultCompilerFilter(), DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE)); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { throw new IllegalStateException("Failed to dexopt: " + res); } } } @GuardedBy("mLock") private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) { if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { Slog.w(TAG, "Unable to update from " + oldPkg.name + " to " + newPkg.getPackageName() + ": old package not in system partition"); return false; } else if (mPackages.get(oldPkg.name) != null) { Slog.w(TAG, "Unable to update from " + oldPkg.name + " to " + newPkg.getPackageName() + ": old package still exists"); return false; } return true; } @GuardedBy("mInstallLock") void removeCodePathLI(File codePath) { if (codePath.isDirectory()) { final File codePathParent = codePath.getParentFile(); final boolean needRemoveParent = codePathParent.getName().startsWith(RANDOM_DIR_PREFIX); try { final boolean isIncremental = (mIncrementalManager != null && isIncrementalPath( codePath.getAbsolutePath())); if (isIncremental) { if (needRemoveParent) { mIncrementalManager.rmPackageDir(codePathParent); } else { mIncrementalManager.rmPackageDir(codePath); } } mInstaller.rmPackageDir(codePath.getAbsolutePath()); if (needRemoveParent) { mInstaller.rmPackageDir(codePathParent.getAbsolutePath()); removeCachedResult(codePathParent); } } catch (InstallerException e) { Slog.w(TAG, "Failed to remove code path", e); } } else { codePath.delete(); } } private void removeCachedResult(@NonNull File codePath) { if (mCacheDir == null) { return; } final PackageCacher cacher = new PackageCacher(mCacheDir); // Find and delete the cached result belong to the given codePath. cacher.cleanCachedResult(codePath); } private int[] resolveUserIds(int userId) { return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { return; } clearAppDataLeafLIF(pkg, userId, flags); if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) { clearAppProfilesLIF(pkg, UserHandle.USER_ALL); } } private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } } private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppDataLeafLIF(pkg, userId, flags); } private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId); } } private void destroyAppProfilesLIF(AndroidPackage pkg) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppProfilesLeafLIF(pkg); } private void destroyAppProfilesLeafLIF(AndroidPackage pkg) { try { mInstaller.destroyAppProfiles(pkg.getPackageName()); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } private void clearAppProfilesLIF(AndroidPackage pkg, int userId) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } mArtManagerService.clearAppProfiles(pkg); } @GuardedBy("mLock") private void applyDefiningSharedLibraryUpdateLocked( AndroidPackage pkg, SharedLibraryInfo libInfo, BiConsumer action) { // Note that libraries defined by this package may be null if: // - Package manager was unable to create the shared library. The package still // gets installed, but the shared library does not get created. // Or: // - Package manager is in a state where package isn't scanned yet. This will // get called again after scanning to fix the dependencies. if (AndroidPackageUtils.isLibrary(pkg)) { if (pkg.getStaticSharedLibName() != null) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (definedLibrary != null) { action.accept(definedLibrary, libInfo); } } else { for (String libraryName : pkg.getLibraryNames()) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( libraryName, SharedLibraryInfo.VERSION_UNDEFINED); if (definedLibrary != null) { action.accept(definedLibrary, libInfo); } } } } } @GuardedBy("mLock") private void addSharedLibraryLPr(AndroidPackage pkg, Set usesLibraryFiles, SharedLibraryInfo libInfo, @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting) { if (libInfo.getPath() != null) { usesLibraryFiles.add(libInfo.getPath()); return; } AndroidPackage pkgForCodePaths = mPackages.get(libInfo.getPackageName()); PackageSetting pkgSetting = mSettings.getPackageLPr(libInfo.getPackageName()); if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) { // If we are doing this while in the middle of updating a library apk, // then we need to make sure to use that new apk for determining the // dependencies here. (We haven't yet finished committing the new apk // to the package manager state.) if (pkgForCodePaths == null || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) { pkgForCodePaths = changingLib; pkgSetting = changingLibSetting; } } if (pkgForCodePaths != null) { usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths)); // If the package provides libraries, add the dependency to them. applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, SharedLibraryInfo::addDependency); if (pkgSetting != null) { usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles()); } } } @GuardedBy("mLock") private void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting, Map availablePackages) throws PackageManagerException { final ArrayList sharedLibraryInfos = collectSharedLibraryInfos( pkgSetting.pkg, availablePackages, mSharedLibraries, null /* newLibraries */, mInjector.getCompatibility()); executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting, sharedLibraryInfos, mUserManager.getUserIds()); } private static ArrayList collectSharedLibraryInfos(AndroidPackage pkg, Map availablePackages, @NonNull final Map> existingLibraries, @Nullable final Map> newLibraries, PlatformCompat platformCompat) throws PackageManagerException { if (pkg == null) { return null; } // The collection used here must maintain the order of addition (so // that libraries are searched in the correct order) and must have no // duplicates. ArrayList usesLibraryInfos = null; if (!pkg.getUsesLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null, availablePackages, existingLibraries, newLibraries); } if (!pkg.getUsesStaticLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } if (!pkg.getUsesOptionalLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } if (platformCompat.isChangeEnabledInternal(ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES, pkg.getPackageName(), pkg.getTargetSdkVersion())) { if (!pkg.getUsesNativeLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesNativeLibraries(), null, null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } if (!pkg.getUsesOptionalNativeLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalNativeLibraries(), null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } } return usesLibraryInfos; } private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting, ArrayList usesLibraryInfos, int[] allUsers) { // If the package provides libraries, clear their old dependencies. // This method will set them up again. applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> { definingLibrary.clearDependencies(); }); if (usesLibraryInfos != null) { pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos); // Use LinkedHashSet to preserve the order of files added to // usesLibraryFiles while eliminating duplicates. Set usesLibraryFiles = new LinkedHashSet<>(); for (SharedLibraryInfo libInfo : usesLibraryInfos) { addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib, changingLibSetting); } pkgSetting.getPkgState().setUsesLibraryFiles(new ArrayList<>(usesLibraryFiles)); // let's make sure we mark all static shared libraries as installed for the same users // that its dependent packages are installed for. int[] installedUsers = new int[allUsers.length]; int installedUserCount = 0; for (int u = 0; u < allUsers.length; u++) { if (pkgSetting.getInstalled(allUsers[u])) { installedUsers[installedUserCount++] = allUsers[u]; } } for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) { if (!sharedLibraryInfo.isStatic()) { continue; } final PackageSetting staticLibPkgSetting = getPackageSetting(sharedLibraryInfo.getPackageName()); if (staticLibPkgSetting == null) { Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo); continue; } for (int u = 0; u < installedUserCount; u++) { staticLibPkgSetting.setInstalled(true, installedUsers[u]); } } } else { pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList()) .setUsesLibraryFiles(Collections.emptyList()); } } @GuardedBy("mLock") private static ArrayList collectSharedLibraryInfos( @NonNull List requestedLibraries, @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests, @NonNull String packageName, boolean required, int targetSdk, @Nullable ArrayList outUsedLibraries, @NonNull final Map availablePackages, @NonNull final Map> existingLibraries, @Nullable final Map> newLibraries) throws PackageManagerException { final int libCount = requestedLibraries.size(); for (int i = 0; i < libCount; i++) { final String libName = requestedLibraries.get(i); final long libVersion = requiredVersions != null ? requiredVersions[i] : SharedLibraryInfo.VERSION_UNDEFINED; final SharedLibraryInfo libraryInfo = getSharedLibraryInfo(libName, libVersion, existingLibraries, newLibraries); if (libraryInfo == null) { if (required) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable shared library " + libName + "; failing!"); } else if (DEBUG_SHARED_LIBRARIES) { Slog.i(TAG, "Package " + packageName + " desires unavailable shared library " + libName + "; ignoring!"); } } else { if (requiredVersions != null && requiredCertDigests != null) { if (libraryInfo.getLongVersion() != requiredVersions[i]) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable static shared" + " library " + libName + " version " + libraryInfo.getLongVersion() + "; failing!"); } AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName()); SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails(); if (libPkg == null) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable static shared" + " library; failing!"); } final String[] expectedCertDigests = requiredCertDigests[i]; if (expectedCertDigests.length > 1) { // For apps targeting O MR1 we require explicit enumeration of all certs. final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1) ? PackageUtils.computeSignaturesSha256Digests( libPkg.signatures) : PackageUtils.computeSignaturesSha256Digests( new Signature[]{libPkg.signatures[0]}); // Take a shortcut if sizes don't match. Note that if an app doesn't // target O we don't parse the "additional-certificate" tags similarly // how we only consider all certs only for apps targeting O (see above). // Therefore, the size check is safe to make. if (expectedCertDigests.length != libCertDigests.length) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + " static shared library; failing!"); } // Use a predictable order as signature order may vary Arrays.sort(libCertDigests); Arrays.sort(expectedCertDigests); final int certCount = libCertDigests.length; for (int j = 0; j < certCount; j++) { if (!libCertDigests[j].equalsIgnoreCase(expectedCertDigests[j])) { throw new PackageManagerException( INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + " static shared library; failing!"); } } } else { // lib signing cert could have rotated beyond the one expected, check to see // if the new one has been blessed by the old byte[] digestBytes = HexEncoding.decode( expectedCertDigests[0], false /* allowSingleChar */); if (!libPkg.hasSha256Certificate(digestBytes)) { throw new PackageManagerException( INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + " static shared library; failing!"); } } } if (outUsedLibraries == null) { outUsedLibraries = new ArrayList<>(); } outUsedLibraries.add(libraryInfo); } } return outUsedLibraries; } private static boolean hasString(List list, List which) { if (list == null || which == null) { return false; } for (int i=list.size()-1; i>=0; i--) { for (int j=which.size()-1; j>=0; j--) { if (which.get(j).equals(list.get(i))) { return true; } } } return false; } @GuardedBy("mLock") private ArrayList updateAllSharedLibrariesLocked( @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting, Map availablePackages) { ArrayList resultList = null; // Set of all descendants of a library; used to eliminate cycles ArraySet descendants = null; // The current list of packages that need updating List> needsUpdating = null; if (updatedPkg != null && updatedPkgSetting != null) { needsUpdating = new ArrayList<>(1); needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting)); } do { final Pair changingPkgPair = (needsUpdating == null) ? null : needsUpdating.remove(0); final AndroidPackage changingPkg = changingPkgPair != null ? changingPkgPair.first : null; final PackageSetting changingPkgSetting = changingPkgPair != null ? changingPkgPair.second : null; for (int i = mPackages.size() - 1; i >= 0; --i) { final AndroidPackage pkg = mPackages.valueAt(i); final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName()); if (changingPkg != null && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames()) && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames()) && !ArrayUtils.contains(pkg.getUsesStaticLibraries(), changingPkg.getStaticSharedLibName())) { continue; } if (resultList == null) { resultList = new ArrayList<>(); } resultList.add(pkg); // if we're updating a shared library, all of its descendants must be updated if (changingPkg != null) { if (descendants == null) { descendants = new ArraySet<>(); } if (!descendants.contains(pkg.getPackageName())) { descendants.add(pkg.getPackageName()); needsUpdating.add(Pair.create(pkg, pkgSetting)); } } try { updateSharedLibrariesLocked(pkg, pkgSetting, changingPkg, changingPkgSetting, availablePackages); } catch (PackageManagerException e) { // If a system app update or an app and a required lib missing we // delete the package and for updated system apps keep the data as // it is better for the user to reinstall than to be in an limbo // state. Also libs disappearing under an app should never happen // - just in case. if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) { final int flags = pkgSetting.getPkgState().isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; deletePackageLIF(pkg.getPackageName(), null, true, mUserManager.getUserIds(), flags, null, true, null); } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } } } while (needsUpdating != null && needsUpdating.size() > 0); return resultList; } private int getVendorPartitionVersion() { final String version = SystemProperties.get("ro.vndk.version"); if (!version.isEmpty()) { try { return Integer.parseInt(version); } catch (NumberFormatException ignore) { if (ArrayUtils.contains(Build.VERSION.ACTIVE_CODENAMES, version)) { return Build.VERSION_CODES.CUR_DEVELOPMENT; } } } return Build.VERSION_CODES.P; } @GuardedBy({"mInstallLock", "mLock"}) private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); try { return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user, cpuAbiOverride); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** The result of a package scan. */ @VisibleForTesting static class ScanResult { /** The request that initiated the scan that produced this result. */ public final ScanRequest request; /** Whether or not the package scan was successful */ public final boolean success; /** * Whether or not the original PackageSetting needs to be updated with this result on * commit. */ public final boolean existingSettingCopied; /** * The final package settings. This may be the same object passed in * the {@link ScanRequest}, but, with modified values. */ @Nullable public final PackageSetting pkgSetting; /** ABI code paths that have changed in the package scan */ @Nullable public final List changedAbiCodePath; public final SharedLibraryInfo staticSharedLibraryInfo; public final List dynamicSharedLibraryInfos; public ScanResult( ScanRequest request, boolean success, @Nullable PackageSetting pkgSetting, @Nullable List changedAbiCodePath, boolean existingSettingCopied, SharedLibraryInfo staticSharedLibraryInfo, List dynamicSharedLibraryInfos) { this.request = request; this.success = success; this.pkgSetting = pkgSetting; this.changedAbiCodePath = changedAbiCodePath; this.existingSettingCopied = existingSettingCopied; this.staticSharedLibraryInfo = staticSharedLibraryInfo; this.dynamicSharedLibraryInfos = dynamicSharedLibraryInfos; } } /** A package to be scanned */ @VisibleForTesting static class ScanRequest { /** The parsed package */ @NonNull public final ParsedPackage parsedPackage; /** The package this package replaces */ @Nullable public final AndroidPackage oldPkg; /** Shared user settings, if the package has a shared user */ @Nullable public final SharedUserSetting sharedUserSetting; /** * Package settings of the currently installed version. *

    IMPORTANT: The contents of this object may be modified * during scan. */ @Nullable public final PackageSetting pkgSetting; /** A copy of the settings for the currently installed version */ @Nullable public final PackageSetting oldPkgSetting; /** Package settings for the disabled version on the /system partition */ @Nullable public final PackageSetting disabledPkgSetting; /** Package settings for the installed version under its original package name */ @Nullable public final PackageSetting originalPkgSetting; /** The real package name of a renamed application */ @Nullable public final String realPkgName; public final @ParseFlags int parseFlags; public final @ScanFlags int scanFlags; /** The user for which the package is being scanned */ @Nullable public final UserHandle user; /** Whether or not the platform package is being scanned */ public final boolean isPlatformPackage; /** Override value for package ABI if set during install */ @Nullable public final String cpuAbiOverride; public ScanRequest( @NonNull ParsedPackage parsedPackage, @Nullable SharedUserSetting sharedUserSetting, @Nullable AndroidPackage oldPkg, @Nullable PackageSetting pkgSetting, @Nullable PackageSetting disabledPkgSetting, @Nullable PackageSetting originalPkgSetting, @Nullable String realPkgName, @ParseFlags int parseFlags, @ScanFlags int scanFlags, boolean isPlatformPackage, @Nullable UserHandle user, @Nullable String cpuAbiOverride) { this.parsedPackage = parsedPackage; this.oldPkg = oldPkg; this.pkgSetting = pkgSetting; this.sharedUserSetting = sharedUserSetting; this.oldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting); this.disabledPkgSetting = disabledPkgSetting; this.originalPkgSetting = originalPkgSetting; this.realPkgName = realPkgName; this.parseFlags = parseFlags; this.scanFlags = scanFlags; this.isPlatformPackage = isPlatformPackage; this.user = user; this.cpuAbiOverride = cpuAbiOverride; } } /** * Returns the actual scan flags depending upon the state of the other settings. *

    Updated system applications will not have the following flags set * by default and need to be adjusted after the fact: *

      *
    • {@link #SCAN_AS_SYSTEM}
    • *
    • {@link #SCAN_AS_PRIVILEGED}
    • *
    • {@link #SCAN_AS_OEM}
    • *
    • {@link #SCAN_AS_VENDOR}
    • *
    • {@link #SCAN_AS_PRODUCT}
    • *
    • {@link #SCAN_AS_SYSTEM_EXT}
    • *
    • {@link #SCAN_AS_INSTANT_APP}
    • *
    • {@link #SCAN_AS_VIRTUAL_PRELOAD}
    • *
    • {@link #SCAN_AS_ODM}
    • *
    */ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user, AndroidPackage pkg) { // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain // the correct isSystem value now that we don't disable system packages before scan. final PackageSetting systemPkgSetting = (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null && pkgSetting != null && pkgSetting.isSystem() ? pkgSetting : disabledPkgSetting; if (systemPkgSetting != null) { // updated system application, must at least have SCAN_AS_SYSTEM scanFlags |= SCAN_AS_SYSTEM; if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { scanFlags |= SCAN_AS_PRIVILEGED; } if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) { scanFlags |= SCAN_AS_OEM; } if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) { scanFlags |= SCAN_AS_VENDOR; } if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) { scanFlags |= SCAN_AS_PRODUCT; } if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) { scanFlags |= SCAN_AS_SYSTEM_EXT; } if ((systemPkgSetting.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) { scanFlags |= SCAN_AS_ODM; } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); if (pkgSetting.getInstantApp(userId)) { scanFlags |= SCAN_AS_INSTANT_APP; } if (pkgSetting.getVirtulalPreload(userId)) { scanFlags |= SCAN_AS_VIRTUAL_PRELOAD; } } // Scan as privileged apps that share a user with a priv-app. final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0) && getVendorPartitionVersion() < 28; if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) && !pkg.isPrivileged() && (pkg.getSharedUserId() != null) && !skipVendorPrivilegeScan) { SharedUserSetting sharedUserSetting = null; try { sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0, 0, false); } catch (PackageManagerException ignore) { } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. // TODO(b/72378145) Fix this exemption. Force signature apps // to allowlist their privileged permissions just like other // priv-apps. synchronized (mLock) { PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures, pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { scanFlags |= SCAN_AS_PRIVILEGED; } } } } return scanFlags; } // TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting // the results / removing app data needs to be moved up a level to the callers of this // method. Also, we need to solve the problem of potentially creating a new shared user // setting. That can probably be done later and patch things up after the fact. @GuardedBy({"mInstallLock", "mLock"}) private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException { final String renamedPkgName = mSettings.getRenamedPackageLPr( parsedPackage.getRealPackage()); final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { ensurePackageRenamed(parsedPackage, renamedPkgName); } final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, renamedPkgName); final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName()); final PackageSetting disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName()); if (mTransferredPackages.contains(parsedPackage.getPackageName())) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " was transferred to another, but its .apk remains"); } scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage); synchronized (mLock) { boolean isUpdatedSystemApp; if (pkgSetting != null) { isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp(); } else { isUpdatedSystemApp = disabledPkgSetting != null; } applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp); assertPackageIsValid(parsedPackage, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; if (parsedPackage.getSharedUserId() != null) { // SIDE EFFECTS; may potentially allocate a new shared user sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) { Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } } } String platformPackageName = mPlatformPackage == null ? null : mPlatformPackage.getPackageName(); final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting, originalPkgSetting, realPkgName, parseFlags, scanFlags, Objects.equals(parsedPackage.getPackageName(), platformPackageName), user, cpuAbiOverride); return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime); } } /** * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering * the app ID required for reconcile. * @return {@code true} if a new app ID was registered and will need to be cleaned up on * failure. */ private boolean optimisticallyRegisterAppId(@NonNull ScanResult result) throws PackageManagerException { if (!result.existingSettingCopied) { // THROWS: when we can't allocate a user id. add call to check if there's // enough space to ensure we won't throw; otherwise, don't modify state return mSettings.registerAppIdLPw(result.pkgSetting); } return false; } /** * Reverts any app ID creation that were made by * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the * referenced method returned true. */ private void cleanUpAppIdCreation(@NonNull ScanResult result) { // iff we've acquired an app ID for a new package setting, remove it so that it can be // acquired by another request. if (result.pkgSetting.appId > 0) { mSettings.removeAppIdLPw(result.pkgSetting.appId); } } /** * Commits the package scan and modifies system state. *

    WARNING: The method may throw an excpetion in the middle * of committing the package, leaving the system in an inconsistent state. * This needs to be fixed so, once we get to this point, no errors are * possible and the system is not left in an inconsistent state. */ @GuardedBy({"mLock", "mInstallLock"}) private AndroidPackage commitReconciledScanResultLocked( @NonNull ReconciledPackage reconciledPkg, int[] allUsers) { final ScanResult result = reconciledPkg.scanResult; final ScanRequest request = result.request; // TODO(b/135203078): Move this even further away ParsedPackage parsedPackage = request.parsedPackage; if ("android".equals(parsedPackage.getPackageName())) { // TODO(b/135203078): Move this to initial parse parsedPackage.setVersionCode(mSdkVersion) .setVersionCodeMajor(0); } final AndroidPackage oldPkg = request.oldPkg; final @ParseFlags int parseFlags = request.parseFlags; final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; final UserHandle user = request.user; final String realPkgName = request.realPkgName; final List changedAbiCodePath = result.changedAbiCodePath; final PackageSetting pkgSetting; if (request.pkgSetting != null && request.pkgSetting.sharedUser != null && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) { // shared user changed, remove from old shared user request.pkgSetting.sharedUser.removePackage(request.pkgSetting); } if (result.existingSettingCopied) { pkgSetting = request.pkgSetting; pkgSetting.updateFrom(result.pkgSetting); } else { pkgSetting = result.pkgSetting; if (originalPkgSetting != null) { mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(), originalPkgSetting.name); mTransferredPackages.add(originalPkgSetting.name); } else { mSettings.removeRenamedPackageLPw(parsedPackage.getPackageName()); } } if (pkgSetting.sharedUser != null) { pkgSetting.sharedUser.addPackage(pkgSetting); } if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) { pkgSetting.forceQueryableOverride = true; } // If this is part of a standard install, set the initiating package name, else rely on // previous device state. if (reconciledPkg.installArgs != null) { InstallSource installSource = reconciledPkg.installArgs.installSource; if (installSource.initiatingPackageName != null) { final PackageSetting ips = mSettings.getPackageLPr( installSource.initiatingPackageName); if (ips != null) { installSource = installSource.setInitiatingPackageSignatures( ips.signatures); } } pkgSetting.setInstallSource(installSource); } // TODO(toddke): Consider a method specifically for modifying the Package object // post scan; or, moving this stuff out of the Package object since it has nothing // to do with the package on disk. // We need to have this here because addUserToSettingLPw() is sometimes responsible // for creating the application ID. If we did this earlier, we would be saving the // correct ID. parsedPackage.setUid(pkgSetting.appId); final AndroidPackage pkg = parsedPackage.hideAsFinal(); mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting); if (realPkgName != null) { mTransferredPackages.add(pkg.getPackageName()); } if (reconciledPkg.collectedSharedLibraryInfos != null) { executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null, reconciledPkg.collectedSharedLibraryInfos, allUsers); } final KeySetManagerService ksms = mSettings.getKeySetManagerService(); if (reconciledPkg.removeAppKeySetData) { ksms.removeAppKeySetDataLPw(pkg.getPackageName()); } if (reconciledPkg.sharedUserSignaturesChanged) { pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE; pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails; } pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { final String codePathString = changedAbiCodePath.get(i); try { mInstaller.rmdex(codePathString, getDexCodeInstructionSet(getPreferredInstructionSet())); } catch (InstallerException ignored) { } } } final int userId = user == null ? 0 : user.getIdentifier(); // Modify state for the given package setting commitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags, (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); if (pkgSetting.getInstantApp(userId)) { mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); } pkgSetting.setStatesOnCommit(); return pkg; } /** * Returns the "real" name of the package. *

    This may differ from the package's actual name if the application has already * been installed under one of this package's original names. */ private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (isPackageRenamed(pkg, renamedPkgName)) { return pkg.getRealPackage(); } return null; } /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */ private static boolean isPackageRenamed(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { return pkg.getOriginalPackages().contains(renamedPkgName); } /** * Returns the original package setting. *

    A package can migrate its name during an update. In this scenario, a package * designates a set of names that it considers as one of its original names. *

    An original package must be signed identically and it must have the same * shared user [if any]. */ @GuardedBy("mLock") private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (isPackageRenamed(pkg, renamedPkgName)) { return null; } for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) { final PackageSetting originalPs = mSettings.getPackageLPr(pkg.getOriginalPackages().get(i)); if (originalPs != null) { // the package is already installed under its original name... // but, should we use it? if (!verifyPackageUpdateLPr(originalPs, pkg)) { // the new package is incompatible with the original continue; } else if (originalPs.sharedUser != null) { if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) { // the shared user id is incompatible with the original Slog.w(TAG, "Unable to migrate data from " + originalPs.name + " to " + pkg.getPackageName() + ": old uid " + originalPs.sharedUser.name + " differs from " + pkg.getSharedUserId()); continue; } // TODO: Add case when shared user id is added [b/28144775] } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " + pkg.getPackageName() + " to old name " + originalPs.name); } return originalPs; } } return null; } /** * Renames the package if it was installed under a different name. *

    When we've already installed the package under an original name, update * the new package so we can continue to have the old name. */ private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage, @NonNull String renamedPackageName) { if (!parsedPackage.getOriginalPackages().contains(renamedPackageName) || parsedPackage.getPackageName().equals(renamedPackageName)) { return; } parsedPackage.setPackageName(renamedPackageName); } /** * Applies the adjusted ABI calculated by * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all * relevant packages and settings. * @param sharedUserSetting The {@code SharedUserSetting} to adjust * @param scannedPackage the package being scanned or null * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper} * @return the list of code paths that belong to packages that had their ABIs adjusted. */ private static List applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting, ParsedPackage scannedPackage, String adjustedAbi) { if (scannedPackage != null) { scannedPackage.setPrimaryCpuAbi(adjustedAbi); } List changedAbiCodePath = null; for (PackageSetting ps : sharedUserSetting.packages) { if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) { if (ps.primaryCpuAbiString != null) { continue; } ps.primaryCpuAbiString = adjustedAbi; if (ps.pkg != null) { if (!TextUtils.equals(adjustedAbi, AndroidPackageUtils.getRawPrimaryCpuAbi(ps.pkg))) { if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi + " (scannedPackage=" + (scannedPackage != null ? scannedPackage : "null") + ")"); } if (changedAbiCodePath == null) { changedAbiCodePath = new ArrayList<>(); } changedAbiCodePath.add(ps.getPathString()); } } } } return changedAbiCodePath; } /** * Sets the enabled state of components configured through {@link SystemConfig}. * This modifies the {@link PackageSetting} object. * * TODO(b/135203078): Move this to package parsing **/ static void configurePackageComponents(AndroidPackage pkg) { final ArrayMap componentsEnabledStates = SystemConfig.getInstance() .getComponentsEnabledStates(pkg.getPackageName()); if (componentsEnabledStates == null) { return; } for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) { final ParsedActivity component = pkg.getActivities().get(i); final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } } for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) { final ParsedActivity component = pkg.getReceivers().get(i); final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } } for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) { final ParsedProvider component = pkg.getProviders().get(i); final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } } for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) { final ParsedService component = pkg.getServices().get(i); final Boolean enabled = componentsEnabledStates.get(component.getName()); if (enabled != null) { component.setEnabled(enabled); } } } /** * Just scans the package without any side effects. *

    Not entirely true at the moment. There is still one side effect -- this * method potentially modifies a live {@link PackageSetting} object representing * the package being scanned. This will be resolved in the future. * * @param injector injector for acquiring dependencies * @param request Information about the package to be scanned * @param isUnderFactoryTest Whether or not the device is under factory test * @param currentTime The current time, in millis * @return The results of the scan */ @GuardedBy("mInstallLock") @VisibleForTesting @NonNull static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request, Injector injector, boolean isUnderFactoryTest, long currentTime) throws PackageManagerException { final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); final UserManagerInternal userManager = injector.getUserManagerInternal(); ParsedPackage parsedPackage = request.parsedPackage; PackageSetting pkgSetting = request.pkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; final @ParseFlags int parseFlags = request.parseFlags; final @ScanFlags int scanFlags = request.scanFlags; final String realPkgName = request.realPkgName; final SharedUserSetting sharedUserSetting = request.sharedUserSetting; final UserHandle user = request.user; final boolean isPlatformPackage = request.isPlatformPackage; List changedAbiCodePath = null; if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) { Log.d(TAG, "Scanning package " + parsedPackage.getPackageName()); } } // Initialize package source and resource directories final File destCodeFile = new File(parsedPackage.getPath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. String primaryCpuAbiFromSettings = null; String secondaryCpuAbiFromSettings = null; boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0; if (!needToDeriveAbi) { if (pkgSetting != null) { // TODO(b/154610922): if it is not first boot or upgrade, we should directly use // API info from existing package setting. However, stub packages currently do not // preserve ABI info, thus the special condition check here. Remove the special // check after we fix the stub generation. if (pkgSetting.pkg != null && pkgSetting.pkg.isStub()) { needToDeriveAbi = true; } else { primaryCpuAbiFromSettings = pkgSetting.primaryCpuAbiString; secondaryCpuAbiFromSettings = pkgSetting.secondaryCpuAbiString; } } else { // Re-scanning a system package after uninstalling updates; need to derive ABI needToDeriveAbi = true; } } if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) { PackageManagerService.reportSettingsProblem(Log.WARN, "Package " + parsedPackage.getPackageName() + " shared user changed from " + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "") + " to " + (sharedUserSetting != null ? sharedUserSetting.name : "") + "; replacing with new"); pkgSetting = null; } String[] usesStaticLibraries = null; if (!parsedPackage.getUsesStaticLibraries().isEmpty()) { usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); } final UUID newDomainSetId = injector.getDomainVerificationManagerInternal().generateNewId(); // TODO(b/135203078): Remove appInfoFlag usage in favor of individually assigned booleans // to avoid adding something that's unsupported due to lack of state, since it's called // with null. final boolean createNewPackage = (pkgSetting == null); if (createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; // Flags contain system values stored in the server variant of AndroidPackage, // and so the server-side PackageInfoUtils is still called, even without a // PackageSetting to pass in. int pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, null); int pkgPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(parsedPackage, null); // REMOVE SharedUserSetting from method; update in a separate call pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, parsedPackage.getNativeLibraryRootDir(), AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user, true /*allowInstall*/, instantApp, virtualPreload, UserManagerService.getInstance(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), newDomainSetId); } else { // make a deep copy to avoid modifying any existing system state. pkgSetting = new PackageSetting(pkgSetting); pkgSetting.pkg = parsedPackage; // REMOVE SharedUserSetting from method; update in a separate call. // // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi, // secondaryCpuAbi are not known at this point so we always update them // to null here, only to reset them at a later point. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting, destCodeFile, parsedPackage.getNativeLibraryDir(), AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting), AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting), PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting), PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting), UserManagerService.getInstance(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), newDomainSetId); } if (createNewPackage && originalPkgSetting != null) { // This is the initial transition from the original package, so, // fix up the new package's name now. We must do this after looking // up the package under its new name, so getPackageLP takes care of // fiddling things correctly. parsedPackage.setPackageName(originalPkgSetting.name); // File a report about this. String msg = "New package " + pkgSetting.realName + " renamed to replace old package " + pkgSetting.name; reportSettingsProblem(Log.WARN, msg); } final int userId = (user == null ? UserHandle.USER_SYSTEM : user.getIdentifier()); // for existing packages, change the install state; but, only if it's explicitly specified if (!createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0; setInstantAppForUser(injector, pkgSetting, userId, instantApp, fullApp); } // TODO(patb): see if we can do away with disabled check here. if (disabledPkgSetting != null || (0 != (scanFlags & SCAN_NEW_INSTALL) && pkgSetting != null && pkgSetting.isSystem())) { pkgSetting.getPkgState().setUpdatedSystemApp(true); } parsedPackage .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting, injector.getCompatibility())) .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))); if (parsedPackage.isSystem()) { configurePackageComponents(parsedPackage); } final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride); final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp(); final File appLib32InstallDir = getAppLib32InstallDir(); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if (needToDeriveAbi) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); final Pair derivedAbi = packageAbiHelper.derivePackageAbi(parsedPackage, isUpdatedSystemApp, cpuAbiOverride, appLib32InstallDir); derivedAbi.first.applyTo(parsedPackage); derivedAbi.second.applyTo(parsedPackage); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage); if (parsedPackage.isSystem() && !isUpdatedSystemApp && pkgRawPrimaryCpuAbi == null) { final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis( parsedPackage); abis.applyTo(parsedPackage); abis.applyTo(pkgSetting); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp, appLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); } } else { // This is not a first boot or an upgrade, don't bother deriving the // ABI during the scan. Instead, trust the value that was stored in the // package setting. parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings) .setSecondaryCpuAbi(secondaryCpuAbiFromSettings); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp, appLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Using ABIS and native lib paths from settings : " + parsedPackage.getPackageName() + " " + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) + ", " + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)); } } } else { if ((scanFlags & SCAN_MOVE) != 0) { // We haven't run dex-opt for this move (since we've moved the compiled output too) // but we already have this packages package info in the PackageSetting. We just // use that and derive the native library path based on the new codepath. parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString) .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString); } // Set native library paths again. For moves, the path will be updated based on the // ABIs we've determined above. For non-moves, the path will be updated based on the // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp, appLib32InstallDir); nativeLibraryPaths.applyTo(parsedPackage); } // This is a special case for the "system" package, where the ABI is // dictated by the zygote configuration (and init.rc). We should keep track // of this ABI so that we can deal with "normal" applications that run under // the same UID correctly. if (isPlatformPackage) { parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]); } // If there's a mismatch between the abi-override in the package setting // and the abiOverride specified for the install. Warn about this because we // would've already compiled the app without taking the package setting into // account. if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { if (cpuAbiOverride == null) { Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride + " for package " + parsedPackage.getPackageName()); } } pkgSetting.primaryCpuAbiString = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage); pkgSetting.secondaryCpuAbiString = AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage); pkgSetting.cpuAbiOverrideString = cpuAbiOverride; if (DEBUG_ABI_SELECTION) { Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName() + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", to dir=" + parsedPackage.getNativeLibraryDir() + ", isa=" + parsedPackage.isNativeLibraryRootRequiresIsa()); } // Push the derived path down into PackageSettings so we know what to // clean up at uninstall time. pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir(); if (DEBUG_ABI_SELECTION) { Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" + " primary=" + pkgSetting.primaryCpuAbiString + " secondary=" + pkgSetting.primaryCpuAbiString + " abiOverride=" + pkgSetting.cpuAbiOverrideString); } if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { // We don't do this here during boot because we can do it all // at once after scanning all existing packages. // // We also do this *before* we perform dexopt on this package, so that // we can avoid redundant dexopts, and also to make sure we've got the // code and package path correct. changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser( pkgSetting.sharedUser.packages, parsedPackage)); } parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions() .contains(android.Manifest.permission.FACTORY_TEST)); if (parsedPackage.isSystem()) { pkgSetting.setIsOrphaned(true); } // Take care of first install / last update times. final long scanFileTime = getLastModifiedTime(parsedPackage); if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime; } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) { pkgSetting.lastUpdateTime = currentTime; } } else if (pkgSetting.firstInstallTime == 0) { // We need *something*. Take time time stamp of the file. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime; } else if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) { if (scanFileTime != pkgSetting.timeStamp) { // A package on the system image has changed; consider this // to be an update. pkgSetting.lastUpdateTime = scanFileTime; } } pkgSetting.setTimeStamp(scanFileTime); // TODO(b/135203078): Remove, move to constructor pkgSetting.pkg = parsedPackage; pkgSetting.pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting); pkgSetting.pkgPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting); if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) { pkgSetting.versionCode = parsedPackage.getLongVersionCode(); } // Update volume if needed final String volumeUuid = parsedPackage.getVolumeUuid(); if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) { Slog.i(PackageManagerService.TAG, "Update" + (pkgSetting.isSystem() ? " system" : "") + " package " + parsedPackage.getPackageName() + " volume from " + pkgSetting.volumeUuid + " to " + volumeUuid); pkgSetting.volumeUuid = volumeUuid; } SharedLibraryInfo staticSharedLibraryInfo = null; if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) { staticSharedLibraryInfo = AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage); } List dynamicSharedLibraryInfos = null; if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); for (String name : parsedPackage.getLibraryNames()) { dynamicSharedLibraryInfos.add( AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name)); } } return new ScanResult(request, true, pkgSetting, changedAbiCodePath, !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo, dynamicSharedLibraryInfos); } /** * Returns {@code true} if the given file contains code. Otherwise {@code false}. */ private static boolean apkHasCode(String fileName) { StrictJarFile jarFile = null; try { jarFile = new StrictJarFile(fileName, false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/); return jarFile.findEntry("classes.dex") != null; } catch (IOException ignore) { } finally { try { if (jarFile != null) { jarFile.close(); } } catch (IOException ignore) {} } return false; } /** * Enforces code policy for the package. This ensures that if an APK has * declared hasCode="true" in its manifest that the APK actually contains * code. * * @throws PackageManagerException If bytecode could not be found when it should exist */ private static void assertCodePolicy(AndroidPackage pkg) throws PackageManagerException { final boolean shouldHaveCode = pkg.isHasCode(); if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package " + pkg.getBaseApkPath() + " code is missing"); } if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) { for (int i = 0; i < pkg.getSplitCodePaths().length; i++) { final boolean splitShouldHaveCode = (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package " + pkg.getSplitCodePaths()[i] + " code is missing"); } } } } /** * Applies policy to the parsed package based upon the given policy flags. * Ensures the package is in a good state. *

    * Implementation detail: This method must NOT have any side effect. It would * ideally be static, but, it requires locks to read system state. */ private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags, AndroidPackage platformPkg, boolean isUpdatedSystemApp) { if ((scanFlags & SCAN_AS_SYSTEM) != 0) { parsedPackage.setSystem(true); // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag // is set during parse. if (parsedPackage.isDirectBootAware()) { parsedPackage.setAllComponentsDirectBootAware(true); } if (compressedFileExists(parsedPackage.getPath())) { parsedPackage.setStub(true); } } else { parsedPackage // Non system apps cannot mark any broadcast as protected .clearProtectedBroadcasts() // non system apps can't be flagged as core .setCoreApp(false) // clear flags not applicable to regular apps .setPersistent(false) .setDefaultToDeviceProtectedStorage(false) .setDirectBootAware(false) // non system apps can't have permission priority .capPermissionPriorities(); } if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { parsedPackage .markNotActivitiesAsNotExportedIfSingleUser(); } parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0) .setOem((scanFlags & SCAN_AS_OEM) != 0) .setVendor((scanFlags & SCAN_AS_VENDOR) != 0) .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0) .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) .setOdm((scanFlags & SCAN_AS_ODM) != 0); // Check if the package is signed with the same key as the platform package. parsedPackage.setSignedWithPlatformKey( (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName()) || (platformPkg != null && compareSignatures( platformPkg.getSigningDetails().signatures, parsedPackage.getSigningDetails().signatures ) == PackageManager.SIGNATURE_MATCH)) ); if (!parsedPackage.isSystem()) { // Only system apps can use these features. parsedPackage.clearOriginalPackages() .setRealPackage(null) .clearAdoptPermissions(); } PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp); } private static @NonNull T assertNotNull(@Nullable T object, String message) throws PackageManagerException { if (object == null) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, message); } return object; } private void assertPackageProcesses(AndroidPackage pkg, List components, Map procs, String compName) throws PackageManagerException { if (components == null) { return; } for (int i = components.size() - 1; i >= 0; i--) { final ParsedMainComponent component = components.get(i); if (!procs.containsKey(component.getProcessName())) { throw new PackageManagerException( INSTALL_FAILED_PROCESS_NOT_DEFINED, "Can't install because " + compName + " " + component.getClassName() + "'s process attribute " + component.getProcessName() + " (in package " + pkg.getPackageName() + ") is not included in the list"); } } } /** * Asserts the parsed package is valid according to the given policy. If the * package is invalid, for whatever reason, throws {@link PackageManagerException}. *

    * Implementation detail: This method must NOT have any side effects. It would * ideally be static, but, it requires locks to read system state. * * @throws PackageManagerException If the package fails any of the validation checks */ private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags) throws PackageManagerException { if ((parseFlags & ParsingPackageUtils.PARSE_ENFORCE_CODE) != 0) { assertCodePolicy(pkg); } if (pkg.getPath() == null) { // Bail out. The resource and code paths haven't been set. throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); } // Check that there is an APEX package with the same name only during install/first boot // after OTA. final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0; final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0; if ((isUserInstall || isFirstBootOrUpgrade) && mApexManager.isApexPackage(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, pkg.getPackageName() + " is an APEX package and can't be installed as an APK."); } // Make sure we're not adding any bogus keyset info final KeySetManagerService ksms = mSettings.getKeySetManagerService(); ksms.assertScannedPackageValid(pkg); synchronized (mLock) { // The special "android" package can only be defined once if (pkg.getPackageName().equals("android")) { if (mAndroidApplication != null) { Slog.w(TAG, "*************************************************"); Slog.w(TAG, "Core android package being redefined. Skipping."); Slog.w(TAG, " codePath=" + pkg.getPath()); Slog.w(TAG, "*************************************************"); throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, "Core android package being redefined. Skipping."); } } // A package name must be unique; don't allow duplicates if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, "Application package " + pkg.getPackageName() + " already installed. Skipping duplicate."); } if (pkg.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // but we still want the base name to be unique. if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.getManifestPackageName())) { throw new PackageManagerException( "Duplicate static shared lib provider package"); } // Static shared libraries should have at least O target SDK if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { throw new PackageManagerException( "Packages declaring static-shared libs must target O SDK or higher"); } // Package declaring static a shared lib cannot be instant apps if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { throw new PackageManagerException( "Packages declaring static-shared libs cannot be instant apps"); } // Package declaring static a shared lib cannot be renamed since the package // name is synthetic and apps can't code around package manager internals. if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot be renamed"); } // Package declaring static a shared lib cannot declare dynamic libs if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare dynamic libs"); } // Package declaring static a shared lib cannot declare shared users if (pkg.getSharedUserId() != null) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare shared users"); } // Static shared libs cannot declare activities if (!pkg.getActivities().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare activities"); } // Static shared libs cannot declare services if (!pkg.getServices().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare services"); } // Static shared libs cannot declare providers if (!pkg.getProviders().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare content providers"); } // Static shared libs cannot declare receivers if (!pkg.getReceivers().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare broadcast receivers"); } // Static shared libs cannot declare permission groups if (!pkg.getPermissionGroups().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permission groups"); } // Static shared libs cannot declare attributions if (!pkg.getAttributions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare features"); } // Static shared libs cannot declare permissions if (!pkg.getPermissions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permissions"); } // Static shared libs cannot declare protected broadcasts if (!pkg.getProtectedBroadcasts().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare protected broadcasts"); } // Static shared libs cannot be overlay targets if (pkg.getOverlayTarget() != null) { throw new PackageManagerException( "Static shared libs cannot be overlay targets"); } // The version codes must be ordered as lib versions long minVersionCode = Long.MIN_VALUE; long maxVersionCode = Long.MAX_VALUE; WatchedLongSparseArray versionedLib = mSharedLibraries.get( pkg.getStaticSharedLibName()); if (versionedLib != null) { final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { SharedLibraryInfo libInfo = versionedLib.valueAt(i); final long libVersionCode = libInfo.getDeclaringPackage() .getLongVersionCode(); if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) { minVersionCode = Math.max(minVersionCode, libVersionCode + 1); } else if (libInfo.getLongVersion() > pkg.getStaticSharedLibVersion()) { maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1); } else { minVersionCode = maxVersionCode = libVersionCode; break; } } } if (pkg.getLongVersionCode() < minVersionCode || pkg.getLongVersionCode() > maxVersionCode) { throw new PackageManagerException("Static shared" + " lib version codes must be ordered as lib versions"); } } // If we're only installing presumed-existing packages, require that the // scanned APK is both already known and at the path previously established // for it. Previously unknown packages we pick up normally, but if we have an // a priori expectation about this package's install presence, enforce it. // With a singular exception for new system packages. When an OTA contains // a new system package, we allow the codepath to change from a system location // to the user-installed location. If we don't allow this change, any newer, // user-installed version of the application will be ignored. if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) { if (mExpectingBetter.containsKey(pkg.getPackageName())) { Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.getPackageName()); } else { PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName()); if (known != null) { if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Examining " + pkg.getPath() + " and requiring known path " + known.getPathString()); } if (!pkg.getPath().equals(known.getPathString())) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, "Application package " + pkg.getPackageName() + " found at " + pkg.getPath() + " but expected at " + known.getPathString() + "; ignoring."); } } else { throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Application package " + pkg.getPackageName() + " not found; ignoring."); } } } // Verify that this new package doesn't have any content providers // that conflict with existing packages. Only do this if the // package isn't already installed, since we don't want to break // things that are installed. if ((scanFlags & SCAN_NEW_INSTALL) != 0) { mComponentResolver.assertProvidersNotDefined(pkg); } // If this package has defined explicit processes, then ensure that these are // the only processes used by its components. final Map procs = pkg.getProcesses(); if (!procs.isEmpty()) { if (!procs.containsKey(pkg.getProcessName())) { throw new PackageManagerException( INSTALL_FAILED_PROCESS_NOT_DEFINED, "Can't install because application tag's process attribute " + pkg.getProcessName() + " (in package " + pkg.getPackageName() + ") is not included in the list"); } assertPackageProcesses(pkg, pkg.getActivities(), procs, "activity"); assertPackageProcesses(pkg, pkg.getServices(), procs, "service"); assertPackageProcesses(pkg, pkg.getReceivers(), procs, "receiver"); assertPackageProcesses(pkg, pkg.getProviders(), procs, "provider"); } // Verify that packages sharing a user with a privileged app are marked as privileged. if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) { SharedUserSetting sharedUserSetting = null; try { sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0, 0, false); } catch (PackageManagerException ignore) { } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); if (!comparePackageSignatures(platformPkgSetting, pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.getPackageName() + " shares privileged user " + pkg.getSharedUserId() + "."); } } } // Apply policies specific for runtime resource overlays (RROs). if (pkg.getOverlayTarget() != null) { // System overlays have some restrictions on their use of the 'static' state. if ((scanFlags & SCAN_AS_SYSTEM) != 0) { // We are scanning a system overlay. This can be the first scan of the // system/vendor/oem partition, or an update to the system overlay. if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { // This must be an update to a system overlay. Immutable overlays cannot be // upgraded. Objects.requireNonNull(mOverlayConfig, "Parsing non-system dir before overlay configs are initialized"); if (!mOverlayConfig.isMutable(pkg.getPackageName())) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " is static and cannot be upgraded."); } } else { if ((scanFlags & SCAN_AS_VENDOR) != 0) { if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) { Slog.w(TAG, "System overlay " + pkg.getPackageName() + " targets an SDK below the required SDK level of vendor" + " overlays (" + getVendorPartitionVersion() + ")." + " This will become an install error in a future release"); } } else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) { Slog.w(TAG, "System overlay " + pkg.getPackageName() + " targets an SDK below the required SDK level of system" + " overlays (" + Build.VERSION.SDK_INT + ")." + " This will become an install error in a future release"); } } } else { // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be // signed with the platform certificate. Check this in increasing order of // computational cost. if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { final PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); if (!comparePackageSignatures(platformPkgSetting, pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " must target Q or later, " + "or be signed with the platform certificate"); } } // A non-preloaded overlay package, without , will // only be used if it is signed with the same certificate as its target OR if // it is signed with the same certificate as a reference package declared // in 'overlay-config-signature' tag of SystemConfig. // If the target is already installed or 'overlay-config-signature' tag in // SystemConfig is set, check this here to augment the last line of defense // which is OMS. if (pkg.getOverlayTargetName() == null) { final PackageSetting targetPkgSetting = mSettings.getPackageLPr(pkg.getOverlayTarget()); if (targetPkgSetting != null) { if (!comparePackageSignatures(targetPkgSetting, pkg.getSigningDetails().signatures)) { // check reference signature if (mOverlayConfigSignaturePackage == null) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " and target " + pkg.getOverlayTarget() + " signed with" + " different certificates, and the overlay lacks" + " "); } final PackageSetting refPkgSetting = mSettings.getPackageLPr(mOverlayConfigSignaturePackage); if (!comparePackageSignatures(refPkgSetting, pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " signed with a different " + "certificate than both the reference package and " + "target " + pkg.getOverlayTarget() + ", and the " + "overlay lacks "); } } } } } } // If the package is not on a system partition ensure it is signed with at least the // minimum signature scheme version required for its target SDK. if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { int minSignatureSchemeVersion = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( pkg.getTargetSdkVersion()); if (pkg.getSigningDetails().signatureSchemeVersion < minSignatureSchemeVersion) { throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No signature found in package of version " + minSignatureSchemeVersion + " or newer for package " + pkg.getPackageName()); } } } } @GuardedBy("mLock") private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) { if (nonStaticSharedLibExistsLocked(entry.name)) { return false; } SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null, entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN, new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null, entry.isNative); commitSharedLibraryInfoLocked(libraryInfo); return true; } @GuardedBy("mLock") private boolean nonStaticSharedLibExistsLocked(String name) { return sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED, mSharedLibraries); } private static boolean sharedLibExists(final String name, final long version, Map> librarySource) { WatchedLongSparseArray versionedLib = librarySource.get(name); if (versionedLib != null && versionedLib.indexOfKey(version) >= 0) { return true; } return false; } @GuardedBy("mLock") private void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) { final String name = libraryInfo.getName(); WatchedLongSparseArray versionedLib = mSharedLibraries.get(name); if (versionedLib == null) { versionedLib = new WatchedLongSparseArray<>(); mSharedLibraries.put(name, versionedLib); } final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName(); if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) { mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib); } versionedLib.put(libraryInfo.getLongVersion(), libraryInfo); } private boolean removeSharedLibraryLPw(String name, long version) { WatchedLongSparseArray versionedLib = mSharedLibraries.get(name); if (versionedLib == null) { return false; } final int libIdx = versionedLib.indexOfKey(version); if (libIdx < 0) { return false; } SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx); // Remove the shared library overlays from its dependent packages. for (int currentUserId : UserManagerService.getInstance().getUserIds()) { final List dependents = getPackagesUsingSharedLibraryLPr( libraryInfo, 0, Process.SYSTEM_UID, currentUserId); if (dependents == null) { continue; } for (VersionedPackage dependentPackage : dependents) { final PackageSetting ps = mSettings.getPackageLPr( dependentPackage.getPackageName()); if (ps != null) { ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId); } } } versionedLib.remove(version); if (versionedLib.size() <= 0) { mSharedLibraries.remove(name); if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) { mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage() .getPackageName()); } } return true; } @Override public Property getProperty(String propertyName, String packageName, String className) { Objects.requireNonNull(propertyName); Objects.requireNonNull(packageName); synchronized (mLock) { final PackageSetting ps = getPackageSetting(packageName); if (shouldFilterApplicationLocked(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) { return null; } return mPackageProperty.getProperty(propertyName, packageName, className); } } @Override public ParceledListSlice queryProperty( String propertyName, @PropertyLocation int componentType) { Objects.requireNonNull(propertyName); final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getCallingUserId(); final List result = mPackageProperty.queryProperty(propertyName, componentType, packageName -> { final PackageSetting ps = getPackageSetting(packageName); return shouldFilterApplicationLocked(ps, callingUid, callingUserId); }); if (result == null) { return ParceledListSlice.emptyList(); } return new ParceledListSlice<>(result); } /** * Adds a scanned package to the system. When this method is finished, the package will * be available for query, resolution, etc... */ private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg, @NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting, final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) { final String pkgName = pkg.getPackageName(); if (mCustomResolverComponentName != null && mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) { setUpCustomResolverActivity(pkg, pkgSetting); } if (pkg.getPackageName().equals("android")) { 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 = pkg.toAppInfoWithoutState(); mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting); mAndroidApplication.privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting); mAndroidApplication.initForUser(UserHandle.USER_SYSTEM); 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; 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); } onChanged(); } } ArrayList clientLibPkgs = null; // writer synchronized (mLock) { if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) { for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) { commitSharedLibraryInfoLocked(info); } final Map combinedSigningDetails = reconciledPkg.getCombinedAvailablePackages(); try { // Shared libraries for the package need to be updated. updateSharedLibrariesLocked(pkg, pkgSetting, null, null, combinedSigningDetails); } catch (PackageManagerException e) { Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e); } // Update all applications that use this library. Skip when booting // since this will be done after all packages are scaned. if ((scanFlags & SCAN_BOOTING) == 0) { clientLibPkgs = updateAllSharedLibrariesLocked(pkg, pkgSetting, combinedSigningDetails); } } } if (reconciledPkg.installResult != null) { reconciledPkg.installResult.libraryConsumers = clientLibPkgs; } if ((scanFlags & SCAN_BOOTING) != 0) { // No apps can run during boot scan, so they don't need to be frozen } else if ((scanFlags & SCAN_DONT_KILL_APP) != 0) { // Caller asked to not kill app, so it's probably not frozen } else if ((scanFlags & SCAN_IGNORE_FROZEN) != 0) { // Caller asked us to ignore frozen check for some reason; they // probably didn't know the package name } else { // We're doing major surgery on this package, so it better be frozen // right now to keep it from launching checkPackageFrozen(pkgName); } // Also need to kill any apps that are dependent on the library. if (clientLibPkgs != null) { for (int i=0; i protectedBroadcasts = pkg.getProtectedBroadcasts(); if (!protectedBroadcasts.isEmpty()) { synchronized (mProtectedBroadcasts) { mProtectedBroadcasts.addAll(protectedBroadcasts); } } mPermissionManager.onPackageAdded(pkg, (scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg); } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } private 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 = pkg.toAppInfoWithoutState(); appInfo.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting); appInfo.privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting); appInfo.initForUser(UserHandle.USER_SYSTEM); // 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; mResolveActivity.theme = 0; mResolveActivity.exported = true; mResolveActivity.enabled = true; mResolveInfo.activityInfo = mResolveActivity; mResolveInfo.priority = 0; mResolveInfo.preferredOrder = 0; mResolveInfo.match = 0; mResolveComponentName = mCustomResolverComponentName; onChanged(); Slog.i(TAG, "Replacing default ResolverActivity with custom activity: " + mResolveComponentName); } } 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(); } private void killApplication(String pkgName, @AppIdInt int appId, String reason) { killApplication(pkgName, appId, UserHandle.USER_ALL, reason); } private void killApplication(String pkgName, @AppIdInt int appId, @UserIdInt int userId, String reason) { // 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); } catch (RemoteException e) { } } } finally { Binder.restoreCallingIdentity(token); } } private void removePackageLI(AndroidPackage pkg, boolean chatty) { // Remove the parent package setting PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { removePackageLI(ps.name, chatty); } else if (DEBUG_REMOVE && chatty) { Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null"); } } private void removePackageLI(String packageName, boolean chatty) { if (DEBUG_INSTALL) { if (chatty) Log.d(TAG, "Removing package " + packageName); } // writer synchronized (mLock) { final AndroidPackage removedPackage = mPackages.remove(packageName); if (removedPackage != null) { cleanPackageDataStructuresLILPw(removedPackage, chatty); } } } private void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); mPermissionManager.onPackageRemoved(pkg); mPackageProperty.removeAllProperties(pkg); final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); StringBuilder r = null; int i; for (i = 0; i < instrumentationSize; i++) { ParsedInstrumentation a = pkg.getInstrumentations().get(i); mInstrumentation.remove(a.getComponentName()); if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.getName()); } } if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r); } r = null; if (pkg.isSystem()) { // Only system apps can hold shared libraries. final int libraryNamesSize = pkg.getLibraryNames().size(); for (i = 0; i < libraryNamesSize; i++) { String name = pkg.getLibraryNames().get(i); if (removeSharedLibraryLPw(name, 0)) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(name); } } } } r = null; // Any package can hold static shared libraries. if (pkg.getStaticSharedLibName() != null) { if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion())) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(pkg.getStaticSharedLibName()); } } } if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Libraries: " + r); } } @Override public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, @Nullable SparseArray broadcastAllowList, @Nullable Bundle bOptions) { mHandler.post(() -> { try { final IActivityManager am = ActivityManager.getService(); if (am == null) return; final int[] resolvedUserIds; if (userIds == null) { resolvedUserIds = am.getRunningUserIds(); } else { resolvedUserIds = userIds; } doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver, resolvedUserIds, false, broadcastAllowList, bOptions); if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) { doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver, instantUserIds, true, null, bOptions); } } catch (RemoteException ex) { } }); } @Override public void notifyPackageAdded(String packageName, int uid) { final PackageListObserver[] observers; synchronized (mLock) { if (mPackageListObservers.size() == 0) { return; } final PackageListObserver[] observerArray = new PackageListObserver[mPackageListObservers.size()]; observers = mPackageListObservers.toArray(observerArray); } for (int i = observers.length - 1; i >= 0; --i) { observers[i].onPackageAdded(packageName, uid); } } @Override public void notifyPackageChanged(String packageName, int uid) { final PackageListObserver[] observers; synchronized (mLock) { if (mPackageListObservers.size() == 0) { return; } final PackageListObserver[] observerArray = new PackageListObserver[mPackageListObservers.size()]; observers = mPackageListObservers.toArray(observerArray); } for (int i = observers.length - 1; i >= 0; --i) { observers[i].onPackageChanged(packageName, uid); } } private static final Comparator sProviderInitOrderSorter = (p1, p2) -> { final int v1 = p1.initOrder; final int v2 = p2.initOrder; return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0); }; @Override public void notifyPackageRemoved(String packageName, int uid) { final PackageListObserver[] observers; synchronized (mLock) { if (mPackageListObservers.size() == 0) { return; } final PackageListObserver[] observerArray = new PackageListObserver[mPackageListObservers.size()]; observers = mPackageListObservers.toArray(observerArray); } for (int i = observers.length - 1; i >= 0; --i) { observers[i].onPackageRemoved(packageName, uid); } } /** * Sends a broadcast for the given action. *

    If {@code isInstantApp} is {@code true}, then the broadcast is protected with * the {@link android.Manifest.permission#ACCESS_INSTANT_APPS} permission. This allows * the system and applications allowed to see instant applications to receive package * lifecycle events for instant applications. */ private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras, int flags, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds, boolean isInstantApp, @Nullable SparseArray broadcastAllowList, @Nullable Bundle bOptions) { for (int id : userIds) { final Intent intent = new Intent(action, pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null); final String[] requiredPermissions = isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null; if (extras != null) { intent.putExtras(extras); } if (targetPkg != null) { intent.setPackage(targetPkg); } // Modify the UID when posting to other users int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid > 0 && UserHandle.getUserId(uid) != id) { uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); intent.putExtra(Intent.EXTRA_UID, uid); } if (broadcastAllowList != null && PLATFORM_PACKAGE_NAME.equals(targetPkg)) { intent.putExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST, broadcastAllowList.get(id)); } intent.putExtra(Intent.EXTRA_USER_HANDLE, id); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags); if (DEBUG_BROADCASTS) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Slog.d(TAG, "Sending to user " + id + ": " + intent.toShortString(false, true, false, false) + " " + intent.getExtras(), here); } mInjector.getLocalService(ActivityManagerInternal.class).broadcastIntent( intent, finishedReceiver, requiredPermissions, finishedReceiver != null, id, broadcastAllowList == null ? null : broadcastAllowList.get(id), bOptions); } } /** * Check if the external storage media is available. This is true if there * is a mounted external storage medium or if the external storage is * emulated. */ private boolean isExternalMediaAvailable() { return mMediaMounted || Environment.isExternalStorageEmulated(); } /** * Ensure that the install reason matches what we know about the package installer (e.g. whether * it is acting on behalf on an enterprise or the user). * * Note that the ordering of the conditionals in this method is important. The checks we perform * are as follows, in this order: * * 1) If the install is being performed by a system app, we can trust the app to have set the * install reason correctly. Thus, we pass through the install reason unchanged, no matter * what it is. * 2) If the install is being performed by a device or profile owner app, the install reason * should be enterprise policy. However, we cannot be sure that the device or profile owner * set the install reason correctly. If the app targets an older SDK version where install * reasons did not exist yet, or if the app author simply forgot, the install reason may be * unset or wrong. Thus, we force the install reason to be enterprise policy. * 3) In all other cases, the install is being performed by a regular app that is neither part * of the system nor a device or profile owner. We have no reason to believe that this app is * acting on behalf of the enterprise admin. Thus, we check whether the install reason was * set to enterprise policy and if so, change it to unknown instead. */ private int fixUpInstallReason(String installerPackageName, int installerUid, int installReason) { if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) == PERMISSION_GRANTED) { // If the install is being performed by a system app, we trust that app to have set the // install reason correctly. return installReason; } final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage( UserHandle.getUserId(installerUid)); if (ownerPackage != null && ownerPackage.equals(installerPackageName)) { // If the install is being performed by a device or profile owner, the install // reason should be enterprise policy. return PackageManager.INSTALL_REASON_POLICY; } if (installReason == PackageManager.INSTALL_REASON_POLICY) { // If the install is being performed by a regular app (i.e. neither system app nor // device or profile owner), we have no reason to believe that the app is acting on // behalf of an enterprise. If the app set the install reason to enterprise policy, // change it to unknown instead. return PackageManager.INSTALL_REASON_UNKNOWN; } // If the install is being performed by a regular app and the install reason was set to any // value but enterprise policy, leave the install reason unchanged. return installReason; } void installStage(InstallParams params) { final Message msg = mHandler.obtainMessage(INIT_COPY); params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } void installStage(InstallParams parent, List children) throws PackageManagerException { final Message msg = mHandler.obtainMessage(INIT_COPY); final MultiPackageInstallParams params = new MultiPackageInstallParams(parent, children); params.setTraceMethod("installStageMultiPackage") .setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } void verifyStage(VerificationParams params) { mHandler.post(()-> { params.startCopy(); }); } void verifyStage(VerificationParams parent, List children) throws PackageManagerException { final MultiPackageVerificationParams params = new MultiPackageVerificationParams(parent, children); mHandler.post(()-> { params.startCopy(); }); } private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting, int userId, int dataLoaderType) { final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting); final boolean isInstantApp = pkgSetting.getInstantApp(userId); final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId }; final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/, false /*startReceiver*/, pkgSetting.appId, userIds, instantUserIds, dataLoaderType); // Send a session commit broadcast final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo(); info.installReason = pkgSetting.getInstallReason(userId); info.appPackageName = packageName; sendSessionCommitBroadcast(info, userId); } @Override public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted, boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds, int dataLoaderType) { if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) { return; } Bundle extras = new Bundle(1); // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast final int uid = UserHandle.getUid( (ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId); extras.putInt(Intent.EXTRA_UID, uid); extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0, null, null, userIds, instantUserIds, mAppsFilter.getVisibilityAllowList( getPackageSettingInternal(packageName, Process.SYSTEM_UID), userIds, mSettings.getPackagesLocked()), null); if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) { mHandler.post(() -> { for (int userId : userIds) { sendBootCompletedBroadcastToSystemApp( packageName, includeStopped, userId); } } ); } } /** * The just-installed/enabled app is bundled on the system, so presumed to be able to run * automatically without needing an explicit launch. * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones. */ private void sendBootCompletedBroadcastToSystemApp( String packageName, boolean includeStopped, int userId) { // If user is not running, the app didn't miss any broadcast if (!mUserManager.isUserRunning(userId)) { return; } final IActivityManager am = ActivityManager.getService(); try { // Deliver LOCKED_BOOT_COMPLETED first Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) .setPackage(packageName); if (includeStopped) { lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); } final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED}; final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions( REASON_LOCKED_BOOT_COMPLETED); am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null, requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(), false, false, userId); // Deliver BOOT_COMPLETED only if user is unlocked final UserManagerInternal umInternal = mInjector.getUserManagerInternal(); if (umInternal.isUserUnlockingOrUnlocked(userId)) { Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName); if (includeStopped) { bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); } am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null, requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(), false, false, userId); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); PackageSetting pkgSetting; final int callingUid = Binder.getCallingUid(); 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; } final long callingId = Binder.clearCallingIdentity(); try { boolean sendAdded = false; boolean sendRemoved = false; // writer synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null) { return false; } if (shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) { return false; } // Do not allow "android" is being disabled if ("android".equals(packageName)) { Slog.w(TAG, "Cannot hide package: android"); 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 = mPackages.get(packageName); if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot hide package: " + packageName + " providing static shared library: " + pkg.getStaticSharedLibName()); return false; } // Only allow protected packages to hide themselves. if (hidden && !UserHandle.isSameApp(callingUid, pkgSetting.appId) && mProtectedPackages.isPackageStateProtected(userId, packageName)) { Slog.w(TAG, "Not hiding protected package: " + packageName); return false; } if (pkgSetting.getHidden(userId) != hidden) { pkgSetting.setHidden(hidden, userId); mSettings.writePackageRestrictionsLPr(userId); if (hidden) { sendRemoved = true; } else { sendAdded = true; } } } if (sendAdded) { sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE); return true; } if (sendRemoved) { killApplication(packageName, pkgSetting.appId, userId, "hiding pkg"); sendApplicationHiddenForUser(packageName, pkgSetting, userId); return true; } } finally { Binder.restoreCallingIdentity(callingId); } return false; } @Override public void setSystemAppHiddenUntilInstalled(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"); } synchronized (mLock) { final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null || !pkgSetting.isSystem()) { return; } if (pkgSetting.getPkg().isCoreApp() && !calledFromSystemOrPhone) { throw new SecurityException("Only system or phone callers can modify core apps"); } pkgSetting.getPkgState().setHiddenUntilInstalled(hidden); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); if (disabledPs == null) { return; } disabledPs.getPkgState().setHiddenUntilInstalled(hidden); } } @Override public boolean setSystemAppInstallState(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"); } synchronized (mLock) { final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); // The target app should always be in system if (pkgSetting == null || !pkgSetting.isSystem()) { return false; } if (pkgSetting.getPkg().isCoreApp() && !calledFromSystemOrPhone) { throw new SecurityException("Only system or phone callers can modify core apps"); } // Check if the install state is the same if (pkgSetting.getInstalled(userId) == installed) { return false; } } final long callingId = Binder.clearCallingIdentity(); try { if (installed) { // install the app from uninstalled state installExistingPackageAsUser( packageName, userId, PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, PackageManager.INSTALL_REASON_DEVICE_SETUP, null); return true; } // uninstall the app from installed state deletePackageVersioned( new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), new LegacyPackageDeleteObserver(null).getBinder(), userId, PackageManager.DELETE_SYSTEM_APP); return true; } finally { Binder.restoreCallingIdentity(callingId); } } private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(this); info.removedPackage = packageName; info.installerPackageName = pkgSetting.installSource.installerPackageName; info.removedUsers = new int[] {userId}; info.broadcastUsers = new int[] {userId}; info.uid = UserHandle.getUid(userId, pkgSetting.appId); info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/); } private void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId, int distractionFlags) { final Bundle extras = new Bundle(3); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList); extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags); sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null, null, null); } @VisibleForTesting(visibility = Visibility.PRIVATE) void sendPackagesSuspendedForUser(String intent, String[] pkgList, int[] uidList, int userId) { final List> pkgsToSend = new ArrayList(pkgList.length); final List uidsToSend = new ArrayList(pkgList.length); final List> allowListsToSend = new ArrayList(pkgList.length); final int[] userIds = new int[] {userId}; // Get allow lists for the pkg in the pkgList. Merge into the existed pkgs and uids if // allow lists are the same. synchronized (mLock) { for (int i = 0; i < pkgList.length; i++) { final String pkgName = pkgList[i]; final int uid = uidList[i]; SparseArray allowList = mAppsFilter.getVisibilityAllowList( getPackageSettingInternal(pkgName, Process.SYSTEM_UID), userIds, mSettings.getPackagesLocked()); if (allowList == null) { allowList = new SparseArray<>(0); } boolean merged = false; for (int j = 0; j < allowListsToSend.size(); j++) { if (Arrays.equals(allowListsToSend.get(j).get(userId), allowList.get(userId))) { pkgsToSend.get(j).add(pkgName); uidsToSend.get(j).add(uid); merged = true; break; } } if (!merged) { pkgsToSend.add(new ArrayList<>(Arrays.asList(pkgName))); uidsToSend.add(IntArray.wrap(new int[] {uid})); allowListsToSend.add(allowList); } } } for (int i = 0; i < pkgsToSend.size(); i++) { final Bundle extras = new Bundle(3); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgsToSend.get(i).toArray(new String[pkgsToSend.get(i).size()])); extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray()); final SparseArray allowList = allowListsToSend.get(i).size() == 0 ? null : allowListsToSend.get(i); sendPackageBroadcast(intent, null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, userIds, null, allowList, null); } } /** * Returns true if application is not found or there was an error. Otherwise it returns * the hidden state of the package for the given user. */ @Override public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "getApplicationHidden for user " + userId); PackageSetting ps; final long callingId = Binder.clearCallingIdentity(); try { // writer synchronized (mLock) { ps = mSettings.getPackageLPr(packageName); if (ps == null) { return true; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return true; } return ps.getHidden(userId); } } finally { Binder.restoreCallingIdentity(callingId); } } /** * @hide */ @Override public int installExistingPackageAsUser(String packageName, int userId, int installFlags, int installReason, List whiteListedPermissions) { return installExistingPackageAsUser(packageName, userId, installFlags, installReason, whiteListedPermissions, null); } int installExistingPackageAsUser(@Nullable String packageName, @UserIdInt int userId, @PackageManager.InstallFlags int installFlags, @PackageManager.InstallReason int installReason, @Nullable List allowlistedRestrictedPermissions, @Nullable IntentSender intentSender) { if (DEBUG_INSTALL) { Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId + " installFlags=" + installFlags + " installReason=" + installReason + " allowlistedRestrictedPermissions=" + allowlistedRestrictedPermissions); } final int callingUid = Binder.getCallingUid(); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission( android.Manifest.permission.INSTALL_EXISTING_PACKAGES) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Neither user " + callingUid + " nor current process has " + android.Manifest.permission.INSTALL_PACKAGES + "."); } PackageSetting pkgSetting; enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "installExistingPackage for user " + userId); if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { return PackageManager.INSTALL_FAILED_USER_RESTRICTED; } final long callingId = Binder.clearCallingIdentity(); try { boolean installed = false; final boolean instantApp = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; final boolean fullApp = (installFlags & PackageManager.INSTALL_FULL_APP) != 0; // writer synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null) { return PackageManager.INSTALL_FAILED_INVALID_URI; } if (!canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) { // only allow the existing package to be used if it's installed as a full // application for at least one user boolean installAllowed = false; for (int checkUserId : mUserManager.getUserIds()) { installAllowed = !pkgSetting.getInstantApp(checkUserId); if (installAllowed) { break; } } if (!installAllowed) { return PackageManager.INSTALL_FAILED_INVALID_URI; } } if (!pkgSetting.getInstalled(userId)) { pkgSetting.setInstalled(true, userId); pkgSetting.setHidden(false, userId); pkgSetting.setInstallReason(installReason, userId); pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId); mSettings.writePackageRestrictionsLPr(userId); mSettings.writeKernelMappingLPr(pkgSetting); installed = true; } else if (fullApp && pkgSetting.getInstantApp(userId)) { // upgrade app from instant to full; we don't allow app downgrade installed = true; } setInstantAppForUser(mInjector, pkgSetting, userId, instantApp, fullApp); } if (installed) { if (pkgSetting.pkg != null) { final PermissionManagerServiceInternal.PackageInstalledParams.Builder permissionParamsBuilder = new PermissionManagerServiceInternal.PackageInstalledParams.Builder(); if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) { permissionParamsBuilder.setAllowlistedRestrictedPermissions( pkgSetting.pkg.getRequestedPermissions()); } mPermissionManager.onPackageInstalled(pkgSetting.pkg, permissionParamsBuilder.build(), userId); } if (pkgSetting.pkg != null) { synchronized (mInstallLock) { // We don't need to freeze for a brand new install prepareAppDataAfterInstallLIF(pkgSetting.pkg); } } sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE); synchronized (mLock) { updateSequenceNumberLP(pkgSetting, new int[]{ userId }); } // start async restore with no post-install since we finish install here PackageInstalledInfo res = createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED); res.pkg = pkgSetting.pkg; res.newUsers = new int[]{ userId }; PostInstallData postInstallData = new PostInstallData(null, res, () -> { restorePermissionsAndUpdateRolesForNewUserInstall(packageName, pkgSetting.getInstallReason(userId), userId); if (intentSender != null) { onRestoreComplete(res.returnCode, mContext, intentSender); } }); restoreAndPostInstall(userId, res, postInstallData); } } finally { Binder.restoreCallingIdentity(callingId); } return PackageManager.INSTALL_SUCCEEDED; } static void onRestoreComplete(int returnCode, Context context, IntentSender target) { Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageManager.installStatusToPublicStatus(returnCode)); try { target.sendIntent(context, 0, fillIn, null, null); } catch (SendIntentException ignored) { } } static void setInstantAppForUser(Injector injector, PackageSetting pkgSetting, int userId, boolean instantApp, boolean fullApp) { // no state specified; do nothing if (!instantApp && !fullApp) { return; } if (userId != UserHandle.USER_ALL) { if (instantApp && !pkgSetting.getInstantApp(userId)) { pkgSetting.setInstantApp(true /*instantApp*/, userId); } else if (fullApp && pkgSetting.getInstantApp(userId)) { pkgSetting.setInstantApp(false /*instantApp*/, userId); } } else { for (int currentUserId : injector.getUserManagerInternal().getUserIds()) { if (instantApp && !pkgSetting.getInstantApp(currentUserId)) { pkgSetting.setInstantApp(true /*instantApp*/, currentUserId); } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) { pkgSetting.setInstantApp(false /*instantApp*/, currentUserId); } } } } 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; } @Override public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames, int restrictionFlags, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, "setDistractingPackageRestrictionsAsUser"); final int callingUid = Binder.getCallingUid(); if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID && UserHandle.getUserId(callingUid) != userId) { throw new SecurityException("Calling uid " + callingUid + " cannot call for user " + userId); } Objects.requireNonNull(packageNames, "packageNames cannot be null"); if (restrictionFlags != 0 && !isSuspendAllowedForUser(userId)) { Slog.w(TAG, "Cannot restrict packages due to restrictions on user " + userId); return packageNames; } final List changedPackagesList = new ArrayList<>(packageNames.length); final IntArray changedUids = new IntArray(packageNames.length); final List unactionedPackages = new ArrayList<>(packageNames.length); final boolean[] canRestrict = (restrictionFlags != 0) ? canSuspendPackageForUserInternal( packageNames, userId) : null; for (int i = 0; i < packageNames.length; i++) { final String packageName = packageNames[i]; final PackageSetting pkgSetting; synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) { Slog.w(TAG, "Could not find package setting for package: " + packageName + ". Skipping..."); unactionedPackages.add(packageName); continue; } } if (canRestrict != null && !canRestrict[i]) { unactionedPackages.add(packageName); continue; } synchronized (mLock) { final int oldDistractionFlags = pkgSetting.getDistractionFlags(userId); if (restrictionFlags != oldDistractionFlags) { pkgSetting.setDistractionFlags(restrictionFlags, userId); changedPackagesList.add(packageName); changedUids.add(UserHandle.getUid(userId, pkgSetting.appId)); } } } if (!changedPackagesList.isEmpty()) { final String[] changedPackages = changedPackagesList.toArray( new String[changedPackagesList.size()]); sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId, restrictionFlags); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } return unactionedPackages.toArray(new String[0]); } private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid, int userId, 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(userId); if (ownerPackage != null) { final int ownerUid = getPackageUid(ownerPackage, 0, userId); if (ownerUid == callingUid) { return; } } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, callingMethod); final int packageUid = getPackageUid(callingPackage, 0, userId); 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("Calling package " + callingPackage + " in user " + userId + " does not belong to calling uid " + callingUid); } } @Override public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended, PersistableBundle appExtras, PersistableBundle launcherExtras, SuspendDialogInfo dialogInfo, String callingPackage, int userId) { final int callingUid = Binder.getCallingUid(); enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId, "setPackagesSuspendedAsUser"); if (ArrayUtils.isEmpty(packageNames)) { return packageNames; } if (suspended && !isSuspendAllowedForUser(userId)) { Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId); return packageNames; } final List changedPackagesList = new ArrayList<>(packageNames.length); final IntArray changedUids = new IntArray(packageNames.length); final List modifiedPackagesList = new ArrayList<>(packageNames.length); final IntArray modifiedUids = new IntArray(packageNames.length); final List unactionedPackages = new ArrayList<>(packageNames.length); final boolean[] canSuspend = suspended ? canSuspendPackageForUserInternal(packageNames, userId) : null; for (int i = 0; i < packageNames.length; i++) { final String packageName = packageNames[i]; if (callingPackage.equals(packageName)) { Slog.w(TAG, "Calling package: " + callingPackage + " trying to " + (suspended ? "" : "un") + "suspend itself. Ignoring"); unactionedPackages.add(packageName); continue; } final PackageSetting pkgSetting; synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) { Slog.w(TAG, "Could not find package setting for package: " + packageName + ". Skipping suspending/un-suspending."); unactionedPackages.add(packageName); continue; } } if (canSuspend != null && !canSuspend[i]) { unactionedPackages.add(packageName); continue; } final boolean packageUnsuspended; final boolean packageModified; synchronized (mLock) { if (suspended) { packageModified = pkgSetting.addOrUpdateSuspension(callingPackage, dialogInfo, appExtras, launcherExtras, userId); } else { packageModified = pkgSetting.removeSuspension(callingPackage, userId); } packageUnsuspended = !suspended && !pkgSetting.getSuspended(userId); } if (suspended || packageUnsuspended) { changedPackagesList.add(packageName); changedUids.add(UserHandle.getUid(userId, pkgSetting.appId)); } if (packageModified) { modifiedPackagesList.add(packageName); modifiedUids.add(UserHandle.getUid(userId, pkgSetting.appId)); } } if (!changedPackagesList.isEmpty()) { final String[] changedPackages = changedPackagesList.toArray(new String[0]); sendPackagesSuspendedForUser( suspended ? Intent.ACTION_PACKAGES_SUSPENDED : Intent.ACTION_PACKAGES_UNSUSPENDED, changedPackages, changedUids.toArray(), userId); sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } // Send the suspension changed broadcast to ensure suspension state is not stale. if (!modifiedPackagesList.isEmpty()) { sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, modifiedPackagesList.toArray(new String[0]), modifiedUids.toArray(), userId); } return unactionedPackages.toArray(new String[0]); } @Override public Bundle getSuspendedPackageAppExtras(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); if (getPackageUid(packageName, 0, userId) != callingUid) { throw new SecurityException("Calling package " + packageName + " does not belong to calling uid " + callingUid); } return getSuspendedPackageAppExtrasInternal(packageName, userId); } private Bundle getSuspendedPackageAppExtrasInternal(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { return null; } final PackageUserState pus = ps.readUserState(userId); final Bundle allExtras = new Bundle(); if (pus.suspended) { for (int i = 0; i < pus.suspendParams.size(); i++) { final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i); if (params != null && params.appExtras != null) { allExtras.putAll(params.appExtras); } } } return (allExtras.size() > 0) ? allExtras : null; } } private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended, int userId) { final String action = suspended ? Intent.ACTION_MY_PACKAGE_SUSPENDED : Intent.ACTION_MY_PACKAGE_UNSUSPENDED; mHandler.post(() -> { final IActivityManager am = ActivityManager.getService(); if (am == null) { Slog.wtf(TAG, "IActivityManager null. Cannot send MY_PACKAGE_ " + (suspended ? "" : "UN") + "SUSPENDED broadcasts"); return; } final int[] targetUserIds = new int[] {userId}; for (String packageName : affectedPackages) { final Bundle appExtras = suspended ? getSuspendedPackageAppExtrasInternal(packageName, userId) : null; final Bundle intentExtras; if (appExtras != null) { intentExtras = new Bundle(1); intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, appExtras); } else { intentExtras = null; } doSendBroadcast(am, action, null, intentExtras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null, targetUserIds, false, null, null); } }); } @Override public boolean isPackageSuspendedForUser(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "isPackageSuspendedForUser for user " + userId); synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) { throw new IllegalArgumentException("Unknown target package: " + packageName); } return ps.getSuspended(userId); } } void unsuspendForSuspendingPackage(String suspendingPackage, int userId) { final String[] allPackages; synchronized (mLock) { allPackages = mPackages.keySet().toArray(new String[mPackages.size()]); } removeSuspensionsBySuspendingPackage(allPackages, suspendingPackage::equals, userId); } boolean isSuspendingAnyPackages(String suspendingPackage, int userId) { synchronized (mLock) { for (final PackageSetting ps : mSettings.getPackagesLocked().values()) { if (ps.isSuspendedBy(suspendingPackage, userId)) { return true; } } } return false; } /** * Removes any suspensions on given packages that were added by packages that pass the given * predicate. * *

    Caller must flush package restrictions if it cares about immediate data consistency. * * @param packagesToChange The packages on which the suspension are to be removed. * @param suspendingPackagePredicate A predicate identifying the suspending packages whose * suspensions will be removed. * @param userId The user for which the changes are taking place. */ void removeSuspensionsBySuspendingPackage(String[] packagesToChange, Predicate suspendingPackagePredicate, int userId) { final List unsuspendedPackages = new ArrayList<>(); final IntArray unsuspendedUids = new IntArray(); synchronized (mLock) { for (String packageName : packagesToChange) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && ps.getSuspended(userId)) { ps.removeSuspension(suspendingPackagePredicate, userId); if (!ps.getSuspended(userId)) { unsuspendedPackages.add(ps.name); unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId())); } } } scheduleWritePackageRestrictionsLocked(userId); } if (!unsuspendedPackages.isEmpty()) { final String[] packageArray = unsuspendedPackages.toArray( new String[unsuspendedPackages.size()]); sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId); sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED, packageArray, unsuspendedUids.toArray(), userId); } } void removeAllDistractingPackageRestrictions(int userId) { final String[] allPackages; synchronized (mLock) { allPackages = mPackages.keySet().toArray(new String[mPackages.size()]); } removeDistractingPackageRestrictions(allPackages, userId); } /** * Removes any {@link android.content.pm.PackageManager.DistractionRestriction restrictions} * set on given packages. * *

    Caller must flush package restrictions if it cares about immediate data consistency. * * @param packagesToChange The packages on which restrictions are to be removed. * @param userId the user for which changes are taking place. */ void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) { final List changedPackages = new ArrayList<>(); final IntArray changedUids = new IntArray(); synchronized (mLock) { for (String packageName : packagesToChange) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && ps.getDistractionFlags(userId) != 0) { ps.setDistractionFlags(0, userId); changedPackages.add(ps.name); changedUids.add(UserHandle.getUid(userId, ps.getAppId())); } } if (!changedPackages.isEmpty()) { final String[] packageArray = changedPackages.toArray( new String[changedPackages.size()]); sendDistractingPackagesChanged(packageArray, changedUids.toArray(), userId, 0); scheduleWritePackageRestrictionsLocked(userId); } } } private boolean isCallerDeviceOrProfileOwner(int userId) { final int callingUid = Binder.getCallingUid(); if (callingUid == Process.SYSTEM_UID) { return true; } final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId); if (ownerPackage != null) { return callingUid == getPackageUidInternal(ownerPackage, 0, userId, callingUid); } return false; } private boolean isSuspendAllowedForUser(int userId) { return isCallerDeviceOrProfileOwner(userId) || (!mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId) && !mUserManager.hasUserRestriction(UserManager.DISALLOW_UNINSTALL_APPS, userId)); } @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) { throw new SecurityException("Calling uid " + callingUid + " cannot query getUnsuspendablePackagesForUser for user " + userId); } if (!isSuspendAllowedForUser(userId)) { Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId); return packageNames; } final ArraySet unactionablePackages = new ArraySet<>(); final boolean[] canSuspend = canSuspendPackageForUserInternal(packageNames, userId); for (int i = 0; i < packageNames.length; i++) { if (!canSuspend[i]) { unactionablePackages.add(packageNames[i]); continue; } synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageNames[i]); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) { Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]); unactionablePackages.add(packageNames[i]); } } } return unactionablePackages.toArray(new String[unactionablePackages.size()]); } /** * Returns an array of booleans, such that the ith boolean denotes whether the ith package can * be suspended or not. * * @param packageNames The package names to check suspendability for. * @param userId The user to check in * @return An array containing results of the checks */ @NonNull private boolean[] canSuspendPackageForUserInternal(@NonNull String[] packageNames, int userId) { final boolean[] canSuspend = new boolean[packageNames.length]; final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId); final long callingId = Binder.clearCallingIdentity(); try { final String activeLauncherPackageName = mDefaultAppProvider.getDefaultHome(userId); final String dialerPackageName = mDefaultAppProvider.getDefaultDialer(userId); for (int i = 0; i < packageNames.length; i++) { canSuspend[i] = false; final String packageName = packageNames[i]; if (isPackageDeviceAdmin(packageName, userId)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": has an active device admin"); continue; } if (packageName.equals(activeLauncherPackageName)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": contains the active launcher"); continue; } if (packageName.equals(mRequiredInstallerPackage)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package installation"); continue; } if (packageName.equals(mRequiredUninstallerPackage)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package uninstallation"); continue; } if (packageName.equals(mRequiredVerifierPackage)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for package verification"); continue; } if (packageName.equals(dialerPackageName)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": is the default dialer"); continue; } if (packageName.equals(mRequiredPermissionControllerPackage)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": required for permissions management"); continue; } synchronized (mLock) { if (mProtectedPackages.isPackageStateProtected(userId, packageName)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": protected package"); continue; } if (!isCallerOwner && mSettings.getBlockUninstallLPr(userId, packageName)) { Slog.w(TAG, "Cannot suspend package \"" + packageName + "\": blocked by admin"); continue; } // Cannot suspend 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 = mPackages.get(packageName); if (pkg != null && pkg.isStaticSharedLibrary()) { Slog.w(TAG, "Cannot suspend package: " + packageName + " providing static shared library: " + pkg.getStaticSharedLibName()); continue; } } if (PLATFORM_PACKAGE_NAME.equals(packageName)) { Slog.w(TAG, "Cannot suspend the platform package: " + packageName); continue; } canSuspend[i] = true; } } finally { Binder.restoreCallingIdentity(callingId); } return canSuspend; } @Override public void verifyPendingInstall(int id, int verificationCode) throws RemoteException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, "Only package verification agents can verify applications"); final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); final PackageVerificationResponse response = new PackageVerificationResponse( verificationCode, Binder.getCallingUid()); msg.arg1 = id; msg.obj = response; mHandler.sendMessage(msg); } @Override public void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, "Only package verification agents can extend verification timeouts"); final PackageVerificationState state = mPendingVerification.get(id); final PackageVerificationResponse response = new PackageVerificationResponse( verificationCodeAtTimeout, Binder.getCallingUid()); if (millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) { millisecondsToDelay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT; } if (millisecondsToDelay < 0) { millisecondsToDelay = 0; } if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW) && (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) { verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT; } if ((state != null) && !state.timeoutExtended()) { state.extendTimeout(); final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); msg.arg1 = id; msg.obj = response; mHandler.sendMessageDelayed(msg, millisecondsToDelay); } } private void broadcastPackageVerified(int verificationId, Uri packageUri, int verificationCode, @Nullable String rootHashString, int dataLoaderType, UserHandle user) { final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED); intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode); if (rootHashString != null) { intent.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString); } intent.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType); mContext.sendBroadcastAsUser(intent, user, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT); } private ComponentName matchComponentForVerifier(String packageName, List receivers) { ActivityInfo targetReceiver = null; final int NR = receivers.size(); for (int i = 0; i < NR; i++) { final ResolveInfo info = receivers.get(i); if (info.activityInfo == null) { continue; } if (packageName.equals(info.activityInfo.packageName)) { targetReceiver = info.activityInfo; break; } } if (targetReceiver == null) { return null; } return new ComponentName(targetReceiver.packageName, targetReceiver.name); } private List matchVerifiers(PackageInfoLite pkgInfo, List receivers, final PackageVerificationState verificationState) { if (pkgInfo.verifiers.length == 0) { return null; } final int N = pkgInfo.verifiers.length; final List sufficientVerifiers = new ArrayList<>(N + 1); for (int i = 0; i < N; i++) { final VerifierInfo verifierInfo = pkgInfo.verifiers[i]; final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName, receivers); if (comp == null) { continue; } final int verifierUid = getUidForVerifier(verifierInfo); if (verifierUid == -1) { continue; } if (DEBUG_VERIFY) { Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName + " with the correct signature"); } sufficientVerifiers.add(comp); verificationState.addSufficientVerifier(verifierUid); } return sufficientVerifiers; } private int getUidForVerifier(VerifierInfo verifierInfo) { synchronized (mLock) { final AndroidPackage pkg = mPackages.get(verifierInfo.packageName); if (pkg == null) { return -1; } else if (pkg.getSigningDetails().signatures.length != 1) { Slog.i(TAG, "Verifier package " + verifierInfo.packageName + " has more than one signature; ignoring"); return -1; } /* * If the public key of the package's signature does not match * our expected public key, then this is a different package and * we should skip. */ final byte[] expectedPublicKey; try { final Signature verifierSig = pkg.getSigningDetails().signatures[0]; final PublicKey publicKey = verifierSig.getPublicKey(); expectedPublicKey = publicKey.getEncoded(); } catch (CertificateException e) { return -1; } final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded(); if (!Arrays.equals(actualPublicKey, expectedPublicKey)) { Slog.i(TAG, "Verifier package " + verifierInfo.packageName + " does not have the expected public key; ignoring"); return -1; } return pkg.getUid(); } } private void setEnableRollbackCode(int token, int enableRollbackCode) { final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS); msg.arg1 = token; msg.arg2 = enableRollbackCode; mHandler.sendMessage(msg); } @Override public void finishPackageInstall(int token, boolean didLaunch) { enforceSystemOrRoot("Only the system is allowed to finish installs"); if (DEBUG_INSTALL) { Slog.v(TAG, "BM finishing package install for " + token); } Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token); final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0); mHandler.sendMessage(msg); } /** * Get the verification agent timeout. Used for both the APK verifier and the * intent filter verifier. * * @return verification timeout in milliseconds */ private long getVerificationTimeout() { long timeout = Global.getLong(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT); // The setting can be used to increase the timeout but not decrease it, since that is // equivalent to disabling the verifier. return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT); } /** * Get the integrity verification timeout. * * @return verification timeout in milliseconds */ private long getIntegrityVerificationTimeout() { long timeout = Global.getLong(mContext.getContentResolver(), Global.APP_INTEGRITY_VERIFICATION_TIMEOUT, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT); // The setting can be used to increase the timeout but not decrease it, since that is // equivalent to disabling the integrity component. return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT); } /** * Get the default verification agent response code. * * @return default verification response code */ private int getDefaultVerificationResponse(UserHandle user) { if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) { return PackageManager.VERIFICATION_REJECT; } return android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE, DEFAULT_VERIFICATION_RESPONSE); } /** * Get the default integrity verification response code. */ private int getDefaultIntegrityVerificationResponse() { // We are not exposing this as a user-configurable setting because we don't want to provide // an easy way to get around the integrity check. return PackageManager.VERIFICATION_REJECT; } /** * Check whether or not package verification has been enabled. * * @return true if verification should be performed */ private boolean isVerificationEnabled( PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) { if (!DEFAULT_VERIFY_ENABLE) { return false; } // Check if installing from ADB if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) { if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) { return true; } // Check if the developer wants to skip verification for ADB installs if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) { synchronized (mLock) { if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) { // Always verify fresh install return true; } } // Only skip when apk is debuggable return !pkgInfoLite.debuggable; } return Global.getInt(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0; } // only when not installed from ADB, skip verification for instant apps when // the installer and verifier are the same. if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { if (mInstantAppInstallerActivity != null && mInstantAppInstallerActivity.packageName.equals( mRequiredVerifierPackage)) { try { mInjector.getSystemService(AppOpsManager.class) .checkPackage(installerUid, mRequiredVerifierPackage); if (DEBUG_VERIFY) { Slog.i(TAG, "disable verification for instant app"); } return false; } catch (SecurityException ignore) { } } } return true; } /** * Check whether or not integrity verification has been enabled. */ private boolean isIntegrityVerificationEnabled() { // We are not exposing this as a user-configurable setting because we don't want to provide // an easy way to get around the integrity check. return DEFAULT_INTEGRITY_VERIFY_ENABLE; } @Deprecated @Override public void verifyIntentFilter(int id, int verificationCode, List failedDomains) { DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection, id, verificationCode, failedDomains, Binder.getCallingUid()); } @Deprecated @Override public int getIntentVerificationStatus(String packageName, int userId) { return mDomainVerificationManager.getLegacyState(packageName, userId); } @Deprecated @Override public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { return mDomainVerificationManager.setLegacyUserState(packageName, userId, status); } @Deprecated @Override public @NonNull ParceledListSlice getIntentFilterVerifications( String packageName) { return ParceledListSlice.emptyList(); } @Override public @NonNull ParceledListSlice getAllIntentFilters(String packageName) { if (TextUtils.isEmpty(packageName)) { return ParceledListSlice.emptyList(); } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) { return ParceledListSlice.emptyList(); } final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps == null) { return ParceledListSlice.emptyList(); } if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } final int count = ArrayUtils.size(pkg.getActivities()); ArrayList result = new ArrayList<>(); for (int n=0; n 0) { result.addAll(activity.getIntents()); } } return new ParceledListSlice(result) { @Override protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) { parcelable.writeToParcel(dest, callFlags); } @Override protected void writeParcelableCreator(IntentFilter parcelable, Parcel dest) { // All Parcel#writeParcelableCreator does is serialize the class name to // access via reflection to grab its CREATOR. This does that manually, pointing // to the parent IntentFilter so that all of the subclass fields are ignored. dest.writeString(IntentFilter.class.getName()); } }; } } /** * Get the "allow unknown sources" setting. * * @return the current "allow unknown sources" setting */ private int getUnknownSourcesSettings() { return android.provider.Settings.Secure.getInt(mContext.getContentResolver(), android.provider.Settings.Secure.INSTALL_NON_MARKET_APPS, -1); } @Override public void setInstallerPackageName(String targetPackage, String installerPackageName) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); if (getInstantAppPackageName(callingUid) != null) { return; } // writer synchronized (mLock) { PackageSetting targetPackageSetting = mSettings.getPackageLPr(targetPackage); if (targetPackageSetting == null || shouldFilterApplicationLocked( targetPackageSetting, callingUid, callingUserId)) { throw new IllegalArgumentException("Unknown target package: " + targetPackage); } PackageSetting installerPackageSetting; if (installerPackageName != null) { installerPackageSetting = mSettings.getPackageLPr(installerPackageName); if (installerPackageSetting == null || shouldFilterApplicationLocked( installerPackageSetting, callingUid, callingUserId)) { throw new IllegalArgumentException("Unknown installer package: " + installerPackageName); } } else { installerPackageSetting = null; } Signature[] callerSignature; final int appId = UserHandle.getAppId(callingUid); final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { callerSignature = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures; } else { throw new SecurityException("Bad object " + obj + " for uid " + callingUid); } } 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 (installerPackageSetting != null) { if (compareSignatures(callerSignature, installerPackageSetting.signatures.mSigningDetails.signatures) != 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 = targetPackageSetting.installSource.installerPackageName; PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null : mSettings.getPackageLPr(targetInstallerPackageName); if (targetInstallerPkgSetting != null) { if (compareSignatures(callerSignature, targetInstallerPkgSetting.signatures.mSigningDetails.signatures) != 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) != PackageManager.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( 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; } } finally { Binder.restoreCallingIdentity(binderToken); } } // Okay! targetPackageSetting.setInstallerPackageName(installerPackageName); mSettings.addInstallerPackageNames(targetPackageSetting.installSource); mAppsFilter.addPackage(targetPackageSetting); scheduleWriteSettingsLocked(); } } @Override public void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { throw new SecurityException("Instant applications don't have access to this method"); } mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), callerPackageName); synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null || shouldFilterApplicationLocked( ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) { throw new IllegalArgumentException("Unknown target package " + packageName); } if (!Objects.equals(callerPackageName, ps.installSource.installerPackageName)) { throw new IllegalArgumentException("Calling package " + callerPackageName + " is not installer for " + packageName); } if (ps.categoryHint != categoryHint) { ps.categoryHint = categoryHint; scheduleWriteSettingsLocked(); } } } // Queue up an async operation since the package installation may take a little while. private void processInstallRequestsAsync(boolean success, List installRequests) { mHandler.post(() -> { List apexInstallRequests = new ArrayList<>(); List apkInstallRequests = new ArrayList<>(); for (InstallRequest request : installRequests) { if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) { apexInstallRequests.add(request); } else { apkInstallRequests.add(request); } } // Note: supporting multi package install of both APEXes and APKs might requir some // thinking to ensure atomicity of the install. if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { // This should've been caught at the validation step, but for some reason wasn't. throw new IllegalStateException( "Attempted to do a multi package install of both APEXes and APKs"); } if (!apexInstallRequests.isEmpty()) { if (success) { // Since installApexPackages requires talking to external service (apexd), we // schedule to run it async. Once it finishes, it will resume the install. Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), "installApexPackages"); t.start(); } else { // Non-staged APEX installation failed somewhere before // processInstallRequestAsync. In that case just notify the observer about the // failure. InstallRequest request = apexInstallRequests.get(0); notifyInstallObserver(request.installResult, request.args.observer); } return; } if (success) { for (InstallRequest request : apkInstallRequests) { request.args.doPreInstall(request.installResult.returnCode); } synchronized (mInstallLock) { installPackagesTracedLI(apkInstallRequests); } for (InstallRequest request : apkInstallRequests) { request.args.doPostInstall( request.installResult.returnCode, request.installResult.uid); } } for (InstallRequest request : apkInstallRequests) { restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult, new PostInstallData(request.args, request.installResult, null)); } }); } private void installApexPackagesTraced(List requests) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages"); installApexPackages(requests); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void installApexPackages(List requests) { if (requests.isEmpty()) { return; } if (requests.size() != 1) { throw new IllegalStateException( "Only a non-staged install of a single APEX is supported"); } InstallRequest request = requests.get(0); try { // Should directory scanning logic be moved to ApexManager for better test coverage? final File dir = request.args.origin.resolvedFile; final File[] apexes = dir.listFiles(); if (apexes == null) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, dir.getAbsolutePath() + " is not a directory"); } if (apexes.length != 1) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Expected exactly one .apex file under " + dir.getAbsolutePath() + " got: " + apexes.length); } try (PackageParser2 packageParser = mInjector.getScanningPackageParser()) { mApexManager.installPackage(apexes[0], packageParser); } } catch (PackageManagerException e) { request.installResult.setError("APEX installation failed", e); } invalidatePackageInfoCache(); notifyInstallObserver(request.installResult, request.args.observer); } private PackageInstalledInfo createPackageInstalledInfo( int currentStatus) { PackageInstalledInfo res = new PackageInstalledInfo(); res.setReturnCode(currentStatus); res.uid = -1; res.pkg = null; res.removedInfo = null; return res; } /** @param data Post-install is performed only if this is non-null. */ private void restoreAndPostInstall( int userId, PackageInstalledInfo res, @Nullable PostInstallData data) { if (DEBUG_INSTALL) { Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg); } // A restore should be requested at this point if (a) the install // succeeded, (b) the operation is not an update. final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; boolean doRestore = !update && res.pkg != null; // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether // there's a restore pass performed. Token values are >= 1. int token; if (mNextInstallToken < 0) mNextInstallToken = 1; token = mNextInstallToken++; if (data != null) { mRunningInstalls.put(token, data); } else if (DEBUG_INSTALL) { Log.v(TAG, "No post-install required for " + token); } if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { // Pass responsibility to the Backup Manager. It will perform a // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks // and broadcasts. if (res.freezer != null) { res.freezer.close(); } doRestore = performBackupManagerRestore(userId, token, res); } // If this is an update to a package that might be potentially downgraded, then we // need to check with the rollback manager whether there's any userdata that might // need to be snapshotted or restored for the package. // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { doRestore = performRollbackManagerRestore(userId, token, res, data); } if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token); Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } } /** * Perform Backup Manager restore for a given {@link PackageInstalledInfo}. * Returns whether the restore successfully completed. */ private boolean performBackupManagerRestore(int userId, int token, PackageInstalledInfo res) { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); if (bm != null) { // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM // in the BackupManager. USER_ALL is used in compatibility tests. if (userId == UserHandle.USER_ALL) { userId = UserHandle.USER_SYSTEM; } if (DEBUG_INSTALL) { Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId); } Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token); try { if (bm.isUserReadyForBackup(userId)) { bm.restoreAtInstallForUser( userId, res.pkg.getPackageName(), token); } else { Slog.w(TAG, "User " + userId + " is not ready. Restore at install " + "didn't take place."); return false; } } catch (RemoteException e) { // can't happen; the backup manager is local } catch (Exception e) { Slog.e(TAG, "Exception trying to enqueue restore", e); return false; } } else { Slog.e(TAG, "Backup Manager not found!"); return false; } return true; } /** * Perform Rollback Manager restore for a given {@link PackageInstalledInfo}. * Returns whether the restore successfully completed. */ private boolean performRollbackManagerRestore(int userId, int token, PackageInstalledInfo res, PostInstallData data) { RollbackManagerInternal rm = mInjector.getLocalService(RollbackManagerInternal.class); final String packageName = res.pkg.getPackageName(); final int[] allUsers = mUserManager.getUserIds(); final int[] installedUsers; final PackageSetting ps; int appId = -1; long ceDataInode = -1; synchronized (mLock) { ps = mSettings.getPackageLPr(packageName); if (ps != null) { appId = ps.appId; ceDataInode = ps.getCeDataInode(userId); } // NOTE: We ignore the user specified in the InstallParam because we know this is // an update, and hence need to restore data for all installed users. installedUsers = ps.queryInstalledUsers(allUsers, true); } boolean doSnapshotOrRestore = data != null && data.args != null && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0 || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); if (ps != null && doSnapshotOrRestore) { final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps); rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers), appId, ceDataInode, seInfo, token); return true; } return false; } /** * 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 PostInstallData data = mRunningInstalls.valueAt(i); if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) { continue; } if (packageName.equals(data.res.pkg.getPackageName())) { // right package; but is it for the right user? for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { if (userId == data.res.newUsers[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 = isInstantApp(packageName, userId); final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId }; final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; sendFirstLaunchBroadcast(packageName, installerPackage, userIds, instantUserIds); }); } private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds, int[] instantUserIds) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0, installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null); } private abstract class HandlerParams { /** User handle for the user requesting the information or installation. */ private final UserHandle mUser; String traceMethod; int traceCookie; HandlerParams(UserHandle user) { mUser = user; } UserHandle getUser() { return mUser; } HandlerParams setTraceMethod(String traceMethod) { this.traceMethod = traceMethod; return this; } HandlerParams setTraceCookie(int traceCookie) { this.traceCookie = traceCookie; return this; } final void startCopy() { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy(); handleReturnCode(); } abstract void handleStartCopy(); abstract void handleReturnCode(); } static class OriginInfo { /** * Location where install is coming from, before it has been * copied/renamed into place. This could be a single monolithic APK * file, or a cluster directory. This location may be untrusted. */ final File file; /** * Flag indicating that {@link #file} has already been staged, meaning downstream users * don't need to defensively copy the contents. */ final boolean staged; /** * Flag indicating that {@link #file} is an already installed app that is being moved. */ final boolean existing; final String resolvedPath; final File resolvedFile; static OriginInfo fromNothing() { return new OriginInfo(null, false, false); } static OriginInfo fromUntrustedFile(File file) { return new OriginInfo(file, false, false); } static OriginInfo fromExistingFile(File file) { return new OriginInfo(file, false, true); } static OriginInfo fromStagedFile(File file) { return new OriginInfo(file, true, false); } private OriginInfo(File file, boolean staged, boolean existing) { this.file = file; this.staged = staged; this.existing = existing; if (file != null) { resolvedPath = file.getAbsolutePath(); resolvedFile = file; } else { resolvedPath = null; resolvedFile = null; } } } static class MoveInfo { final int moveId; final String fromUuid; final String toUuid; final String packageName; final int appId; final String seinfo; final int targetSdkVersion; final String fromCodePath; public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName, int appId, String seinfo, int targetSdkVersion, String fromCodePath) { this.moveId = moveId; this.fromUuid = fromUuid; this.toUuid = toUuid; this.packageName = packageName; this.appId = appId; this.seinfo = seinfo; this.targetSdkVersion = targetSdkVersion; this.fromCodePath = fromCodePath; } } static class VerificationInfo { /** A constant used to indicate that a uid value is not present. */ public static final int NO_UID = -1; /** URI referencing where the package was downloaded from. */ final Uri originatingUri; /** HTTP referrer URI associated with the originatingURI. */ final Uri referrer; /** UID of the application that the install request originated from. */ final int originatingUid; /** UID of application requesting the install */ final int installerUid; VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) { this.originatingUri = originatingUri; this.referrer = referrer; this.originatingUid = originatingUid; this.installerUid = installerUid; } } /** * Container for a multi-package install which refers to all install sessions and args being * committed together. */ class MultiPackageInstallParams extends HandlerParams { private final List mChildParams; private final Map mCurrentState; MultiPackageInstallParams(InstallParams parent, List childParams) throws PackageManagerException { super(parent.getUser()); if (childParams.size() == 0) { throw new PackageManagerException("No child sessions found!"); } mChildParams = childParams; for (int i = 0; i < childParams.size(); i++) { final InstallParams childParam = childParams.get(i); childParam.mParentInstallParams = this; } this.mCurrentState = new ArrayMap<>(mChildParams.size()); } @Override void handleStartCopy() { for (InstallParams params : mChildParams) { params.handleStartCopy(); } } @Override void handleReturnCode() { for (InstallParams params : mChildParams) { params.handleReturnCode(); } } void tryProcessInstallRequest(InstallArgs args, int currentStatus) { mCurrentState.put(args, currentStatus); if (mCurrentState.size() != mChildParams.size()) { return; } int completeStatus = PackageManager.INSTALL_SUCCEEDED; for (Integer status : mCurrentState.values()) { if (status == PackageManager.INSTALL_UNKNOWN) { return; } else if (status != PackageManager.INSTALL_SUCCEEDED) { completeStatus = status; break; } } final List installRequests = new ArrayList<>(mCurrentState.size()); for (Map.Entry entry : mCurrentState.entrySet()) { installRequests.add(new InstallRequest(entry.getKey(), createPackageInstalledInfo(completeStatus))); } processInstallRequestsAsync( completeStatus == PackageManager.INSTALL_SUCCEEDED, installRequests); } } class InstallParams extends HandlerParams { final OriginInfo origin; final MoveInfo move; final IPackageInstallObserver2 observer; int installFlags; @NonNull final InstallSource installSource; final String volumeUuid; int mRet; final String packageAbiOverride; final String[] grantedRuntimePermissions; final List whitelistedRestrictedPermissions; final int autoRevokePermissionsMode; final PackageParser.SigningDetails signingDetails; final int installReason; final int mInstallScenario; @Nullable MultiPackageInstallParams mParentInstallParams; final boolean forceQueryableOverride; final int mDataLoaderType; final long requiredInstalledVersionCode; final PackageLite mPackageLite; InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, int installFlags, InstallSource installSource, String volumeUuid, UserHandle user, String packageAbiOverride, PackageLite packageLite) { super(user); this.origin = origin; this.move = move; this.observer = observer; this.installFlags = installFlags; this.installSource = Preconditions.checkNotNull(installSource); this.volumeUuid = volumeUuid; this.packageAbiOverride = packageAbiOverride; this.grantedRuntimePermissions = null; this.whitelistedRestrictedPermissions = null; this.autoRevokePermissionsMode = MODE_DEFAULT; this.signingDetails = PackageParser.SigningDetails.UNKNOWN; this.installReason = PackageManager.INSTALL_REASON_UNKNOWN; this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; this.forceQueryableOverride = false; this.mDataLoaderType = DataLoaderType.NONE; this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST; this.mPackageLite = packageLite; } InstallParams(File stagedDir, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, InstallSource installSource, UserHandle user, SigningDetails signingDetails, int installerUid, PackageLite packageLite) { super(user); origin = OriginInfo.fromStagedFile(stagedDir); move = null; installReason = fixUpInstallReason( installSource.installerPackageName, installerUid, sessionParams.installReason); mInstallScenario = sessionParams.installScenario; this.observer = observer; installFlags = sessionParams.installFlags; this.installSource = installSource; volumeUuid = sessionParams.volumeUuid; packageAbiOverride = sessionParams.abiOverride; grantedRuntimePermissions = sessionParams.grantedRuntimePermissions; whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions; autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode; this.signingDetails = signingDetails; forceQueryableOverride = sessionParams.forceQueryableOverride; mDataLoaderType = (sessionParams.dataLoaderParams != null) ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; mPackageLite = packageLite; } @Override public String toString() { return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) + " file=" + origin.file + "}"; } private int installLocationPolicy(PackageInfoLite pkgLite) { String packageName = pkgLite.packageName; int installLocation = pkgLite.installLocation; // reader synchronized (mLock) { // Currently installed package which the new package is attempting to replace or // null if no such package is installed. AndroidPackage installedPkg = mPackages.get(packageName); if (installedPkg != null) { if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // Check for updated system application. if (installedPkg.isSystem()) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else { // If current upgrade specifies particular preference if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { // Application explicitly specified internal. return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { // App explictly prefers external. Let policy decide } else { // Prefer previous location if (installedPkg.isExternalStorage()) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } } } else { // Invalid install. Return error code return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS; } } } return pkgLite.recommendedInstallLocation; } /** * Override install location based on default policy if needed. * * Only {@link #installFlags} may mutate in this method. * * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in * {@link #installFlags} */ private int overrideInstallLocation(PackageInfoLite pkgLite) { final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; if (DEBUG_INSTANT && ephemeral) { Slog.v(TAG, "pkgLite for install: " + pkgLite); } if (origin.staged) { // If we're already staged, we've firmly committed to an install location if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } else if (pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { /* * If we are not staged and have too little free space, try to free cache * before giving up. */ // TODO: focus freeing disk space on the target device final StorageManager storage = StorageManager.from(mContext); final long lowThreshold = storage.getStorageLowBytes( Environment.getDataDirectory()); final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( origin.resolvedPath, packageAbiOverride); if (sizeBytes >= 0) { try { mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride); } catch (InstallerException e) { Slog.w(TAG, "Failed to free cache", e); } } /* * The cache free must have deleted the file we downloaded to install. * * TODO: fix the "freeCache" call to not delete the file we care about. */ if (pkgLite.recommendedInstallLocation == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { pkgLite.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } int ret = INSTALL_SUCCEEDED; int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { ret = PackageManager.INSTALL_FAILED_INVALID_APK; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { ret = PackageManager.INSTALL_FAILED_INVALID_URI; } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; } else { // Override with defaults if needed. loc = installLocationPolicy(pkgLite); final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; if (!onInt) { // Override install location with flags if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { // Set the flag to install on external media. installFlags &= ~PackageManager.INSTALL_INTERNAL; } else { // Make sure the flag for installing on external // media is unset installFlags |= PackageManager.INSTALL_INTERNAL; } } } return ret; } /* * Invoke remote method to get package information and install * location values. Override install location based on default * policy if needed and then create install arguments based * on the install location. */ public void handleStartCopy() { if ((installFlags & PackageManager.INSTALL_APEX) != 0) { mRet = INSTALL_SUCCEEDED; return; } PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride); // For staged session, there is a delay between its verification and install. Device // state can change within this delay and hence we need to re-verify certain conditions. boolean isStaged = (installFlags & INSTALL_STAGED) != 0; if (isStaged) { mRet = verifyReplacingVersionCode( pkgLite, requiredInstalledVersionCode, installFlags); if (mRet != INSTALL_SUCCEEDED) { return; } } mRet = overrideInstallLocation(pkgLite); } @Override void handleReturnCode() { processPendingInstall(); } private void processPendingInstall() { InstallArgs args = createInstallArgs(this); if (mRet == PackageManager.INSTALL_SUCCEEDED) { mRet = args.copyApk(); } if (mRet == PackageManager.INSTALL_SUCCEEDED) { F2fsUtils.releaseCompressedBlocks( mContext.getContentResolver(), new File(args.getCodePath())); } if (mParentInstallParams != null) { mParentInstallParams.tryProcessInstallRequest(args, mRet); } else { PackageInstalledInfo res = createPackageInstalledInfo(mRet); processInstallRequestsAsync( res.returnCode == PackageManager.INSTALL_SUCCEEDED, Collections.singletonList(new InstallRequest(args, res))); } } } /** * Container for a multi-package install which refers to all install sessions and args being * committed together. */ class MultiPackageVerificationParams extends HandlerParams { private final IPackageInstallObserver2 mObserver; private final List mChildParams; private final Map mVerificationState; MultiPackageVerificationParams( VerificationParams parent, List children) throws PackageManagerException { super(parent.getUser()); if (children.size() == 0) { throw new PackageManagerException("No child sessions found!"); } mChildParams = children; // Provide every child with reference to this object as parent for (int i = 0; i < children.size(); i++) { final VerificationParams childParams = children.get(i); childParams.mParentVerificationParams = this; } this.mVerificationState = new ArrayMap<>(mChildParams.size()); mObserver = parent.observer; } @Override void handleStartCopy() { for (VerificationParams params : mChildParams) { params.handleStartCopy(); } } @Override void handleReturnCode() { for (VerificationParams params : mChildParams) { params.handleReturnCode(); } } void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) { mVerificationState.put(child, currentStatus); if (mVerificationState.size() != mChildParams.size()) { return; } int completeStatus = PackageManager.INSTALL_SUCCEEDED; for (Integer status : mVerificationState.values()) { if (status == PackageManager.INSTALL_UNKNOWN) { return; } else if (status != PackageManager.INSTALL_SUCCEEDED) { completeStatus = status; break; } } try { mObserver.onPackageInstalled(null, completeStatus, "Package Verification Result", new Bundle()); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } class VerificationParams extends HandlerParams { final OriginInfo origin; final IPackageInstallObserver2 observer; final int installFlags; @NonNull final InstallSource installSource; final String packageAbiOverride; final VerificationInfo verificationInfo; final PackageParser.SigningDetails signingDetails; @Nullable MultiPackageVerificationParams mParentVerificationParams; final long requiredInstalledVersionCode; final int mDataLoaderType; final int mSessionId; private boolean mWaitForVerificationToComplete; private boolean mWaitForIntegrityVerificationToComplete; private boolean mWaitForEnableRollbackToComplete; private int mRet; final PackageLite mPackageLite; VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, InstallSource installSource, int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite) { super(user); origin = OriginInfo.fromStagedFile(stagedDir); this.observer = observer; installFlags = sessionParams.installFlags; this.installSource = installSource; packageAbiOverride = sessionParams.abiOverride; verificationInfo = new VerificationInfo( sessionParams.originatingUri, sessionParams.referrerUri, sessionParams.originatingUid, installerUid ); this.signingDetails = signingDetails; requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; mDataLoaderType = (sessionParams.dataLoaderParams != null) ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; mSessionId = sessionId; mPackageLite = lite; } @Override public String toString() { return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) + " file=" + origin.file + "}"; } public void handleStartCopy() { if ((installFlags & PackageManager.INSTALL_APEX) != 0) { // Apex packages get verified in StagingManager currently. // TODO(b/136257624): Move apex verification logic out of StagingManager mRet = INSTALL_SUCCEEDED; return; } PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride); mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags); if (mRet != INSTALL_SUCCEEDED) { return; } // Perform package verification and enable rollback (unless we are simply moving the // package). if (!origin.existing) { sendApkVerificationRequest(pkgLite); if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { sendEnableRollbackRequest(); } } } void sendApkVerificationRequest(PackageInfoLite pkgLite) { final int verificationId = mPendingVerificationToken++; PackageVerificationState verificationState = new PackageVerificationState(this); mPendingVerification.append(verificationId, verificationState); sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState); mRet = sendPackageVerificationRequest( verificationId, pkgLite, verificationState); // If both verifications are skipped, we should remove the state. if (verificationState.areAllVerificationsComplete()) { mPendingVerification.remove(verificationId); } } void sendEnableRollbackRequest() { final int enableRollbackToken = mPendingEnableRollbackToken++; Trace.asyncTraceBegin( TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); mPendingEnableRollback.append(enableRollbackToken, this); Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, enableRollbackToken); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, mSessionId); enableRollbackIntent.setType(PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Allow the broadcast to be sent before boot complete. // This is needed when committing the apk part of a staged // session in early boot. The rollback manager registers // its receiver early enough during the boot process that // it will not miss the broadcast. enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM, android.Manifest.permission.PACKAGE_ROLLBACK_AGENT, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // the duration to wait for rollback to be enabled, in millis long rollbackTimeout = DeviceConfig.getLong( DeviceConfig.NAMESPACE_ROLLBACK, PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS); if (rollbackTimeout < 0) { rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS; } final Message msg = mHandler.obtainMessage( ENABLE_ROLLBACK_TIMEOUT); msg.arg1 = enableRollbackToken; msg.arg2 = mSessionId; mHandler.sendMessageDelayed(msg, rollbackTimeout); } }, null, 0, null, null); mWaitForEnableRollbackToComplete = true; } /** * Send a request to check the integrity of the package. */ void sendIntegrityVerificationRequest( int verificationId, PackageInfoLite pkgLite, PackageVerificationState verificationState) { if (!isIntegrityVerificationEnabled()) { // Consider the integrity check as passed. verificationState.setIntegrityVerificationResult( PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); return; } final Intent integrityVerification = new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); integrityVerification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND; integrityVerification.addFlags(flags); integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId); integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName); integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode); integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode()); populateInstallerExtras(integrityVerification); // send to integrity component only. integrityVerification.setPackage("android"); final BroadcastOptions options = BroadcastOptions.makeBasic(); mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM, /* receiverPermission= */ null, /* appOp= */ AppOpsManager.OP_NONE, /* options= */ options.toBundle(), new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final Message msg = mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION); msg.arg1 = verificationId; mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout()); } }, /* scheduler= */ null, /* initialCode= */ 0, /* initialData= */ null, /* initialExtras= */ null); Trace.asyncTraceBegin( TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId); // stop the copy until verification succeeds. mWaitForIntegrityVerificationToComplete = true; } /** * Send a request to verifier(s) to verify the package if necessary, and return * {@link PackageManager#INSTALL_SUCCEEDED} if succeeded. */ int sendPackageVerificationRequest( int verificationId, PackageInfoLite pkgLite, PackageVerificationState verificationState) { int ret = INSTALL_SUCCEEDED; // TODO: http://b/22976637 // Apps installed for "all" users use the device owner to verify the app UserHandle verifierUser = getUser(); if (verifierUser == UserHandle.ALL) { verifierUser = UserHandle.SYSTEM; } /* * Determine if we have any installed package verifiers. If we * do, then we'll defer to them to verify the packages. */ final int requiredUid = mRequiredVerifierPackage == null ? -1 : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, verifierUser.getIdentifier()); verificationState.setRequiredVerifierUid(requiredUid); final int installerUid = verificationInfo == null ? -1 : verificationInfo.installerUid; final boolean isVerificationEnabled = isVerificationEnabled( pkgLite, verifierUser.getIdentifier(), installFlags, installerUid); final boolean isV4Signed = (signingDetails.signatureSchemeVersion == SIGNING_BLOCK_V4); final boolean isIncrementalInstall = (mDataLoaderType == DataLoaderType.INCREMENTAL); // NOTE: We purposefully skip verification for only incremental installs when there's // a v4 signature block. Otherwise, proceed with verification as usual. if (!origin.existing && isVerificationEnabled && (!isIncrementalInstall || !isV4Signed)) { final Intent verification = new Intent( Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Query all live verifiers based on current user state final List receivers = queryIntentReceiversInternal(verification, PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(), false /*allowDynamicSplits*/); if (DEBUG_VERIFY) { Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " + verification.toString() + " with " + pkgLite.verifiers.length + " optional verifiers"); } verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); verification.putExtra( PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, installFlags); verification.putExtra( PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName); verification.putExtra( PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode); verification.putExtra( PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE, pkgLite.getLongVersionCode()); populateInstallerExtras(verification); final List sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); DeviceIdleInternal idleController = mInjector.getLocalService(DeviceIdleInternal.class); final long idleDuration = getVerificationTimeout(); final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setTemporaryAppAllowlist(idleDuration, TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, REASON_PACKAGE_VERIFIER, ""); /* * If any sufficient verifiers were listed in the package * manifest, attempt to ask them. */ if (sufficientVerifiers != null) { final int n = sufficientVerifiers.size(); if (n == 0) { Slog.i(TAG, "Additional verifiers required, but none installed."); ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; } else { for (int i = 0; i < n; i++) { final ComponentName verifierComponent = sufficientVerifiers.get(i); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), verifierComponent.getPackageName(), idleDuration, verifierUser.getIdentifier(), false, REASON_PACKAGE_VERIFIER,"package verifier"); final Intent sufficientIntent = new Intent(verification); sufficientIntent.setComponent(verifierComponent); mContext.sendBroadcastAsUser(sufficientIntent, verifierUser, /* receiverPermission= */ null, options.toBundle()); } } } if (mRequiredVerifierPackage != null) { final ComponentName requiredVerifierComponent = matchComponentForVerifier( mRequiredVerifierPackage, receivers); /* * Send the intent to the required verification agent, * but only start the verification timeout after the * target BroadcastReceivers have run. */ verification.setComponent(requiredVerifierComponent); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), mRequiredVerifierPackage, idleDuration, verifierUser.getIdentifier(), false, REASON_PACKAGE_VERIFIER, "package verifier"); mContext.sendOrderedBroadcastAsUser(verification, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, /* appOp= */ AppOpsManager.OP_NONE, /* options= */ options.toBundle(), new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final Message msg = mHandler .obtainMessage(CHECK_PENDING_VERIFICATION); msg.arg1 = verificationId; mHandler.sendMessageDelayed(msg, getVerificationTimeout()); } }, null, 0, null, null); Trace.asyncTraceBegin( TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); /* * We don't want the copy to proceed until verification * succeeds. */ mWaitForVerificationToComplete = true; } } else { verificationState.setVerifierResponse( requiredUid, PackageManager.VERIFICATION_ALLOW); } return ret; } void populateInstallerExtras(Intent intent) { intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE, installSource.initiatingPackageName); if (verificationInfo != null) { if (verificationInfo.originatingUri != null) { intent.putExtra(Intent.EXTRA_ORIGINATING_URI, verificationInfo.originatingUri); } if (verificationInfo.referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, verificationInfo.referrer); } if (verificationInfo.originatingUid >= 0) { intent.putExtra(Intent.EXTRA_ORIGINATING_UID, verificationInfo.originatingUid); } if (verificationInfo.installerUid >= 0) { intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID, verificationInfo.installerUid); } } } void setReturnCode(int ret) { if (mRet == PackageManager.INSTALL_SUCCEEDED) { // Only update mRet if it was previously INSTALL_SUCCEEDED to // ensure we do not overwrite any previous failure results. mRet = ret; } } void handleVerificationFinished() { mWaitForVerificationToComplete = false; handleReturnCode(); } void handleIntegrityVerificationFinished() { mWaitForIntegrityVerificationToComplete = false; handleReturnCode(); } void handleRollbackEnabled() { // TODO(ruhler) b/112431924: Consider halting the install if we // couldn't enable rollback. mWaitForEnableRollbackToComplete = false; handleReturnCode(); } @Override void handleReturnCode() { if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete || mWaitForEnableRollbackToComplete) { return; } sendVerificationCompleteNotification(); } private void sendVerificationCompleteNotification() { if (mParentVerificationParams != null) { mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet); } else { try { observer.onPackageInstalled(null, mRet, "Package Verification Result", new Bundle()); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } } } private InstallArgs createInstallArgs(InstallParams params) { if (params.move != null) { return new MoveInstallArgs(params); } else { return new FileInstallArgs(params); } } /** * Create args that describe an existing installed package. Typically used * when cleaning up old installs, or used as a move source. */ private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) { return new FileInstallArgs(codePath, instructionSets); } static abstract class InstallArgs { /** @see InstallParams#origin */ final OriginInfo origin; /** @see InstallParams#move */ final MoveInfo move; final IPackageInstallObserver2 observer; // Always refers to PackageManager flags only final int installFlags; @NonNull final InstallSource installSource; final String volumeUuid; final UserHandle user; final String abiOverride; final String[] installGrantPermissions; final List whitelistedRestrictedPermissions; final int autoRevokePermissionsMode; /** If non-null, drop an async trace when the install completes */ final String traceMethod; final int traceCookie; final PackageParser.SigningDetails signingDetails; final int installReason; final int mInstallScenario; final boolean forceQueryableOverride; final int mDataLoaderType; // The list of instruction sets supported by this app. This is currently // only used during the rmdex() phase to clean up resources. We can get rid of this // if we move dex files under the common app path. /* nullable */ String[] instructionSets; InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, int installFlags, InstallSource installSource, String volumeUuid, UserHandle user, String[] instructionSets, String abiOverride, String[] installGrantPermissions, List whitelistedRestrictedPermissions, int autoRevokePermissionsMode, String traceMethod, int traceCookie, SigningDetails signingDetails, int installReason, int installScenario, boolean forceQueryableOverride, int dataLoaderType) { this.origin = origin; this.move = move; this.installFlags = installFlags; this.observer = observer; this.installSource = Preconditions.checkNotNull(installSource); this.volumeUuid = volumeUuid; this.user = user; this.instructionSets = instructionSets; this.abiOverride = abiOverride; this.installGrantPermissions = installGrantPermissions; this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; this.autoRevokePermissionsMode = autoRevokePermissionsMode; this.traceMethod = traceMethod; this.traceCookie = traceCookie; this.signingDetails = signingDetails; this.installReason = installReason; this.mInstallScenario = installScenario; this.forceQueryableOverride = forceQueryableOverride; this.mDataLoaderType = dataLoaderType; } /** New install */ InstallArgs(InstallParams params) { this(params.origin, params.move, params.observer, params.installFlags, params.installSource, params.volumeUuid, params.getUser(), null /*instructionSets*/, params.packageAbiOverride, params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions, params.autoRevokePermissionsMode, params.traceMethod, params.traceCookie, params.signingDetails, params.installReason, params.mInstallScenario, params.forceQueryableOverride, params.mDataLoaderType); } abstract int copyApk(); abstract int doPreInstall(int status); /** * Rename package into final resting place. All paths on the given * scanned package should be updated to reflect the rename. */ abstract boolean doRename(int status, ParsedPackage parsedPackage); abstract int doPostInstall(int status, int uid); /** @see PackageSettingBase#getPath() */ abstract String getCodePath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); abstract boolean doPostDeleteLI(boolean delete); /** * Called before the source arguments are copied. This is used mostly * for MoveParams when it needs to read the source file to put it in the * destination. */ int doPreCopy() { return PackageManager.INSTALL_SUCCEEDED; } /** * Called after the source arguments are copied. This is used mostly for * MoveParams when it needs to read the source file to put it in the * destination. */ int doPostCopy(int uid) { return PackageManager.INSTALL_SUCCEEDED; } protected boolean isEphemeral() { return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; } UserHandle getUser() { return user; } } void removeDexFiles(List allCodePaths, String[] instructionSets) { if (!allCodePaths.isEmpty()) { if (instructionSets == null) { throw new IllegalStateException("instructionSet == null"); } String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); for (String codePath : allCodePaths) { for (String dexCodeInstructionSet : dexCodeInstructionSets) { try { mInstaller.rmdex(codePath, dexCodeInstructionSet); } catch (InstallerException ignored) { } } } } } /** * Logic to handle installation of new applications, including copying * and renaming logic. */ class FileInstallArgs extends InstallArgs { private File codeFile; private File resourceFile; // Example topology: // /data/app/com.example/base.apk // /data/app/com.example/split_foo.apk // /data/app/com.example/lib/arm/libfoo.so // /data/app/com.example/lib/arm64/libfoo.so // /data/app/com.example/dalvik/arm/[email protected] /** New install */ FileInstallArgs(InstallParams params) { super(params); } /** Existing install */ FileInstallArgs(String codePath, String[] instructionSets) { super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0, PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE); this.codeFile = (codePath != null) ? new File(codePath) : null; } int copyApk() { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk"); try { return doCopyApk(); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private int doCopyApk() { if (origin.staged) { if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy"); codeFile = origin.file; return PackageManager.INSTALL_SUCCEEDED; } try { final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); codeFile = tempDir; } catch (IOException e) { Slog.w(TAG, "Failed to create copy file: " + e); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } int ret = PackageManagerServiceUtils.copyPackage( origin.file.getAbsolutePath(), codeFile); if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "Failed to copy package"); return ret; } final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath()); final File libraryRoot = new File(codeFile, LIB_DIR_NAME); NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(codeFile); ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, abiOverride, isIncremental); } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } finally { IoUtils.closeQuietly(handle); } return ret; } int doPreInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); } return status; } @Override boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); return false; } final File targetDir = resolveTargetDir(); final File beforeCodeFile = codeFile; final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName()); if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); final boolean onIncremental = mIncrementalManager != null && isIncrementalPath(beforeCodeFile.getAbsolutePath()); try { makeDirRecursive(afterCodeFile.getParentFile(), 0775); if (onIncremental) { // Just link files here. The stage dir will be removed when the installation // session is completed. mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile); } else { Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); } } catch (IOException | ErrnoException e) { Slog.w(TAG, "Failed to rename", e); return false; } if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) { Slog.w(TAG, "Failed to restorecon"); return false; } // Reflect the rename internally codeFile = afterCodeFile; // Reflect the rename in scanned details try { parsedPackage.setCodePath(afterCodeFile.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Failed to get path: " + afterCodeFile, e); return false; } parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, parsedPackage.getBaseApkPath())); parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, parsedPackage.getSplitCodePaths())); return true; } // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged // flow, we won't need this method anymore. private File resolveTargetDir() { boolean isStagedInstall = (installFlags & INSTALL_STAGED) != 0; if (isStagedInstall) { return Environment.getDataAppDirectory(null); } else { return codeFile.getParentFile(); } } int doPostInstall(int status, int uid) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); } return status; } @Override String getCodePath() { return (codeFile != null) ? codeFile.getAbsolutePath() : null; } private boolean cleanUp() { if (codeFile == null || !codeFile.exists()) { return false; } removeCodePathLI(codeFile); return true; } void cleanUpResourcesLI() { // Try enumerating all code paths before deleting List allCodePaths = Collections.EMPTY_LIST; if (codeFile != null && codeFile.exists()) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult result = ApkLiteParseUtils.parsePackageLite( input.reset(), codeFile, /* flags */ 0); if (result.isSuccess()) { // Ignore error; we tried our best allCodePaths = result.getResult().getAllApkPaths(); } } cleanUp(); removeDexFiles(allCodePaths, instructionSets); } boolean doPostDeleteLI(boolean delete) { // XXX err, shouldn't we respect the delete flag? cleanUpResourcesLI(); return true; } } /** * Logic to handle movement of existing installed applications. */ class MoveInstallArgs extends InstallArgs { private File codeFile; /** New install */ MoveInstallArgs(InstallParams params) { super(params); } int copyApk() { if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from " + move.fromUuid + " to " + move.toUuid); synchronized (mInstaller) { try { mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName, move.appId, move.seinfo, move.targetSdkVersion, move.fromCodePath); } catch (InstallerException e) { Slog.w(TAG, "Failed to move app", e); return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } } final String toPathName = new File(move.fromCodePath).getName(); codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName); if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile); return PackageManager.INSTALL_SUCCEEDED; } int doPreInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(move.toUuid); } return status; } @Override boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(move.toUuid); return false; } return true; } int doPostInstall(int status, int uid) { if (status == PackageManager.INSTALL_SUCCEEDED) { cleanUp(move.fromUuid); } else { cleanUp(move.toUuid); } return status; } @Override String getCodePath() { return (codeFile != null) ? codeFile.getAbsolutePath() : null; } private boolean cleanUp(String volumeUuid) { final String toPathName = new File(move.fromCodePath).getName(); final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), toPathName); Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid); final int[] userIds = mUserManager.getUserIds(); synchronized (mInstallLock) { // Clean up both app data and code // All package moves are frozen until finished // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since // this task was only focused on moving data on internal storage. // We don't want ART profiles cleared, because they don't move, // so we would be deleting the only copy (b/149200535). final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES; for (int userId : userIds) { try { mInstaller.destroyAppData(volumeUuid, move.packageName, userId, flags, 0); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } removeCodePathLI(codeFile); } return true; } void cleanUpResourcesLI() { throw new UnsupportedOperationException(); } boolean doPostDeleteLI(boolean delete) { throw new UnsupportedOperationException(); } } /** * Given {@code targetDir}, returns {@code targetDir/~~[randomStrA]/[packageName]-[randomStrB].} * Makes sure that {@code targetDir/~~[randomStrA]} directory doesn't exist. * Notice that this method doesn't actually create any directory. * * @param targetDir Directory that is two-levels up from the result directory. * @param packageName Name of the package whose code files are to be installed under the result * directory. * @return File object for the directory that should hold the code files of {@code packageName}. */ private File getNextCodePath(File targetDir, String packageName) { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[16]; File firstLevelDir; do { random.nextBytes(bytes); String dirName = RANDOM_DIR_PREFIX + Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); firstLevelDir = new File(targetDir, dirName); } while (firstLevelDir.exists()); random.nextBytes(bytes); String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); return new File(firstLevelDir, packageName + "-" + suffix); } static class PackageInstalledInfo { String name; int uid; // The set of users that originally had this package installed. int[] origUsers; // The set of users that now have this package installed. int[] newUsers; AndroidPackage pkg; int returnCode; String returnMsg; String installerPackageName; PackageRemovedInfo removedInfo; // The set of packages consuming this shared library or null if no consumers exist. ArrayList libraryConsumers; PackageFreezer freezer; public void setError(int code, String msg) { setReturnCode(code); setReturnMessage(msg); Slog.w(TAG, msg); } public void setError(String msg, PackageParserException e) { setReturnCode(e.error); setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e)); Slog.w(TAG, msg, e); } public void setError(String msg, PackageManagerException e) { returnCode = e.error; setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e)); Slog.w(TAG, msg, e); } public void setReturnCode(int returnCode) { this.returnCode = returnCode; } private void setReturnMessage(String returnMsg) { this.returnMsg = returnMsg; } // In some error cases we want to convey more info back to the observer String origPackage; String origPermission; } private static void updateDigest(MessageDigest digest, File file) throws IOException { try (DigestInputStream digestStream = new DigestInputStream(new FileInputStream(file), digest)) { while (digestStream.read() != -1) {} // nothing to do; just plow through the file } } private void removeNativeBinariesLI(PackageSetting ps) { if (ps != null) { NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString); } } @GuardedBy("mLock") private void enableSystemPackageLPw(AndroidPackage pkg) { mSettings.enableSystemPackageLPw(pkg.getPackageName()); } @GuardedBy("mLock") private boolean disableSystemPackageLPw(AndroidPackage oldPkg) { return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true); } private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) { updateSettingsInternalLI(newPackage, installArgs, allUsers, res); } private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); final String pkgName = pkg.getPackageName(); final int[] installedForUsers = res.origUsers; final int installReason = installArgs.installReason; InstallSource installSource = installArgs.installSource; final String installerPackageName = installSource.installerPackageName; if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath()); synchronized (mLock) { // For system-bundled packages, we assume that installing an upgraded version // of the package implies that the user actually wants to run that new code, // so we enable the package. final PackageSetting ps = mSettings.getPackageLPr(pkgName); final int userId = installArgs.user.getIdentifier(); if (ps != null) { if (pkg.isSystem()) { if (DEBUG_INSTALL) { Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); } // Enable system package for requested users if (res.origUsers != null) { for (int origUserId : res.origUsers) { if (userId == UserHandle.USER_ALL || userId == origUserId) { ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, origUserId, installerPackageName); } } } // Also convey the prior install/uninstall state if (allUsers != null && installedForUsers != null) { for (int currentUserId : allUsers) { final boolean installed = ArrayUtils.contains( installedForUsers, currentUserId); if (DEBUG_INSTALL) { Slog.d(TAG, " user " + currentUserId + " => " + installed); } ps.setInstalled(installed, currentUserId); } // these install state changes will be persisted in the // upcoming call to mSettings.writeLPr(). } if (allUsers != null) { for (int currentUserId : allUsers) { ps.resetOverrideComponentLabelIcon(currentUserId); } } } // Retrieve the overlays for shared libraries of the package. if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) { for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) { for (int currentUserId : UserManagerService.getInstance().getUserIds()) { if (!sharedLib.isDynamic()) { // TODO(146804378): Support overlaying static shared libraries continue; } final PackageSetting libPs = mSettings.getPackageLPr( sharedLib.getPackageName()); if (libPs == null) { continue; } ps.setOverlayPathsForLibrary(sharedLib.getName(), libPs.getOverlayPaths(currentUserId), currentUserId); } } } // It's implied that when a user requests installation, they want the app to be // installed and enabled. (This does not apply to USER_ALL, which here means only // install on users for which the app is already installed). if (userId != UserHandle.USER_ALL) { ps.setInstalled(true, userId); ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); } mSettings.addInstallerPackageNames(ps.installSource); // When replacing an existing package, preserve the original install reason for all // users that had the package installed before. Similarly for uninstall reasons. final Set previousUserIds = new ArraySet<>(); if (res.removedInfo != null && res.removedInfo.installReasons != null) { final int installReasonCount = res.removedInfo.installReasons.size(); for (int i = 0; i < installReasonCount; i++) { final int previousUserId = res.removedInfo.installReasons.keyAt(i); final int previousInstallReason = res.removedInfo.installReasons.valueAt(i); ps.setInstallReason(previousInstallReason, previousUserId); previousUserIds.add(previousUserId); } } if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) { for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) { final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i); final int previousReason = res.removedInfo.uninstallReasons.valueAt(i); ps.setUninstallReason(previousReason, previousUserId); } } // Set install reason for users that are having the package newly installed. final int[] allUsersList = mUserManager.getUserIds(); if (userId == UserHandle.USER_ALL) { // TODO(b/152629990): It appears that the package doesn't actually get newly // installed in this case, so the installReason shouldn't get modified? for (int currentUserId : allUsersList) { if (!previousUserIds.contains(currentUserId)) { ps.setInstallReason(installReason, currentUserId); } } } else if (!previousUserIds.contains(userId)) { ps.setInstallReason(installReason, userId); } // TODO(b/169721400): generalize Incremental States and create a Callback object // that can be used for all the packages. final String codePath = ps.getPathString(); if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) { final IncrementalStatesCallback incrementalStatesCallback = new IncrementalStatesCallback(ps.name, UserHandle.getUid(userId, ps.appId), getInstalledUsers(ps, userId)); ps.setIncrementalStatesCallback(incrementalStatesCallback); mIncrementalManager.registerLoadingProgressCallback(codePath, new IncrementalProgressListener(ps.name)); } // Ensure that the uninstall reason is UNKNOWN for users with the package installed. for (int currentUserId : allUsersList) { if (ps.getInstalled(currentUserId)) { ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId); } } mSettings.writeKernelMappingLPr(ps); final PermissionManagerServiceInternal.PackageInstalledParams.Builder permissionParamsBuilder = new PermissionManagerServiceInternal.PackageInstalledParams.Builder(); final boolean grantPermissions = (installArgs.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0; if (grantPermissions) { final List grantedPermissions = installArgs.installGrantPermissions != null ? Arrays.asList(installArgs.installGrantPermissions) : pkg.getRequestedPermissions(); permissionParamsBuilder.setGrantedPermissions(grantedPermissions); } final boolean allowlistAllRestrictedPermissions = (installArgs.installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0; final List allowlistedRestrictedPermissions = allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions() : installArgs.whitelistedRestrictedPermissions; if (allowlistedRestrictedPermissions != null) { permissionParamsBuilder.setAllowlistedRestrictedPermissions( allowlistedRestrictedPermissions); } final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode; permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode); mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId); } res.name = pkgName; res.uid = pkg.getUid(); res.pkg = pkg; res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); //to update install status Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings"); writeSettingsLPrTEMP(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } private static class InstallRequest { public final InstallArgs args; public final PackageInstalledInfo installResult; private InstallRequest(InstallArgs args, PackageInstalledInfo res) { this.args = args; this.installResult = res; } } @GuardedBy("mInstallLock") private void installPackagesTracedLI(List requests) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); installPackagesLI(requests); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Package state to commit to memory and disk after reconciliation has completed. */ private static class CommitRequest { final Map reconciledPackages; @NonNull final int[] mAllUsers; private CommitRequest(Map reconciledPackages, @NonNull int[] allUsers) { this.reconciledPackages = reconciledPackages; this.mAllUsers = allUsers; } } /** * Package scan results and related request details used to reconcile the potential addition of * one or more packages to the system. * * Reconcile will take a set of package details that need to be committed to the system and make * sure that they are valid in the context of the system and the other installing apps. Any * invalid state or app will result in a failed reconciliation and thus whatever operation (such * as install) led to the request. */ private static class ReconcileRequest { public final Map scannedPackages; public final Map allPackages; public final Map> sharedLibrarySource; public final Map installArgs; public final Map installResults; public final Map preparedPackages; public final Map versionInfos; public final Map lastStaticSharedLibSettings; private ReconcileRequest(Map scannedPackages, Map installArgs, Map installResults, Map preparedPackages, Map> sharedLibrarySource, Map allPackages, Map versionInfos, Map lastStaticSharedLibSettings) { this.scannedPackages = scannedPackages; this.installArgs = installArgs; this.installResults = installResults; this.preparedPackages = preparedPackages; this.sharedLibrarySource = sharedLibrarySource; this.allPackages = allPackages; this.versionInfos = versionInfos; this.lastStaticSharedLibSettings = lastStaticSharedLibSettings; } private ReconcileRequest(Map scannedPackages, Map> sharedLibrarySource, Map allPackages, Map versionInfos, Map lastStaticSharedLibSettings) { this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos, lastStaticSharedLibSettings); } } private static class ReconcileFailure extends PackageManagerException { ReconcileFailure(String message) { super("Reconcile failed: " + message); } ReconcileFailure(int reason, String message) { super(reason, "Reconcile failed: " + message); } ReconcileFailure(PackageManagerException e) { this(e.error, e.getMessage()); } } /** * A container of all data needed to commit a package to in-memory data structures and to disk. * TODO: move most of the data contained here into a PackageSetting for commit. */ private static class ReconciledPackage { public final ReconcileRequest request; public final PackageSetting pkgSetting; public final ScanResult scanResult; // TODO: Remove install-specific details from the reconcile result public final PackageInstalledInfo installResult; @Nullable public final PrepareResult prepareResult; @Nullable public final InstallArgs installArgs; public final DeletePackageAction deletePackageAction; public final List allowedSharedLibraryInfos; public final SigningDetails signingDetails; public final boolean sharedUserSignaturesChanged; public ArrayList collectedSharedLibraryInfos; public final boolean removeAppKeySetData; private ReconciledPackage(ReconcileRequest request, InstallArgs installArgs, PackageSetting pkgSetting, PackageInstalledInfo installResult, PrepareResult prepareResult, ScanResult scanResult, DeletePackageAction deletePackageAction, List allowedSharedLibraryInfos, SigningDetails signingDetails, boolean sharedUserSignaturesChanged, boolean removeAppKeySetData) { this.request = request; this.installArgs = installArgs; this.pkgSetting = pkgSetting; this.installResult = installResult; this.prepareResult = prepareResult; this.scanResult = scanResult; this.deletePackageAction = deletePackageAction; this.allowedSharedLibraryInfos = allowedSharedLibraryInfos; this.signingDetails = signingDetails; this.sharedUserSignaturesChanged = sharedUserSignaturesChanged; this.removeAppKeySetData = removeAppKeySetData; } /** * Returns a combined set of packages containing the packages already installed combined * with the package(s) currently being installed. The to-be installed packages take * precedence and may shadow already installed packages. */ private Map getCombinedAvailablePackages() { final ArrayMap combined = new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size()); combined.putAll(request.allPackages); for (ScanResult scanResult : request.scannedPackages.values()) { combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); } return combined; } } @GuardedBy("mLock") private static Map reconcilePackagesLocked( final ReconcileRequest request, KeySetManagerService ksms, Injector injector) throws ReconcileFailure { final Map scannedPackages = request.scannedPackages; final Map result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages final ArrayMap combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); combinedPackages.putAll(request.allPackages); final Map> incomingSharedLibraries = new ArrayMap<>(); for (String installPackageName : scannedPackages.keySet()) { final ScanResult scanResult = scannedPackages.get(installPackageName); // add / replace existing with incoming packages combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); // in the first pass, we'll build up the set of incoming shared libraries final List allowedSharedLibInfos = getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource); final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo; if (allowedSharedLibInfos != null) { for (SharedLibraryInfo info : allowedSharedLibInfos) { if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) { throw new ReconcileFailure("Static Shared Library " + staticLib.getName() + " is being installed twice in this set!"); } } } // the following may be null if we're just reconciling on boot (and not during install) final InstallArgs installArgs = request.installArgs.get(installPackageName); final PackageInstalledInfo res = request.installResults.get(installPackageName); final PrepareResult prepareResult = request.preparedPackages.get(installPackageName); final boolean isInstall = installArgs != null; if (isInstall && (res == null || prepareResult == null)) { throw new ReconcileFailure("Reconcile arguments are not balanced for " + installPackageName + "!"); } final DeletePackageAction deletePackageAction; // we only want to try to delete for non system apps if (isInstall && prepareResult.replace && !prepareResult.system) { final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0; final int deleteFlags = PackageManager.DELETE_KEEP_DATA | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, deleteFlags, null /* all users */); if (deletePackageAction == null) { throw new ReconcileFailure( PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE, "May not delete " + installPackageName + " to replace"); } } else { deletePackageAction = null; } final int scanFlags = scanResult.request.scanFlags; final int parseFlags = scanResult.request.parseFlags; final ParsedPackage parsedPackage = scanResult.request.parsedPackage; final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting; final PackageSetting lastStaticSharedLibSetting = request.lastStaticSharedLibSettings.get(installPackageName); final PackageSetting signatureCheckPs = (prepareResult != null && lastStaticSharedLibSetting != null) ? lastStaticSharedLibSetting : scanResult.pkgSetting; boolean removeAppKeySetData = false; boolean sharedUserSignaturesChanged = false; SigningDetails signingDetails = null; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. } else { if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + parsedPackage.getPackageName() + " upgrade keys do not match the previously installed" + " version"); } else { String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } } signingDetails = parsedPackage.getSigningDetails(); } else { try { final VersionInfo versionInfo = request.versionInfos.get(installPackageName); final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo); final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo); final boolean isRollback = installArgs != null && installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK; final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat, compareRecover, isRollback); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { removeAppKeySetData = true; } // We just determined the app is signed correctly, so bring // over the latest parsed certs. signingDetails = parsedPackage.getSigningDetails(); // if this is is a sharedUser, check to see if the new package is signed by a // newer // signing certificate than the existing one, and if so, copy over the new // details if (signatureCheckPs.sharedUser != null) { // Attempt to merge the existing lineage for the shared SigningDetails with // the lineage of the new package; if the shared SigningDetails are not // returned this indicates the new package added new signers to the lineage // and/or changed the capabilities of existing signers in the lineage. SigningDetails sharedSigningDetails = signatureCheckPs.sharedUser.signatures.mSigningDetails; SigningDetails mergedDetails = sharedSigningDetails.mergeLineageWith( signingDetails); if (mergedDetails != sharedSigningDetails) { signatureCheckPs.sharedUser.signatures.mSigningDetails = mergedDetails; } if (signatureCheckPs.sharedUser.signaturesChanged == null) { signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE; } } } catch (PackageManagerException e) { if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(e); } signingDetails = parsedPackage.getSigningDetails(); // If the system app is part of a shared user we allow that shared user to // change // signatures as well as part of an OTA. We still need to verify that the // signatures // are consistent within the shared user for a given boot, so only allow // updating // the signatures on the first package scanned for the shared user (i.e. if the // signaturesChanged state hasn't been initialized yet in SharedUserSetting). if (signatureCheckPs.sharedUser != null) { final Signature[] sharedUserSignatures = signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures; if (signatureCheckPs.sharedUser.signaturesChanged != null && compareSignatures(sharedUserSignatures, parsedPackage.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH) { if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) { // Mismatched signatures is an error and silently skipping system // packages will likely break the device in unforeseen ways. // However, we allow the device to boot anyway because, prior to Q, // vendors were not expecting the platform to crash in this // situation. // This WILL be a hard failure on any new API levels after Q. throw new ReconcileFailure( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Signature mismatch for shared user: " + scanResult.pkgSetting.sharedUser); } else { // Treat mismatched signatures on system packages using a shared // UID as // fatal for the system overall, rather than just failing to install // whichever package happened to be scanned later. throw new IllegalStateException( "Signature mismatch on system package " + parsedPackage.getPackageName() + " for shared user " + scanResult.pkgSetting.sharedUser); } } sharedUserSignaturesChanged = true; signatureCheckPs.sharedUser.signatures.mSigningDetails = parsedPackage.getSigningDetails(); signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE; } // File a report about this. String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } catch (IllegalArgumentException e) { // should never happen: certs matched when checking, but not when comparing // old to new for sharedUser throw new RuntimeException( "Signing certificates comparison made on incomparable signing details" + " but somehow passed verifySignatures!", e); } } result.put(installPackageName, new ReconciledPackage(request, installArgs, scanResult.pkgSetting, res, request.preparedPackages.get(installPackageName), scanResult, deletePackageAction, allowedSharedLibInfos, signingDetails, sharedUserSignaturesChanged, removeAppKeySetData)); } for (String installPackageName : scannedPackages.keySet()) { // Check all shared libraries and map to their actual file path. // We only do this here for apps not on a system dir, because those // are the only ones that can fail an install due to this. We // will take care of the system apps by updating all of their // library paths after the scan is done. Also during the initial // scan don't update any libs as we do this wholesale after all // apps are scanned to avoid dependency based scanning. final ScanResult scanResult = scannedPackages.get(installPackageName); if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0 || (scanResult.request.parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) { continue; } try { result.get(installPackageName).collectedSharedLibraryInfos = collectSharedLibraryInfos(scanResult.request.parsedPackage, combinedPackages, request.sharedLibrarySource, incomingSharedLibraries, injector.getCompatibility()); } catch (PackageManagerException e) { throw new ReconcileFailure(e.error, e.getMessage()); } } return result; } /** * Compare the newly scanned package with current system state to see which of its declared * shared libraries should be allowed to be added to the system. */ private static List getAllowedSharedLibInfos( ScanResult scanResult, Map> existingSharedLibraries) { // Let's used the parsed package as scanResult.pkgSetting may be null final ParsedPackage parsedPackage = scanResult.request.parsedPackage; if (scanResult.staticSharedLibraryInfo == null && scanResult.dynamicSharedLibraryInfos == null) { return null; } // Any app can add new static shared libraries if (scanResult.staticSharedLibraryInfo != null) { return Collections.singletonList(scanResult.staticSharedLibraryInfo); } final boolean hasDynamicLibraries = parsedPackage.isSystem() && scanResult.dynamicSharedLibraryInfos != null; if (!hasDynamicLibraries) { return null; } final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState() .isUpdatedSystemApp(); // We may not yet have disabled the updated package yet, so be sure to grab the // current setting if that's the case. final PackageSetting updatedSystemPs = isUpdatedSystemApp ? scanResult.request.disabledPkgSetting == null ? scanResult.request.oldPkgSetting : scanResult.request.disabledPkgSetting : null; if (isUpdatedSystemApp && (updatedSystemPs.pkg == null || updatedSystemPs.pkg.getLibraryNames() == null)) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares libraries that are not declared on the system image; skipping"); return null; } final ArrayList infos = new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size()); for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) { final String name = info.getName(); if (isUpdatedSystemApp) { // New library entries can only be added through the // system image. This is important to get rid of a lot // of nasty edge cases: for example if we allowed a non- // system update of the app to add a library, then uninstalling // the update would make the library go away, and assumptions // we made such as through app install filtering would now // have allowed apps on the device which aren't compatible // with it. Better to just have the restriction here, be // conservative, and create many fewer cases that can negatively // impact the user experience. if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library " + name + " that is not declared on system image; skipping"); continue; } } if (sharedLibExists( name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library " + name + " that already exists; skipping"); continue; } infos.add(info); } return infos; } /** * Returns false if the adding shared library already exists in the map and so could not be * added. */ private static boolean addSharedLibraryToPackageVersionMap( Map> target, SharedLibraryInfo library) { final String name = library.getName(); if (target.containsKey(name)) { if (library.getType() != SharedLibraryInfo.TYPE_STATIC) { // We've already added this non-version-specific library to the map. return false; } else if (target.get(name).indexOfKey(library.getLongVersion()) >= 0) { // We've already added this version of a version-specific library to the map. return false; } } else { target.put(name, new WatchedLongSparseArray<>()); } target.get(name).put(library.getLongVersion(), library); return true; } @GuardedBy("mLock") private void commitPackagesLocked(final CommitRequest request) { // TODO: remove any expected failures from this method; this should only be able to fail due // to unavoidable errors (I/O, etc.) for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) { final ScanResult scanResult = reconciledPkg.scanResult; final ScanRequest scanRequest = scanResult.request; final ParsedPackage parsedPackage = scanRequest.parsedPackage; final String packageName = parsedPackage.getPackageName(); final PackageInstalledInfo res = reconciledPkg.installResult; if (reconciledPkg.prepareResult.replace) { AndroidPackage oldPackage = mPackages.get(packageName); // Set the update and install times PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName()); reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime; reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis(); res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList( reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked()); if (reconciledPkg.prepareResult.system) { // Remove existing system package removePackageLI(oldPackage, true); if (!disableSystemPackageLPw(oldPackage)) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( oldPackage.getPath(), getAppDexInstructionSets( AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, deletedPkgSetting), AndroidPackageUtils.getSecondaryCpuAbi(oldPackage, deletedPkgSetting))); } else { res.removedInfo.args = null; } } else { try { // Settings will be written during the call to updateSettingsLI(). executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, true, request.mAllUsers, false, parsedPackage); } catch (SystemDeleteException e) { if (mIsEngBuild) { throw new RuntimeException("Unexpected failure", e); // ignore; not possible for non-system app } } // Successfully deleted the old package; proceed with replace. // If deleted package lived in a container, give users a chance to // relinquish resources before killing. if (oldPackage.isExternalStorage()) { if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + oldPackage + " is ASEC-hosted -> UNAVAILABLE"); } final int[] uidArray = new int[]{oldPackage.getUid()}; final ArrayList pkgList = new ArrayList<>(1); pkgList.add(oldPackage.getPackageName()); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } // Update the in-memory copy of the previous code paths. PackageSetting ps1 = mSettings.getPackageLPr( reconciledPkg.prepareResult.existingPackage.getPackageName()); if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP) == 0) { if (ps1.mOldCodePaths == null) { ps1.mOldCodePaths = new ArraySet<>(); } Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath()); if (oldPackage.getSplitCodePaths() != null) { Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths()); } } else { ps1.mOldCodePaths = null; } if (reconciledPkg.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { PackageSetting ps2 = mSettings.getPackageLPr( parsedPackage.getPackageName()); if (ps2 != null) { res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null; } } } } AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers); updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res); final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { updateSequenceNumberLP(ps, res.newUsers); updateInstantAppInstallerLocked(packageName); } } ApplicationPackageManager.invalidateGetPackagesForUidCache(); } /** * Installs one or more packages atomically. This operation is broken up into four phases: *

      *
    • Prepare *
      Analyzes any current install state, parses the package and does initial * validation on it.
    • *
    • Scan *
      Interrogates the parsed packages given the context collected in prepare.
    • *
    • Reconcile *
      Validates scanned packages in the context of each other and the current system * state to ensure that the install will be successful. *
    • Commit *
      Commits all scanned packages and updates system state. This is the only place * that system state may be modified in the install flow and all predictable errors * must be determined before this phase.
    • *
    * * Failure at any phase will result in a full failure to install all packages. */ @GuardedBy("mInstallLock") private void installPackagesLI(List requests) { final Map preparedScans = new ArrayMap<>(requests.size()); final Map installArgs = new ArrayMap<>(requests.size()); final Map installResults = new ArrayMap<>(requests.size()); final Map prepareResults = new ArrayMap<>(requests.size()); final Map versionInfos = new ArrayMap<>(requests.size()); final Map lastStaticSharedLibSettings = new ArrayMap<>(requests.size()); final Map createdAppId = new ArrayMap<>(requests.size()); boolean success = false; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI"); for (InstallRequest request : requests) { // TODO(b/109941548): remove this once we've pulled everything from it and into // scan, reconcile or commit. final PrepareResult prepareResult; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage"); prepareResult = preparePackageLI(request.args, request.installResult); } catch (PrepareFailure prepareFailure) { request.installResult.setError(prepareFailure.error, prepareFailure.getMessage()); request.installResult.origPackage = prepareFailure.conflictingPackage; request.installResult.origPermission = prepareFailure.conflictingPermission; return; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED); request.installResult.installerPackageName = request.args.installSource.installerPackageName; final String packageName = prepareResult.packageToScan.getPackageName(); prepareResults.put(packageName, prepareResult); installResults.put(packageName, request.installResult); installArgs.put(packageName, request.args); try { final ScanResult result = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user, request.args.abiOverride); if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) { request.installResult.setError( PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, "Duplicate package " + result.pkgSetting.pkg.getPackageName() + " in multi-package install request."); return; } createdAppId.put(packageName, optimisticallyRegisterAppId(result)); versionInfos.put(result.pkgSetting.pkg.getPackageName(), getSettingsVersionForPackage(result.pkgSetting.pkg)); if (result.staticSharedLibraryInfo != null) { final PackageSetting sharedLibLatestVersionSetting = getSharedLibLatestVersionSetting(result); if (sharedLibLatestVersionSetting != null) { lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(), sharedLibLatestVersionSetting); } } } catch (PackageManagerException e) { request.installResult.setError("Scanning Failed.", e); return; } } ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs, installResults, prepareResults, mSharedLibraries, Collections.unmodifiableMap(mPackages), versionInfos, lastStaticSharedLibSettings); CommitRequest commitRequest = null; synchronized (mLock) { Map reconciledPackages; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); reconciledPackages = reconcilePackagesLocked( reconcileRequest, mSettings.getKeySetManagerService(), mInjector); } catch (ReconcileFailure e) { for (InstallRequest request : requests) { request.installResult.setError("Reconciliation failed...", e); } return; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages"); commitRequest = new CommitRequest(reconciledPackages, mUserManager.getUserIds()); commitPackagesLocked(commitRequest); success = true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } executePostCommitSteps(commitRequest); } finally { if (success) { for (InstallRequest request : requests) { final InstallArgs args = request.args; if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) { continue; } if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) { continue; } // For incremental installs, we bypass the verifier prior to install. Now // that we know the package is valid, send a notice to the verifier with // the root hash of the base.apk. final String baseCodePath = request.installResult.pkg.getBaseApkPath(); final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths(); final Uri originUri = Uri.fromFile(args.origin.resolvedFile); final int verificationId = mPendingVerificationToken++; final String rootHashString = PackageManagerServiceUtils .buildVerificationRootHashString(baseCodePath, splitCodePaths); broadcastPackageVerified(verificationId, originUri, PackageManager.VERIFICATION_ALLOW, rootHashString, args.mDataLoaderType, args.getUser()); } } else { for (ScanResult result : preparedScans.values()) { if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(), false)) { cleanUpAppIdCreation(result); } } // TODO(patb): create a more descriptive reason than unknown in future release // mark all non-failure installs as UNKNOWN so we do not treat them as success for (InstallRequest request : requests) { if (request.installResult.freezer != null) { request.installResult.freezer.close(); } if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN; } } } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * On successful install, executes remaining steps after commit completes and the package lock * is released. These are typically more expensive or require calls to installd, which often * locks on {@link #mLock}. */ private void executePostCommitSteps(CommitRequest commitRequest) { final ArraySet incrementalStorages = new ArraySet<>(); for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg; final String packageName = pkg.getPackageName(); final String codePath = pkg.getPath(); final boolean onIncremental = mIncrementalManager != null && isIncrementalPath(codePath); if (onIncremental) { IncrementalStorage storage = mIncrementalManager.openStorage(codePath); if (storage == null) { throw new IllegalArgumentException( "Install: null storage for incremental package " + packageName); } incrementalStorages.add(storage); } prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } if (reconciledPkg.prepareResult.replace) { mDexManager.notifyPackageUpdated(pkg.getPackageName(), pkg.getBaseApkPath(), pkg.getSplitCodePaths()); } // Prepare the application profiles for the new code paths. // This needs to be done before invoking dexopt so that any install-time profile // can be used for optimizations. mArtManagerService.prepareAppProfiles( pkg, resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()), /* updateReferenceProfileContent= */ true); // Compute the compilation reason from the installation scenario. final int compilationReason = mDexManager.getCompilationReasonForInstallScenario( reconciledPkg.installArgs.mInstallScenario); // Construct the DexoptOptions early to see if we should skip running dexopt. // // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. // // Also, don't fail application installs if the dexopt step fails. final boolean isBackupOrRestore = reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP; final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0); DexoptOptions dexoptOptions = new DexoptOptions(packageName, compilationReason, dexoptFlags); // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: // - after doRename which will sync the package data from AndroidPackage and // its corresponding ApplicationInfo. // - after installNewPackageLIF or replacePackageLIF which will update result with the // uid of the application (pkg.applicationInfo.uid). // This update happens in place! // // We only need to dexopt if the package meets ALL of the following conditions: // 1) it is not an instant app or if it is then dexopt is enabled via gservices. // 2) it is not debuggable. // 3) it is not on Incremental File System. // // Note that we do not dexopt instant apps by default. dexopt can take some time to // complete, so we skip this step during installation. Instead, we'll take extra time // the first time the instant app starts. It's preferred to do it this way to provide // continuous progress to the useur instead of mysteriously blocking somewhere in the // middle of running an instant app. The default behaviour can be overridden // via gservices. // // Furthermore, dexopt may be skipped, depending on the install scenario and current // state of the device. // // TODO(b/174695087): instantApp and onIncremental should be removed and their install // path moved to SCENARIO_FAST. final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) && !pkg.isDebuggable() && (!onIncremental) && dexoptOptions.isCompilationEnabled(); if (performDexopt) { // Compile the layout resources. if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); mViewCompiler.compileLayouts(pkg); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); ScanResult result = reconciledPkg.scanResult; // This mirrors logic from commitReconciledScanResultLocked, where the library files // needed for dexopt are assigned. // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous // setting needs to be passed to have a comparison, hide it behind an immutable // interface. There's no good reason to have 3 different ways to access the real // PackageSetting object, only one of which is actually correct. PackageSetting realPkgSetting = result.existingSettingCopied ? result.request.pkgSetting : result.pkgSetting; if (realPkgSetting == null) { realPkgSetting = reconciledPkg.pkgSetting; } // Unfortunately, the updated system app flag is only tracked on this PackageSetting boolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState() .isUpdatedSystemApp(); realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp); mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting, null /* instructionSets */, getOrCreateCompilerPackageStats(pkg), mDexManager.getPackageUseInfoOrDefault(packageName), dexoptOptions); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Notify BackgroundDexOptService that the package has been changed. // If this is an update of a package which used to fail to compile, // BackgroundDexOptService will remove it from its denylist. // TODO: Layering violation BackgroundDexOptService.notifyPackageChanged(packageName); notifyPackageChangeObserversOnUpdate(reconciledPkg); } waitForNativeBinariesExtraction(incrementalStorages); } static void waitForNativeBinariesExtraction( ArraySet incrementalStorages) { if (incrementalStorages.isEmpty()) { return; } try { // Native library extraction may take very long time: each page could potentially // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't // make much sense as blocking here doesn't lock up the framework, but only blocks // the installation session and the following ones. Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract"); for (int i = 0; i < incrementalStorages.size(); ++i) { IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i); storage.waitForNativeBinariesExtraction(); } } finally { Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract"); } } private int[] getInstalledUsers(PackageSetting ps, int userId) { final int[] allUserIds = resolveUserIds(userId); final ArrayList installedUserIdsList = new ArrayList<>(); for (int i = 0; i < allUserIds.length; i++) { if (ps.getInstalled(allUserIds[i])) { installedUserIdsList.add(allUserIds[i]); } } final int numInstalledUserId = installedUserIdsList.size(); final int[] installedUserIds = new int[numInstalledUserId]; for (int i = 0; i < numInstalledUserId; i++) { installedUserIds[i] = installedUserIdsList.get(i); } return installedUserIds; } /** * Package states callback, used to listen for package state changes and send broadcasts */ private final class IncrementalStatesCallback implements IncrementalStates.Callback { private final String mPackageName; private final int mUid; private final int[] mInstalledUserIds; IncrementalStatesCallback(String packageName, int uid, int[] installedUserIds) { mPackageName = packageName; mUid = uid; mInstalledUserIds = installedUserIds; } @Override public void onPackageFullyLoaded() { final SparseArray newBroadcastAllowList; final String codePath; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(mPackageName); if (ps == null) { return; } newBroadcastAllowList = mAppsFilter.getVisibilityAllowList( ps, mInstalledUserIds, mSettings.getPackagesLocked()); codePath = ps.getPathString(); } // Unregister progress listener mIncrementalManager.unregisterLoadingProgressCallbacks(codePath); // Make sure the information is preserved scheduleWriteSettingsLocked(); } } /** * Loading progress callback, used to listen for progress changes and update package setting */ private class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub { private final String mPackageName; IncrementalProgressListener(String packageName) { mPackageName = packageName; } @Override public void onPackageLoadingProgressChanged(float progress) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(mPackageName); if (ps == null) { return; } ps.setLoadingProgress(progress); } } } @Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid, int userId) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(packageName); if (ps == null) { Slog.w(TAG, "Failed to get package setting. Package " + packageName + " is not installed"); return null; } if (!ps.getInstalled(userId)) { Slog.w(TAG, "Failed to get package setting. Package " + packageName + " is not installed for user " + userId); return null; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { Slog.w(TAG, "Failed to get package setting. Package " + packageName + " is not visible to the calling app"); return null; } } return ps; } private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) { final PackageSetting pkgSetting = reconciledPkg.pkgSetting; final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult; final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.removedInfo; PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName(); pkgChangeEvent.version = pkgSetting.versionCode; pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime; pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.isUpdate); pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.dataRemoved); pkgChangeEvent.isDeleted = false; notifyPackageChangeObservers(pkgChangeEvent); } private void notifyPackageChangeObserversOnDelete(String packageName, long version) { PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); pkgChangeEvent.packageName = packageName; pkgChangeEvent.version = version; pkgChangeEvent.lastUpdateTimeMillis = 0L; pkgChangeEvent.newInstalled = false; pkgChangeEvent.dataRemoved = false; pkgChangeEvent.isDeleted = true; notifyPackageChangeObservers(pkgChangeEvent); } private void notifyPackageChangeObservers(PackageChangeEvent event) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers"); synchronized (mPackageChangeObservers) { for(IPackageChangeObserver observer : mPackageChangeObservers) { try { observer.onPackageChanged(event); } catch(RemoteException e) { Log.wtf(TAG, e); } } } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * The set of data needed to successfully install the prepared package. This includes data that * will be used to scan and reconcile the package. */ private static class PrepareResult { public final boolean replace; public final int scanFlags; public final int parseFlags; @Nullable /* The original Package if it is being replaced, otherwise {@code null} */ public final AndroidPackage existingPackage; public final ParsedPackage packageToScan; public final boolean clearCodeCache; public final boolean system; public final PackageSetting originalPs; public final PackageSetting disabledPs; private PrepareResult(boolean replace, int scanFlags, int parseFlags, AndroidPackage existingPackage, ParsedPackage packageToScan, boolean clearCodeCache, boolean system, PackageSetting originalPs, PackageSetting disabledPs) { this.replace = replace; this.scanFlags = scanFlags; this.parseFlags = parseFlags; this.existingPackage = existingPackage; this.packageToScan = packageToScan; this.clearCodeCache = clearCodeCache; this.system = system; this.originalPs = originalPs; this.disabledPs = disabledPs; } } private static class PrepareFailure extends PackageManagerException { public String conflictingPackage; public String conflictingPermission; PrepareFailure(int error) { super(error, "Failed to prepare for install."); } PrepareFailure(int error, String detailMessage) { super(error, detailMessage); } PrepareFailure(String message, Exception e) { super(e instanceof PackageParserException ? ((PackageParserException) e).error : ((PackageManagerException) e).error, ExceptionUtils.getCompleteMessage(message, e)); } PrepareFailure conflictsWithExistingPermission(String conflictingPermission, String conflictingPackage) { this.conflictingPermission = conflictingPermission; this.conflictingPackage = conflictingPackage; return this; } } private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName, @NonNull ParsedPackage parsedPackage, int scanFlags) { // If the defining package is signed with our cert, it's okay. This // also includes the "updating the same package" case, of course. // "updating same package" could also involve key-rotation. final PackageSetting sourcePackageSetting; synchronized (mLock) { sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName); } final SigningDetails sourceSigningDetails = (sourcePackageSetting == null ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails()); final KeySetManagerService ksms = mSettings.getKeySetManagerService(); if (sourcePackageName.equals(parsedPackage.getPackageName()) && (ksms.shouldCheckUpgradeKeySetLocked( sourcePackageSetting, scanFlags))) { return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage); } else { // in the event of signing certificate rotation, we need to see if the // package's certificate has rotated from the current one, or if it is an // older certificate with which the current is ok with sharing permissions if (sourceSigningDetails.checkCapability( parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { return true; } else if (parsedPackage.getSigningDetails().checkCapability( sourceSigningDetails, PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { // the scanned package checks out, has signing certificate rotation // history, and is newer; bring it over synchronized (mLock) { sourcePackageSetting.signatures.mSigningDetails = parsedPackage.getSigningDetails(); } return true; } else { return false; } } } /* * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges * as this only works for packages that are installed * * TODO: Move logic for permission group compatibility into PermissionManagerService */ @SuppressWarnings("AndroidFrameworkCompatChange") private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) { return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S; } @GuardedBy("mInstallLock") private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) throws PrepareFailure { final int installFlags = args.installFlags; final File tmpPackageFile = new File(args.getCodePath()); final boolean onExternal = args.volumeUuid != null; final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0); final boolean virtualPreload = ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK; @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE; if (args.move != null) { // moving a complete application; perform an initial scan on the new install location scanFlags |= SCAN_INITIAL; } if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { scanFlags |= SCAN_DONT_KILL_APP; } if (instantApp) { scanFlags |= SCAN_AS_INSTANT_APP; } if (fullApp) { scanFlags |= SCAN_AS_FULL_APP; } if (virtualPreload) { scanFlags |= SCAN_AS_VIRTUAL_PRELOAD; } if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); // Validity check if (instantApp && onExternal) { Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal); throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID); } // Retrieve PackageSettings and parse package @ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY | ParsingPackageUtils.PARSE_ENFORCE_CODE | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final ParsedPackage parsedPackage; try (PackageParser2 pp = mInjector.getPreparingPackageParser()) { parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false); AndroidPackageUtils.validatePackageDexMetadata(parsedPackage); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Instant apps have several additional install-time checks. if (instantApp) { if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) { Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " does not target at least O"); throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, "Instant app package must target at least O"); } if (parsedPackage.getSharedUserId() != null) { Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " may not declare sharedUserId."); throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, "Instant app package may not declare a sharedUserId"); } } if (parsedPackage.isStaticSharedLibrary()) { // Static shared libraries have synthetic package names renameStaticSharedLibraryPackage(parsedPackage); // No static shared libs on external storage if (onExternal) { Slog.i(TAG, "Static shared libs can only be installed on internal storage."); throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Packages declaring static-shared libs cannot be updated"); } } String pkgName = res.name = parsedPackage.getPackageName(); if (parsedPackage.isTestOnly()) { if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); } } try { // either use what we've been given or parse directly from the APK if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) { parsedPackage.setSigningDetails(args.signingDetails); } else { parsedPackage.setSigningDetails(ParsingPackageUtils.getSigningDetails( parsedPackage, false /* skipVerify */)); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); } if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion < SignatureSchemeVersion.SIGNING_BLOCK_V2) { Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " is not signed with at least APK Signature Scheme v2"); throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, "Instant app package must be signed with APK Signature Scheme v2 or greater"); } boolean systemApp = false; boolean replace = false; synchronized (mLock) { // Check if installing already existing package if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.getRenamedPackageLPr(pkgName); if (parsedPackage.getOriginalPackages().contains(oldName) && mPackages.containsKey(oldName)) { // This package is derived from an original package, // and this device has been updating from that original // name. We must continue using the original name, so // rename the new package here. parsedPackage.setPackageName(oldName); pkgName = parsedPackage.getPackageName(); replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, "Replacing existing renamed package: oldName=" + oldName + " pkgName=" + pkgName); } } else if (mPackages.containsKey(pkgName)) { // This package, under its official name, already exists // on the device; we should replace it. replace = true; if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } if (replace) { // Prevent apps opting out from runtime permissions AndroidPackage oldPackage = mPackages.get(pkgName); final int oldTargetSdk = oldPackage.getTargetSdkVersion(); final int newTargetSdk = parsedPackage.getTargetSdkVersion(); if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { throw new PrepareFailure( PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, "Package " + parsedPackage.getPackageName() + " new target SDK " + newTargetSdk + " doesn't support runtime permissions but the old" + " target SDK " + oldTargetSdk + " does."); } // Prevent persistent apps from being updated if (oldPackage.isPersistent() && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, "Package " + oldPackage.getPackageName() + " is a persistent app. " + "Persistent apps are not updateable."); } } } PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps != null) { if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); // Static shared libs have same package with different versions where // we internally use a synthetic package name to allow multiple versions // of the same package, therefore we need to compare signatures against // the package setting for the latest library version. PackageSetting signatureCheckPs = ps; if (parsedPackage.isStaticSharedLibrary()) { SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage); if (libraryInfo != null) { signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName()); } } // Quick validity check that we're signed correctly if updating; // we'll check this again later when scanning, but we want to // bail early here before tripping over redefined permissions. final KeySetManagerService ksms = mSettings.getKeySetManagerService(); if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + parsedPackage.getPackageName() + " upgrade keys do not match the " + "previously installed version"); } } else { try { final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage); final boolean compareRecover = isRecoverSignatureUpdateNeeded( parsedPackage); // We don't care about disabledPkgSetting on install for now. final boolean compatMatch = verifySignatures(signatureCheckPs, null, parsedPackage.getSigningDetails(), compareCompat, compareRecover, isRollback); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { synchronized (mLock) { ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName()); } } } catch (PackageManagerException e) { throw new PrepareFailure(e.error, e.getMessage()); } } if (ps.pkg != null) { systemApp = ps.pkg.isSystem(); } res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups()); for (int groupNum = 0; groupNum < numGroups; groupNum++) { final ParsedPermissionGroup group = parsedPackage.getPermissionGroups().get(groupNum); final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(group.getName(), 0); if (sourceGroup != null && cannotInstallWithBadPermissionGroups(parsedPackage)) { final String sourcePackageName = sourceGroup.packageName; if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName)) && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, scanFlags)) { EventLog.writeEvent(0x534e4554, "146211400", -1, parsedPackage.getPackageName()); throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP, "Package " + parsedPackage.getPackageName() + " attempting to redeclare permission group " + group.getName() + " already owned by " + sourcePackageName); } } } // TODO: Move logic for checking permission compatibility into PermissionManagerService final int N = ArrayUtils.size(parsedPackage.getPermissions()); for (int i = N - 1; i >= 0; i--) { final ParsedPermission perm = parsedPackage.getPermissions().get(i); final Permission bp = mPermissionManager.getPermissionTEMP(perm.getName()); // Don't allow anyone but the system to define ephemeral permissions. if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 && !systemApp) { Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() + " attempting to delcare ephemeral permission " + perm.getName() + "; Removing ephemeral."); perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT); } // Check whether the newly-scanned package wants to define an already-defined perm if (bp != null) { final String sourcePackageName = bp.getPackageName(); if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, scanFlags)) { // If the owning package is the system itself, we log but allow // install to proceed; we fail the install on all other permission // redefinitions. if (!sourcePackageName.equals("android")) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package " + parsedPackage.getPackageName() + " attempting to redeclare permission " + perm.getName() + " already owned by " + sourcePackageName) .conflictsWithExistingPermission(perm.getName(), sourcePackageName); } else { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " attempting to redeclare system permission " + perm.getName() + "; ignoring new declaration"); parsedPackage.removePermission(i); } } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) { // Prevent apps to change protection level to dangerous from any other // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { if (bp != null && !bp.isRuntime()) { Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " trying to change a non-runtime permission " + perm.getName() + " to runtime; keeping old protection level"); perm.setProtectionLevel(bp.getProtectionLevel()); } } } } if (perm.getGroup() != null && cannotInstallWithBadPermissionGroups(parsedPackage)) { boolean isPermGroupDefinedByPackage = false; for (int groupNum = 0; groupNum < numGroups; groupNum++) { if (parsedPackage.getPermissionGroups().get(groupNum).getName() .equals(perm.getGroup())) { isPermGroupDefinedByPackage = true; break; } } if (!isPermGroupDefinedByPackage) { final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(perm.getGroup(), 0); if (sourceGroup == null) { EventLog.writeEvent(0x534e4554, "146211400", -1, parsedPackage.getPackageName()); throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, "Package " + parsedPackage.getPackageName() + " attempting to declare permission " + perm.getName() + " in non-existing group " + perm.getGroup()); } else { String groupSourcePackageName = sourceGroup.packageName; if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName) && !doesSignatureMatchForPermissions(groupSourcePackageName, parsedPackage, scanFlags)) { EventLog.writeEvent(0x534e4554, "146211400", -1, parsedPackage.getPackageName()); throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, "Package " + parsedPackage.getPackageName() + " attempting to declare permission " + perm.getName() + " in group " + perm.getGroup() + " owned by package " + groupSourcePackageName + " with incompatible certificate"); } } } } } } if (systemApp) { if (onExternal) { // Abort update; system app can't be replaced with app on sdcard throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Cannot install updates to system apps on sdcard"); } else if (instantApp) { // Abort update; system app can't be replaced with an instant app throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, "Cannot update a system app with an instant app"); } } if (args.move != null) { // We did an in-place move, so dex is ready to roll scanFlags |= SCAN_NO_DEX; scanFlags |= SCAN_MOVE; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps == null) { res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Missing settings for moved package " + pkgName); } // We moved the entire application as-is, so bring over the // previously derived ABI information. parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString) .setSecondaryCpuAbi(ps.secondaryCpuAbiString); } } else { // Enable SCAN_NO_DEX flag to skip dexopt at a later stage scanFlags |= SCAN_NO_DEX; try { PackageSetting pkgSetting; synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(pkgName); } boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null && pkgSetting.getPkgState().isUpdatedSystemApp(); final String abiOverride = deriveAbiOverride(args.abiOverride); AndroidPackage oldPackage = mPackages.get(pkgName); boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem(); final Pair derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage, isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred, abiOverride, mAppLib32InstallDir); derivedAbi.first.applyTo(parsedPackage); derivedAbi.second.applyTo(parsedPackage); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI: " + pme.getMessage()); } } if (!args.doRename(res.returnCode, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } try { setUpFsVerityIfPossible(parsedPackage); } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Failed to set up verity: " + e); } final PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, "installPackageLI"); boolean shouldCloseFreezerBeforeReturn = true; try { final AndroidPackage existingPackage; String renamedPackage = null; boolean sysPkg = false; int targetScanFlags = scanFlags; int targetParseFlags = parseFlags; final PackageSetting ps; final PackageSetting disabledPs; if (replace) { if (parsedPackage.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // and cannot be updated as an update would get a new package name, // unless this is installed from adb which is useful for development. AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName()); if (existingPkg != null && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring " + "static-shared libs cannot be updated"); } } final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final AndroidPackage oldPackage; final String pkgName11 = parsedPackage.getPackageName(); final int[] allUsers; final int[] installedUsers; final int[] uninstalledUsers; synchronized (mLock) { oldPackage = mPackages.get(pkgName11); existingPackage = oldPackage; if (DEBUG_INSTALL) { Slog.d(TAG, "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage); } ps = mSettings.getPackageLPr(pkgName11); disabledPs = mSettings.getDisabledSystemPkgLPr(ps); // verify signatures are valid final KeySetManagerService ksms = mSettings.getKeySetManagerService(); if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package not signed by keys specified by upgrade-keysets: " + pkgName11); } } else { SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails(); SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails(); // default to original signature matching if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails, SigningDetails.CertCapabilities.INSTALLED_DATA) && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails, SigningDetails.CertCapabilities.ROLLBACK)) { // Allow the update to proceed if this is a rollback and the parsed // package's current signing key is the current signer or in the lineage // of the old package; this allows a rollback to a previously installed // version after an app's signing key has been rotated without requiring // the rollback capability on the previous signing key. if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf( parsedPkgSigningDetails)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package has a different signature: " + pkgName11); } } } // don't allow a system upgrade unless the upgrade hash matches if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) { final byte[] digestBytes; try { final MessageDigest digest = MessageDigest.getInstance("SHA-512"); updateDigest(digest, new File(parsedPackage.getBaseApkPath())); if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) { for (String path : parsedPackage.getSplitCodePaths()) { updateDigest(digest, new File(path)); } } digestBytes = digest.digest(); } catch (NoSuchAlgorithmException | IOException e) { throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "Could not compute hash: " + pkgName11); } if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) { throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "New package fails restrict-update check: " + pkgName11); } // retain upgrade restriction parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash()); } // Check for shared user id changes String invalidPackageName = null; if (!Objects.equals(oldPackage.getSharedUserId(), parsedPackage.getSharedUserId())) { invalidPackageName = parsedPackage.getPackageName(); } if (invalidPackageName != null) { throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, "Package " + invalidPackageName + " tried to change user " + oldPackage.getSharedUserId()); } // In case of rollback, remember per-user/profile install state allUsers = mUserManager.getUserIds(); installedUsers = ps.queryInstalledUsers(allUsers, true); uninstalledUsers = ps.queryInstalledUsers(allUsers, false); // don't allow an upgrade from full to ephemeral if (isInstantApp) { if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) { for (int currentUser : allUsers) { if (!ps.getInstantApp(currentUser)) { // can't downgrade from full to instant Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11 + " for user: " + currentUser); throw new PrepareFailure( PackageManager.INSTALL_FAILED_SESSION_INVALID); } } } else if (!ps.getInstantApp(args.user.getIdentifier())) { // can't downgrade from full to instant Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11 + " for user: " + args.user.getIdentifier()); throw new PrepareFailure( PackageManager.INSTALL_FAILED_SESSION_INVALID); } } } // Update what is removed res.removedInfo = new PackageRemovedInfo(this); res.removedInfo.uid = oldPackage.getUid(); res.removedInfo.removedPackage = oldPackage.getPackageName(); res.removedInfo.installerPackageName = ps.installSource.installerPackageName; res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null; res.removedInfo.isUpdate = true; res.removedInfo.origUsers = installedUsers; res.removedInfo.installReasons = new SparseArray<>(installedUsers.length); for (int i = 0; i < installedUsers.length; i++) { final int userId = installedUsers[i]; res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); } res.removedInfo.uninstallReasons = new SparseArray<>(uninstalledUsers.length); for (int i = 0; i < uninstalledUsers.length; i++) { final int userId = uninstalledUsers[i]; res.removedInfo.uninstallReasons.put(userId, ps.getUninstallReason(userId)); } sysPkg = oldPackage.isSystem(); if (sysPkg) { // Set the system/privileged/oem/vendor/product flags as needed final boolean privileged = oldPackage.isPrivileged(); final boolean oem = oldPackage.isOem(); final boolean vendor = oldPackage.isVendor(); final boolean product = oldPackage.isProduct(); final boolean odm = oldPackage.isOdm(); final boolean systemExt = oldPackage.isSystemExt(); final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) | (vendor ? SCAN_AS_VENDOR : 0) | (product ? SCAN_AS_PRODUCT : 0) | (odm ? SCAN_AS_ODM : 0) | (systemExt ? SCAN_AS_SYSTEM_EXT : 0); if (DEBUG_INSTALL) { Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); targetParseFlags = systemParseFlags; targetScanFlags = systemScanFlags; } else { // non system replace replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, "replaceNonSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } } } else { // new package install ps = null; disabledPs = null; replace = false; existingPackage = null; // Remember this for later, in case we need to rollback this install String pkgName1 = parsedPackage.getPackageName(); if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage); // TODO(patb): MOVE TO RECONCILE synchronized (mLock) { renamedPackage = mSettings.getRenamedPackageLPr(pkgName1); if (renamedPackage != null) { // A package with the same name is already installed, though // it has been renamed to an older name. The package we // are trying to install should be installed as an update to // the existing one, but that has not been requested, so bail. throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName1 + " without first uninstalling package running as " + renamedPackage); } if (mPackages.containsKey(pkgName1)) { // Don't allow installation over an existing package with the same name. throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName1 + " without first uninstalling."); } } } // we're passing the freezer back to be closed in a later phase of install shouldCloseFreezerBeforeReturn = false; return new PrepareResult(replace, targetScanFlags, targetParseFlags, existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg, ps, disabledPs); } finally { res.freezer = freezer; if (shouldCloseFreezerBeforeReturn) { freezer.close(); } } } /** * Set up fs-verity for the given package if possible. This requires a feature flag of system * property to be enabled only if the kernel supports fs-verity. * *

    When the feature flag is set to legacy mode, only APK is supported (with some experimental * kernel patches). In normal mode, all file format can be supported. */ private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException, PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); if (!standardMode && !legacyMode) { return; } if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion() < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) { return; } // Collect files we care for fs-verity setup. ArrayMap fsverityCandidates = new ArrayMap<>(); if (legacyMode) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName()); if (ps != null && ps.isPrivileged()) { fsverityCandidates.put(pkg.getBaseApkPath(), null); if (pkg.getSplitCodePaths() != null) { for (String splitPath : pkg.getSplitCodePaths()) { fsverityCandidates.put(splitPath, null); } } } } } else { // NB: These files will become only accessible if the signing key is loaded in kernel's // .fs-verity keyring. fsverityCandidates.put(pkg.getBaseApkPath(), VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath())); final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( pkg.getBaseApkPath()); if (new File(dmPath).exists()) { fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); } if (pkg.getSplitCodePaths() != null) { for (String path : pkg.getSplitCodePaths()) { fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); if (new File(splitDmPath).exists()) { fsverityCandidates.put(splitDmPath, VerityUtils.getFsveritySignatureFilePath(splitDmPath)); } } } } for (Map.Entry entry : fsverityCandidates.entrySet()) { final String filePath = entry.getKey(); final String signaturePath = entry.getValue(); if (!legacyMode) { // fs-verity is optional for now. Only set up if signature is provided. if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { try { VerityUtils.setUpFsverity(filePath, signaturePath); } catch (IOException e) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, "Failed to enable fs-verity: " + e); } } continue; } // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath); if (result.isOk()) { if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath); final FileDescriptor fd = result.getUnownedFileDescriptor(); try { final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); try { // A file may already have fs-verity, e.g. when reused during a split // install. If the measurement succeeds, no need to attempt to set up. mInstaller.assertFsverityRootHashMatches(filePath, rootHash); } catch (InstallerException e) { mInstaller.installApkVerity(filePath, fd, result.getContentSize()); mInstaller.assertFsverityRootHashMatches(filePath, rootHash); } } finally { IoUtils.closeQuietly(fd); } } else if (result.isFailed()) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, "Failed to generate verity"); } } } private static boolean isExternal(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } private static boolean isSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } private static boolean isUpdatedSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } private 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(); } } @Override public void deletePackageAsUser(String packageName, int versionCode, IPackageDeleteObserver observer, int userId, int flags) { deletePackageVersioned(new VersionedPackage(packageName, versionCode), new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags); } @Override public void deleteExistingPackageAsUser(VersionedPackage versionedPackage, final IPackageDeleteObserver2 observer, final int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); Preconditions.checkNotNull(versionedPackage); Preconditions.checkNotNull(observer); final String packageName = versionedPackage.getPackageName(); final long versionCode = versionedPackage.getLongVersionCode(); int installedForUsersCount = 0; synchronized (mLock) { // Normalize package name to handle renamed packages and static libs final String internalPkgName = resolveInternalPackageNameLPr(packageName, versionCode); final PackageSetting ps = mSettings.getPackageLPr(internalPkgName); if (ps != null) { int[] installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); installedForUsersCount = installedUsers.length; } } if (installedForUsersCount > 1) { deletePackageVersionedInternal(versionedPackage, observer, userId, 0, true); } else { try { observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_INTERNAL_ERROR, null); } catch (RemoteException re) { } } } @Override public void deletePackageVersioned(VersionedPackage versionedPackage, final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) { deletePackageVersionedInternal(versionedPackage, observer, userId, deleteFlags, false); } private void deletePackageVersionedInternal(VersionedPackage versionedPackage, final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags, final boolean allowSilentUninstall) { final int callingUid = Binder.getCallingUid(); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); final boolean canViewInstantApps = canViewInstantApps(callingUid, userId); Preconditions.checkNotNull(versionedPackage); Preconditions.checkNotNull(observer); Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(), PackageManager.VERSION_CODE_HIGHEST, Long.MAX_VALUE, "versionCode must be >= -1"); final String packageName = versionedPackage.getPackageName(); final long versionCode = versionedPackage.getLongVersionCode(); final String internalPackageName; try { if (mInjector.getLocalService(ActivityTaskManagerInternal.class) .isBaseOfLockedTask(packageName)) { observer.onPackageDeleted( packageName, PackageManager.DELETE_FAILED_APP_PINNED, null); EventLog.writeEvent(0x534e4554, "127605586", -1, ""); return; } } catch (RemoteException e) { e.rethrowFromSystemServer(); } synchronized (mLock) { // Normalize package name to handle renamed packages and static libs internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode); } final int uid = Binder.getCallingUid(); if (!isOrphaned(internalPackageName) && !allowSilentUninstall && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) { mHandler.post(() -> { try { final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder()); observer.onUserActionRequired(intent); } catch (RemoteException re) { } }); return; } final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0; final int[] users = deleteAllUsers ? mUserManager.getUserIds() : new int[]{userId}; if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "deletePackage for user " + userId); } if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) { mHandler.post(() -> { try { observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED, null); } catch (RemoteException re) { } }); return; } if (!deleteAllUsers && getBlockUninstallForUser(internalPackageName, userId)) { mHandler.post(() -> { try { observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED, null); } catch (RemoteException re) { } }); return; } if (DEBUG_REMOVE) { Slog.d(TAG, "deletePackageAsUser: pkg=" + internalPackageName + " user=" + userId + " deleteAllUsers: " + deleteAllUsers + " version=" + (versionCode == PackageManager.VERSION_CODE_HIGHEST ? "VERSION_CODE_HIGHEST" : versionCode)); } // Queue up an async operation since the package deletion may take a little while. mHandler.post(() -> { int returnCode; final PackageSetting ps = mSettings.getPackageLPr(internalPackageName); boolean doDeletePackage = true; if (ps != null) { final boolean targetIsInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); doDeletePackage = !targetIsInstantApp || canViewInstantApps; } if (doDeletePackage) { if (!deleteAllUsers) { returnCode = deletePackageX(internalPackageName, versionCode, userId, deleteFlags, false /*removedBySystem*/); } else { int[] blockUninstallUserIds = getBlockUninstallForUsers( internalPackageName, users); // If nobody is blocking uninstall, proceed with delete for all users if (ArrayUtils.isEmpty(blockUninstallUserIds)) { returnCode = deletePackageX(internalPackageName, versionCode, userId, deleteFlags, false /*removedBySystem*/); } else { // Otherwise uninstall individually for users with blockUninstalls=false final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS; for (int userId1 : users) { if (!ArrayUtils.contains(blockUninstallUserIds, userId1)) { returnCode = deletePackageX(internalPackageName, versionCode, userId1, userFlags, false /*removedBySystem*/); if (returnCode != PackageManager.DELETE_SUCCEEDED) { Slog.w(TAG, "Package delete failed for user " + userId1 + ", returnCode " + returnCode); } } } // The app has only been marked uninstalled for certain users. // We still need to report that delete was blocked returnCode = PackageManager.DELETE_FAILED_OWNER_BLOCKED; } } } else { returnCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR; } try { observer.onPackageDeleted(packageName, returnCode, null); } catch (RemoteException e) { Log.i(TAG, "Observer no longer exists."); } //end catch notifyPackageChangeObserversOnDelete(packageName, versionCode); }); } private String resolveExternalPackageNameLPr(AndroidPackage pkg) { return mComputer.resolveExternalPackageNameLPr(pkg); } @GuardedBy("mLock") private String resolveInternalPackageNameLPr(String packageName, long versionCode) { return mComputer.resolveInternalPackageNameLPr(packageName, versionCode); } boolean isCallerVerifier(int callingUid) { final int callingUserId = UserHandle.getUserId(callingUid); return mRequiredVerifierPackage != null && callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId); } private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) { if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID || UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { return true; } final int callingUserId = UserHandle.getUserId(callingUid); // If the caller installed the pkgName, then allow it to silently uninstall. if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) { return true; } // Allow package verifier to silently uninstall. if (mRequiredVerifierPackage != null && callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) { return true; } // Allow package uninstaller to silently uninstall. if (mRequiredUninstallerPackage != null && callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) { return true; } // Allow storage manager to silently uninstall. if (mStorageManagerPackage != null && callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) { return true; } // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently // uninstall for device owner provisioning. if (checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid) == PERMISSION_GRANTED) { return true; } return false; } private int[] getBlockUninstallForUsers(String packageName, int[] userIds) { int[] result = EMPTY_INT_ARRAY; for (int userId : userIds) { if (getBlockUninstallForUser(packageName, userId)) { result = ArrayUtils.appendInt(result, userId); } } return result; } @Override public boolean isPackageDeviceAdminOnAnyUser(String packageName) { final int callingUid = Binder.getCallingUid(); if (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 (getInstantAppPackageName(callingUid) != null && !isCallerSameApp(packageName, callingUid)) { return false; } return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL); } private 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; } } } } catch (RemoteException e) { } return false; } /** 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 shouldKeepUninstalledPackageLPr(String packageName) { return mKeepUninstalledPackages != null && mKeepUninstalledPackages.contains(packageName); } /** * This method is an internal method that could be get invoked either * to delete an installed package or to clean up a failed installation. * After deleting an installed package, a broadcast is sent to notify any * listeners that the package has been removed. For cleaning up a failed * installation, the broadcast is not necessary since the package's * installation wouldn't have sent the initial broadcast either * The key steps in deleting a package are * deleting the package information in internal structures like mPackages, * deleting the packages base directories through installd * updating mSettings to reflect current status * persisting settings for later use * sending a broadcast if necessary * * @param removedBySystem A boolean to indicate the package was removed automatically without * the user-initiated action. */ int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags, boolean removedBySystem) { final PackageRemovedInfo info = new PackageRemovedInfo(this); final boolean res; final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0 ? UserHandle.USER_ALL : userId; if (isPackageDeviceAdmin(packageName, removeUser)) { Slog.w(TAG, "Not removing package " + packageName + ": has active device admin"); return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER; } final PackageSetting uninstalledPs; final PackageSetting disabledSystemPs; final AndroidPackage pkg; // for the uninstall-updates case and restricted profiles, remember the per- // user handle installed state int[] allUsers; final int freezeUser; final SparseArray priorUserStates; /** enabled state of the uninstalled application */ synchronized (mLock) { uninstalledPs = mSettings.getPackageLPr(packageName); if (uninstalledPs == null) { Slog.w(TAG, "Not removing non-existent package " + packageName); return PackageManager.DELETE_FAILED_INTERNAL_ERROR; } if (versionCode != PackageManager.VERSION_CODE_HIGHEST && uninstalledPs.versionCode != versionCode) { Slog.w(TAG, "Not removing package " + packageName + " with versionCode " + uninstalledPs.versionCode + " != " + versionCode); return PackageManager.DELETE_FAILED_INTERNAL_ERROR; } disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName); // Static shared libs can be declared by any package, so let us not // allow removing a package if it provides a lib others depend on. pkg = mPackages.get(packageName); allUsers = mUserManager.getUserIds(); if (pkg != null && pkg.getStaticSharedLibName() != null) { SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (libraryInfo != null) { for (int currUserId : allUsers) { if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) { continue; } List libClientPackages = getPackagesUsingSharedLibraryLPr( libraryInfo, MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId); if (!ArrayUtils.isEmpty(libClientPackages)) { Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName() + " hosting lib " + libraryInfo.getName() + " version " + libraryInfo.getLongVersion() + " used by " + libClientPackages + " for user " + currUserId); return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY; } } } } info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true); if (isUpdatedSystemApp(uninstalledPs) && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) { // We're downgrading a system app, which will apply to all users, so // freeze them all during the downgrade freezeUser = UserHandle.USER_ALL; priorUserStates = new SparseArray<>(); for (int i = 0; i < allUsers.length; i++) { PackageUserState userState = uninstalledPs.readUserState(allUsers[i]); priorUserStates.put(allUsers[i], new TempUserState(userState.enabled, userState.lastDisableAppCaller, userState.installed)); } } else { freezeUser = removeUser; priorUserStates = null; } } synchronized (mInstallLock) { if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId); try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser, deleteFlags, "deletePackageX")) { res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers, deleteFlags | PackageManager.DELETE_CHATTY, info, true, null); } synchronized (mLock) { if (res) { if (pkg != null) { mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs, info.removedUsers); } updateSequenceNumberLP(uninstalledPs, info.removedUsers); updateInstantAppInstallerLocked(packageName); } } ApplicationPackageManager.invalidateGetPackagesForUidCache(); } if (res) { final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0; info.sendPackageRemovedBroadcasts(killApp, removedBySystem); info.sendSystemPackageUpdatedBroadcasts(); } // Force a gc here. Runtime.getRuntime().gc(); // Delete the resources here after sending the broadcast to let // other processes clean up before deleting resources. synchronized (mInstallLock) { if (info.args != null) { info.args.doPostDeleteLI(true); } boolean reEnableStub = false; if (priorUserStates != null) { synchronized (mLock) { for (int i = 0; i < allUsers.length; i++) { TempUserState priorUserState = priorUserStates.get(allUsers[i]); int enabledState = priorUserState.enabledState; PackageSetting pkgSetting = getPackageSetting(packageName); pkgSetting.setEnabled(enabledState, allUsers[i], priorUserState.lastDisableAppCaller); AndroidPackage aPkg = pkgSetting.getPkg(); boolean pkgEnabled = aPkg != null && aPkg.isEnabled(); if (!reEnableStub && priorUserState.installed && ((enabledState == COMPONENT_ENABLED_STATE_DEFAULT && pkgEnabled) || enabledState == COMPONENT_ENABLED_STATE_ENABLED)) { reEnableStub = true; } } mSettings.writeAllUsersPackageRestrictionsLPr(); } } final AndroidPackage stubPkg = (disabledSystemPs == null) ? null : disabledSystemPs.pkg; if (stubPkg != null && stubPkg.isStub()) { final PackageSetting stubPs; synchronized (mLock) { stubPs = mSettings.getPackageLPr(stubPkg.getPackageName()); } if (stubPs != null) { if (reEnableStub) { if (DEBUG_COMPRESSION) { Slog.i(TAG, "Enabling system stub after removal; pkg: " + stubPkg.getPackageName()); } enableCompressedPackage(stubPkg, stubPs); } else if (DEBUG_COMPRESSION) { Slog.i(TAG, "System stub disabled for all users, leaving uncompressed " + "after removal; pkg: " + stubPkg.getPackageName()); } } } } return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } static class PackageRemovedInfo { final PackageSender packageSender; String removedPackage; String installerPackageName; int uid = -1; int removedAppId = -1; int[] origUsers; int[] removedUsers = null; int[] broadcastUsers = null; int[] instantUserIds = null; SparseArray installReasons; SparseArray uninstallReasons; boolean isRemovedPackageSystemUpdate = false; boolean isUpdate; boolean dataRemoved; boolean removedForAllUsers; boolean isStaticSharedLib; // a two dimensional array mapping userId to the set of appIds that can receive notice // of package changes SparseArray broadcastAllowList; // Clean up resources deleted packages. InstallArgs args = null; PackageRemovedInfo(PackageSender packageSender) { this.packageSender = packageSender; } void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) { sendPackageRemovedBroadcastInternal(killApp, removedBySystem); } void sendSystemPackageUpdatedBroadcasts() { if (isRemovedPackageSystemUpdate) { sendSystemPackageUpdatedBroadcastsInternal(); } } private void sendSystemPackageUpdatedBroadcastsInternal() { Bundle extras = new Bundle(2); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null); packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null); packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0, removedPackage, null, null, null, null /* broadcastAllowList */, getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle()); if (installerPackageName != null) { packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras, 0 /*flags*/, installerPackageName, null, null, null, null /* broadcastAllowList */, null); packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, extras, 0 /*flags*/, installerPackageName, null, null, null, null /* broadcastAllowList */, null); } } private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) { // Don't send static shared library removal broadcasts as these // libs are visible only the the apps that depend on them an one // cannot remove the library if it has a dependency. if (isStaticSharedLib) { return; } Bundle extras = new Bundle(2); final int removedUid = removedAppId >= 0 ? removedAppId : uid; extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp); extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem); if (isUpdate || isRemovedPackageSystemUpdate) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null) { packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, 0, null /*targetPackage*/, null, broadcastUsers, instantUserIds, broadcastAllowList, null); if (installerPackageName != null) { packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, 0 /*flags*/, installerPackageName, null, broadcastUsers, instantUserIds, null, null); } packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL, removedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME, null /*finishedReceiver*/, broadcastUsers, instantUserIds, broadcastAllowList, null /*bOptions*/); if (dataRemoved && !isRemovedPackageSystemUpdate) { packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers, instantUserIds, broadcastAllowList, null); packageSender.notifyPackageRemoved(removedPackage, removedUid); } } if (removedAppId >= 0) { // If a system app's updates are uninstalled the UID is not actually removed. Some // services need to know the package name affected. if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) { extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage); } packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, broadcastUsers, instantUserIds, broadcastAllowList, null); } } void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) { removedUsers = userIds; if (removedUsers == null) { broadcastUsers = null; return; } broadcastUsers = EMPTY_INT_ARRAY; instantUserIds = EMPTY_INT_ARRAY; for (int i = userIds.length - 1; i >= 0; --i) { final int userId = userIds[i]; if (deletedPackageSetting.getInstantApp(userId)) { instantUserIds = ArrayUtils.appendInt(instantUserIds, userId); } else { broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId); } } } } /* * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA * flag is not set, the data directory is removed as well. * make sure this flag is set for partially installed apps. If not its meaningless to * delete a partially installed application. */ private void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles, PackageRemovedInfo outInfo, int flags, boolean writeSettings) { String packageName = deletedPs.name; if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs); // Retrieve object to delete permissions for shared user later on final AndroidPackage deletedPkg = deletedPs.pkg; if (outInfo != null) { outInfo.removedPackage = packageName; outInfo.installerPackageName = deletedPs.installSource.installerPackageName; outInfo.isStaticSharedLib = deletedPkg != null && deletedPkg.getStaticSharedLibName() != null; outInfo.populateUsers(deletedPs == null ? null : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs); } removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0); if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { final AndroidPackage resolvedPkg; if (deletedPkg != null) { resolvedPkg = deletedPkg; } else { // We don't have a parsed package when it lives on an ejected // adopted storage device, so fake something together resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name, deletedPs.volumeUuid); } destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); destroyAppProfilesLIF(resolvedPkg); if (outInfo != null) { outInfo.dataRemoved = true; } } int removedAppId = -1; // writer boolean installedStateChanged = false; if (deletedPs != null) { if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mLock) { mDomainVerificationManager.clearPackage(deletedPs.name); mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName); mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { outInfo.removedAppId = removedAppId; } if (!mSettings.isDisabledSystemPackageLPr(packageName)) { // If we don't have a disabled system package to reinstall, the package is // really gone and its permission state should be removed. final SharedUserSetting sus = deletedPs.getSharedUser(); List sharedUserPkgs = sus != null ? sus.getPackages() : null; if (sharedUserPkgs == null) { sharedUserPkgs = Collections.emptyList(); } mPermissionManager.onPackageUninstalled(packageName, deletedPs.appId, deletedPs.pkg, sharedUserPkgs, UserHandle.USER_ALL); } clearPackagePreferredActivitiesLPw( deletedPs.name, changedUsers, UserHandle.USER_ALL); } if (changedUsers.size() > 0) { updateDefaultHomeNotLocked(changedUsers); postPreferredActivityChangedBroadcast(UserHandle.USER_ALL); } } // make sure to preserve per-user disabled state if this removal was just // a downgrade of a system app to the factory package if (outInfo != null && outInfo.origUsers != null) { if (DEBUG_REMOVE) { Slog.d(TAG, "Propagating install state across downgrade"); } for (int userId : allUserHandles) { final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId); if (DEBUG_REMOVE) { Slog.d(TAG, " user " + userId + " => " + installed); } if (installed != deletedPs.getInstalled(userId)) { installedStateChanged = true; } deletedPs.setInstalled(installed, userId); if (installed) { deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId); } } } } synchronized (mLock) { // can downgrade to reader if (writeSettings) { // Save settings now writeSettingsLPrTEMP(); } if (installedStateChanged) { mSettings.writeKernelMappingLPr(deletedPs); } } if (removedAppId != -1) { // A user ID was deleted here. Go through all users and remove it // from KeyStore. removeKeystoreDataIfNeeded( mInjector.getUserManagerInternal(), UserHandle.USER_ALL, removedAppId); } } private static @Nullable ScanPartition resolveApexToScanPartition( ApexManager.ActiveApexInfo apexInfo) { for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) { ScanPartition sp = SYSTEM_PARTITIONS.get(i); if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith( sp.getFolder().getAbsolutePath())) { return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX); } } return null; } /* * Tries to delete system package. */ private void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs, @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo, boolean writeSettings) throws SystemDeleteException { final boolean applyUserRestrictions = outInfo != null && (outInfo.origUsers != null); final AndroidPackage deletedPkg = deletedPs.pkg; // Confirm if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition // reader final PackageSetting disabledPs = action.disabledPs; if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName() + " disabledPs=" + disabledPs); Slog.d(TAG, "Deleting system pkg from data partition"); if (DEBUG_REMOVE) { if (applyUserRestrictions) { Slog.d(TAG, "Remembering install states:"); for (int userId : allUserHandles) { final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId); Slog.d(TAG, " u=" + userId + " inst=" + finstalled); } } } if (outInfo != null) { // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; } if (disabledPs.versionCode < deletedPs.versionCode) { // Delete data for downgrades flags &= ~PackageManager.DELETE_KEEP_DATA; } else { // Preserve data by setting flag flags |= PackageManager.DELETE_KEEP_DATA; } deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, outInfo, writeSettings); // writer synchronized (mLock) { // NOTE: The system package always needs to be enabled; even if it's for // a compressed stub. If we don't, installing the system package fails // during scan [scanning checks the disabled packages]. We will reverse // this later, after we've "installed" the stub. // Reinstate the old system package enableSystemPackageLPw(disabledPs.pkg); // Remove any native libraries from the upgraded package. removeNativeBinariesLI(deletedPs); } // Install the system package if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); try { installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles, outInfo == null ? null : outInfo.origUsers, writeSettings); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": " + e.getMessage()); // TODO(patb): can we avoid this; throw would come from scan... throw new SystemDeleteException(e); } finally { if (disabledPs.pkg.isStub()) { // We've re-installed the stub; make sure it's disabled here. If package was // originally enabled, we'll install the compressed version of the application // and re-enable it afterward. final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName()); if (stubPs != null) { int userId = action.user == null ? UserHandle.USER_ALL : action.user.getIdentifier(); if (userId == UserHandle.USER_ALL) { for (int aUserId : allUserHandles) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android"); } } else if (userId >= UserHandle.USER_SYSTEM) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android"); } } } } } /** * Installs a package that's already on the system partition. */ private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString, @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings) throws PackageManagerException { final File codePath = new File(codePathString); @ParseFlags int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_MUST_BE_APK | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR; @ScanFlags int scanFlags = SCAN_AS_SYSTEM; for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { ScanPartition partition = mDirsToScanAsSystem.get(i); if (partition.containsFile(codePath)) { scanFlags |= partition.scanFlag; if (partition.containsPrivApp(codePath)) { scanFlags |= SCAN_AS_PRIVILEGED; } break; } } final AndroidPackage pkg = scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null); PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName()); try { // update shared libraries for the newly re-installed system package updateSharedLibrariesLocked(pkg, pkgSetting, null, null, Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } prepareAppDataAfterInstallLIF(pkg); // writer synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName()); final boolean applyUserRestrictions = origUserHandles != null; if (applyUserRestrictions) { boolean installedStateChanged = false; if (DEBUG_REMOVE) { Slog.d(TAG, "Propagating install state across reinstall"); } for (int userId : allUserHandles) { final boolean installed = ArrayUtils.contains(origUserHandles, userId); if (DEBUG_REMOVE) { Slog.d(TAG, " user " + userId + " => " + installed); } if (installed != ps.getInstalled(userId)) { installedStateChanged = true; } ps.setInstalled(installed, userId); if (installed) { ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId); } } // Regardless of writeSettings we need to ensure that this restriction // state propagation is persisted mSettings.writeAllUsersPackageRestrictionsLPr(); if (installedStateChanged) { mSettings.writeKernelMappingLPr(ps); } } // The method below will take care of removing obsolete permissions and granting // install permissions. mPermissionManager.onPackageInstalled(pkg, PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, UserHandle.USER_ALL); for (final int userId : allUserHandles) { if (applyUserRestrictions) { mSettings.writePermissionStateForUserLPr(userId, false); } } // can downgrade to reader here if (writeSettings) { writeSettingsLPrTEMP(); } } return pkg; } private void deleteInstalledPackageLIF(PackageSetting ps, boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles, PackageRemovedInfo outInfo, boolean writeSettings) { synchronized (mLock) { if (outInfo != null) { outInfo.uid = ps.appId; outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps, allUserHandles, mSettings.getPackagesLocked()); } } // Delete package data from internal structures and also remove data if flag is set removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings); // Delete application code and resources only for parent packages if (deleteCodeAndResources && (outInfo != null)) { outInfo.args = createInstallArgsForExisting( ps.getPathString(), getAppDexInstructionSets( ps.primaryCpuAbiString, ps.secondaryCpuAbiString)); if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } } @Override public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_PACKAGES, null); // TODO (b/157774108): This should fail on non-existent packages. synchronized (mLock) { // 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. AndroidPackage pkg = mPackages.get(packageName); if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot block uninstall of package: " + packageName + " providing static shared library: " + pkg.getStaticSharedLibName()); return false; } mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall); mSettings.writePackageRestrictionsLPr(userId); } return true; } @Override public boolean getBlockUninstallForUser(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null || shouldFilterApplicationLocked(ps, Binder.getCallingUid(), userId)) { return false; } return mSettings.getBlockUninstallLPr(userId, packageName); } } @Override public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) { enforceSystemOrRoot("setRequiredForSystemUser can only be run by the system or root"); synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { Log.w(TAG, "Package doesn't exist: " + packageName); return false; } if (systemUserApp) { ps.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER; } else { ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER; } writeSettingsLPrTEMP(); } return true; } private static class DeletePackageAction { public final PackageSetting deletingPs; public final PackageSetting disabledPs; public final PackageRemovedInfo outInfo; public final int flags; public final UserHandle user; private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs, PackageRemovedInfo outInfo, int flags, UserHandle user) { this.deletingPs = deletingPs; this.disabledPs = disabledPs; this.outInfo = outInfo; this.flags = flags; this.user = user; } } /** * @return a {@link DeletePackageAction} if the provided package and related state may be * deleted, {@code null} otherwise. */ @Nullable @GuardedBy("mLock") private static DeletePackageAction mayDeletePackageLocked( PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs, int flags, UserHandle user) { if (ps == null) { return null; } if (isSystemApp(ps)) { final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0; final boolean deleteAllUsers = user == null || user.getIdentifier() == UserHandle.USER_ALL; if ((!deleteSystem || deleteAllUsers) && disabledPs == null) { Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName()); return null; } // Confirmed if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition reader } return new DeletePackageAction(ps, disabledPs, outInfo, flags, user); } /* * This method handles package deletion in general */ private boolean deletePackageLIF(@NonNull String packageName, UserHandle user, boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags, PackageRemovedInfo outInfo, boolean writeSettings, ParsedPackage replacingPackage) { final DeletePackageAction action; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps); action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user); } if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); if (null == action) { if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: action was null"); return false; } try { executeDeletePackageLIF(action, packageName, deleteCodeAndResources, allUserHandles, writeSettings, replacingPackage); } catch (SystemDeleteException e) { if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e); return false; } return true; } private static class SystemDeleteException extends Exception { public final PackageManagerException reason; private SystemDeleteException(PackageManagerException reason) { this.reason = reason; } } /** Deletes a package. Only throws when install of a disabled package fails. */ private void executeDeletePackageLIF(DeletePackageAction action, String packageName, boolean deleteCodeAndResources, @NonNull int[] allUserHandles, boolean writeSettings, ParsedPackage replacingPackage) throws SystemDeleteException { final PackageSetting ps = action.deletingPs; final PackageRemovedInfo outInfo = action.outInfo; final UserHandle user = action.user; final int flags = action.flags; final boolean systemApp = isSystemApp(ps); // We need to get the permission state before package state is (potentially) destroyed. final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray(); for (int userId : allUserHandles) { hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId) == PERMISSION_GRANTED); } final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0) && userId != UserHandle.USER_ALL) { // The caller is asking that the package only be deleted for a single // user. To do this, we just mark its uninstalled state and delete // its data. If this is a system app, we only allow this to happen if // they have set the special DELETE_SYSTEM_APP which requests different // semantics than normal for uninstalling system apps. final boolean clearPackageStateAndReturn; synchronized (mLock) { markPackageUninstalledForUserLPw(ps, user); if (!systemApp) { // Do not uninstall the APK if an app should be cached boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName); if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) { // Other users still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users"); clearPackageStateAndReturn = true; } else { // We need to set it back to 'installed' so the uninstall // broadcasts will be sent correctly. if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete"); ps.setInstalled(true, userId); mSettings.writeKernelMappingLPr(ps); clearPackageStateAndReturn = false; } } else { // This is a system app, so we assume that the // other users still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app"); clearPackageStateAndReturn = true; } } if (clearPackageStateAndReturn) { clearPackageStateForUserLIF(ps, userId, outInfo, flags); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(user); } return; } } // TODO(b/109941548): break reasons for ret = false out into mayDelete method if (systemApp) { if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name); // When an updated system application is deleted we delete the existing resources // as well and fall back to existing code in system partition deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings); } else { if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name); deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles, outInfo, writeSettings); } // If the package removed had SUSPEND_APPS, unset any restrictions that might have been in // place for all affected users. int[] affectedUserIds = (outInfo != null) ? outInfo.removedUsers : null; if (affectedUserIds == null) { affectedUserIds = resolveUserIds(userId); } for (final int affectedUserId : affectedUserIds) { if (hadSuspendAppsPermission.get(affectedUserId)) { unsuspendForSuspendingPackage(packageName, affectedUserId); removeAllDistractingPackageRestrictions(affectedUserId); } } // Take a note whether we deleted the package for all users if (outInfo != null) { outInfo.removedForAllUsers = mPackages.get(ps.name) == null; } } @GuardedBy("mLock") private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) { final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] {user.getIdentifier()}; for (int nextUserId : userIds) { if (DEBUG_REMOVE) { Slog.d(TAG, "Marking package:" + ps.name + " uninstalled for user:" + nextUserId); } ps.setUserState(nextUserId, 0, COMPONENT_ENABLED_STATE_DEFAULT, false /*installed*/, true /*stopped*/, true /*notLaunched*/, false /*hidden*/, 0 /*distractionFlags*/, false /*suspended*/, null /*suspendParams*/, false /*instantApp*/, false /*virtualPreload*/, null /*lastDisableAppCaller*/, null /*enabledComponents*/, null /*disabledComponents*/, PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.UNINSTALL_REASON_UNKNOWN, null /*harmfulAppWarning*/, null /*splashScreenTheme*/); } mSettings.writeKernelMappingLPr(ps); } private void clearPackageStateForUserLIF(PackageSetting ps, int userId, PackageRemovedInfo outInfo, int flags) { final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(ps.name); } destroyAppProfilesLIF(pkg); final SharedUserSetting sus = ps.getSharedUser(); List sharedUserPkgs = sus != null ? sus.getPackages() : null; if (sharedUserPkgs == null) { sharedUserPkgs = Collections.emptyList(); } final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] {userId}; for (int nextUserId : userIds) { if (DEBUG_REMOVE) { Slog.d(TAG, "Updating package:" + ps.name + " install state for user:" + nextUserId); } if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { destroyAppDataLIF(pkg, nextUserId, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); } removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId); clearPackagePreferredActivities(ps.name, nextUserId); mDomainVerificationManager.clearPackageForUser(ps.name, nextUserId); } mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs, userId); if (outInfo != null) { if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { outInfo.dataRemoved = true; } outInfo.removedPackage = ps.name; outInfo.installerPackageName = ps.installSource.installerPackageName; outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null; outInfo.removedAppId = ps.appId; outInfo.removedUsers = userIds; outInfo.broadcastUsers = userIds; } } @Override public void clearApplicationProfileData(String packageName) { enforceSystemOrRoot("Only the system can clear all profile data"); final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationProfileData")) { synchronized (mInstallLock) { clearAppProfilesLIF(pkg, UserHandle.USER_ALL); } } } @Override public void clearApplicationUserData(final String packageName, final IPackageDataObserver observer, final int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_USER_DATA, null); final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "clear application data"); final boolean filterApp; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); filterApp = shouldFilterApplicationLocked(ps, callingUid, userId); } if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) { throw new SecurityException("Cannot clear data for a protected package: " + 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; if (!filterApp) { try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationUserData")) { synchronized (mInstallLock) { succeeded = clearApplicationUserDataLIF(packageName, userId); } synchronized (mLock) { mInstantAppRegistry.deleteInstantApplicationMetadataLPw( 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) { unsuspendForSuspendingPackage(packageName, userId); removeAllDistractingPackageRestrictions(userId); flushPackageRestrictionsAsUserInternalLocked(userId); } } } else { succeeded = false; } if (observer != null) { try { observer.onRemoveCompleted(packageName, succeeded); } catch (RemoteException e) { Log.i(TAG, "Observer no longer exists."); } } //end if observer } //end run }); } private boolean clearApplicationUserDataLIF(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; PackageSetting ps; synchronized (mLock) { pkg = mPackages.get(packageName); ps = mSettings.getPackageLPr(packageName); if (pkg == null) { if (ps != null) { pkg = ps.pkg; } } } if (pkg == null) { Slog.w(TAG, "Package named '" + packageName + "' doesn't exist."); return false; } mPermissionManager.resetRuntimePermissions(pkg, userId); clearAppDataLIF(pkg, userId, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); final int appId = UserHandle.getAppId(pkg.getUid()); removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); final int flags; if (StorageManager.isUserKeyUnlocked(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; } prepareAppDataContentsLIF(pkg, ps, userId, flags); return true; } private void resetNetworkPolicies(int userId) { mInjector.getLocalService(NetworkPolicyManagerInternal.class).resetUserState(userId); } /** * Remove entries from the keystore daemon. Will only remove it if the * {@code appId} is valid. */ private static void removeKeystoreDataIfNeeded(UserManagerInternal um, @UserIdInt int userId, @AppIdInt int appId) { if (appId < 0) { return; } final KeyStore keyStore = KeyStore.getInstance(); if (keyStore != null) { if (userId == UserHandle.USER_ALL) { for (final int individual : um.getUserIds()) { keyStore.clearUid(UserHandle.getUid(individual, appId)); } } else { keyStore.clearUid(UserHandle.getUid(userId, appId)); } } else { Slog.w(TAG, "Could not contact keystore to clear entries for app id " + appId); } } @Override public 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); } enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true, /* checkShell= */ false, "delete application cache files"); final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_INSTANT_APPS); final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } // Queue up an async operation since the package deletion may take a little while. mHandler.post(() -> { final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName()); boolean doClearData = true; if (ps != null) { final boolean targetIsInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); doClearData = !targetIsInstantApp || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED; } if (doClearData) { synchronized (mInstallLock) { final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL; // We're only clearing cache files, so we don't care if the // app is unfrozen and still able to run clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY); 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 getPackageSizeInfo(final String packageName, int userId, final IPackageStatsObserver observer) { throw new UnsupportedOperationException( "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!"); } @GuardedBy("mInstallLock") private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(packageName); if (ps == null) { Slog.w(TAG, "Failed to find settings for " + packageName); return false; } } final String[] packageNames = { packageName }; final long[] ceDataInodes = { ps.getCeDataInode(userId) }; final String[] codePaths = { ps.getPathString() }; try { mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0, ps.appId, ceDataInodes, codePaths, stats); // For now, ignore code size of packages on system partition if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) { stats.codeSize = 0; } // External clients expect these to be tracked separately stats.dataSize -= stats.cacheSize; } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); return false; } return true; } @GuardedBy("mLock") private int getUidTargetSdkVersionLockedLPr(int uid) { final int appId = UserHandle.getAppId(uid); final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; int vers = Build.VERSION_CODES.CUR_DEVELOPMENT; final int numPackages = sus.packages.size(); for (int index = 0; index < numPackages; index++) { final PackageSetting ps = sus.packages.valueAt(index); if (ps.pkg != null) { int v = ps.pkg.getTargetSdkVersion(); if (v < vers) vers = v; } } return vers; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (ps.pkg != null) { return ps.pkg.getTargetSdkVersion(); } } return Build.VERSION_CODES.CUR_DEVELOPMENT; } @GuardedBy("mLock") private int getPackageTargetSdkVersionLockedLPr(String packageName) { final AndroidPackage p = mPackages.get(packageName); if (p != null) { return p.getTargetSdkVersion(); } return Build.VERSION_CODES.CUR_DEVELOPMENT; } @Override public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) { addPreferredActivity(new WatchedIntentFilter(filter), match, set, activity, true, userId, "Adding preferred", removeExisting); } /** * Variant that takes a {@link WatchedIntentFilter} */ public void addPreferredActivity(WatchedIntentFilter filter, int match, ComponentName[] set, ComponentName activity, boolean always, int userId, String opname, boolean removeExisting) { // writer int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "add preferred activity"); if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { synchronized (mLock) { if (getUidTargetSdkVersionLockedLPr(callingUid) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring addPreferredActivity() from uid " + callingUid); return; } } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } if (filter.countActions() == 0) { Slog.w(TAG, "Cannot set a preferred activity with no filter actions"); return; } if (DEBUG_PREFERRED) { Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user " + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); } synchronized (mLock) { final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId); final ArrayList existing = pir.findFilters(filter); if (removeExisting && existing != null) { Settings.removeFilters(pir, filter, existing); } pir.addFilter(new PreferredActivity(filter, match, set, activity, always)); scheduleWritePackageRestrictionsLocked(userId); } if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(userId))) { postPreferredActivityChangedBroadcast(userId); } } private void postPreferredActivityChangedBroadcast(int userId) { mHandler.post(() -> { final IActivityManager am = ActivityManager.getService(); if (am == null) { return; } final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); try { am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false, userId); } catch (RemoteException e) { } }); } @Override public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId) { replacePreferredActivity(new WatchedIntentFilter(filter), match, set, activity, userId); } /** * Variant that takes a {@link WatchedIntentFilter} */ public void replacePreferredActivity(WatchedIntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId) { if (filter.countActions() != 1) { throw new IllegalArgumentException( "replacePreferredActivity expects filter to have only 1 action."); } if (filter.countDataAuthorities() != 0 || filter.countDataPaths() != 0 || filter.countDataSchemes() > 1 || filter.countDataTypes() != 0) { throw new IllegalArgumentException( "replacePreferredActivity expects filter to have no data authorities, " + "paths, or types; and at most one scheme."); } final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "replace preferred activity"); if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { synchronized (mLock) { if (getUidTargetSdkVersionLockedLPr(callingUid) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring replacePreferredActivity() from uid " + Binder.getCallingUid()); return; } } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } synchronized (mLock) { final PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); if (pir != null) { // Get all of the existing entries that exactly match this filter. final ArrayList existing = pir.findFilters(filter); if (existing != null && existing.size() == 1) { final PreferredActivity cur = existing.get(0); if (DEBUG_PREFERRED) { Slog.i(TAG, "Checking replace of preferred:"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); if (!cur.mPref.mAlways) { Slog.i(TAG, " -- CUR; not mAlways!"); } else { Slog.i(TAG, " -- CUR: mMatch=" + cur.mPref.mMatch); Slog.i(TAG, " -- CUR: mSet=" + Arrays.toString(cur.mPref.mSetComponents)); Slog.i(TAG, " -- CUR: mComponent=" + cur.mPref.mShortComponent); Slog.i(TAG, " -- NEW: mMatch=" + (match&IntentFilter.MATCH_CATEGORY_MASK)); Slog.i(TAG, " -- CUR: mSet=" + Arrays.toString(set)); Slog.i(TAG, " -- CUR: mComponent=" + activity.flattenToShortString()); } } if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity) && cur.mPref.mMatch == (match&IntentFilter.MATCH_CATEGORY_MASK) && cur.mPref.sameSet(set)) { // Setting the preferred activity to what it happens to be already if (DEBUG_PREFERRED) { Slog.i(TAG, "Replacing with same preferred activity " + cur.mPref.mShortComponent + " for user " + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); } return; } } if (existing != null) { Settings.removeFilters(pir, filter, existing); } } } addPreferredActivity(filter, match, set, activity, true, userId, "Replacing preferred", false); } @Override public void clearPackagePreferredActivities(String packageName) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return; } // writer synchronized (mLock) { AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || !isCallerSameApp(packageName, callingUid)) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { if (getUidTargetSdkVersionLockedLPr(callingUid) < Build.VERSION_CODES.FROYO) { Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid " + callingUid); return; } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } } final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null && shouldFilterApplicationLocked( ps, callingUid, UserHandle.getUserId(callingUid))) { return; } } int callingUserId = UserHandle.getCallingUserId(); clearPackagePreferredActivities(packageName, callingUserId); } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ private void clearPackagePreferredActivities(String packageName, int userId) { final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mLock) { clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId); } if (changedUsers.size() > 0) { updateDefaultHomeNotLocked(changedUsers); postPreferredActivityChangedBroadcast(userId); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } } /** This method takes a specific user id as well as UserHandle.USER_ALL. */ @GuardedBy("mLock") private void clearPackagePreferredActivitiesLPw(String packageName, @NonNull SparseBooleanArray outUserChanged, int userId) { mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId); } private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName, int installReason, @UserIdInt int userId) { // We may also need to apply pending (restored) runtime permission grants // within these users. mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId); // Persistent preferred activity might have came into effect due to this // install. updateDefaultHomeNotLocked(userId); } @Override public void resetApplicationPreferences(int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); final long identity = Binder.clearCallingIdentity(); // writer try { final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mLock) { clearPackagePreferredActivitiesLPw(null, changedUsers, userId); } if (changedUsers.size() > 0) { postPreferredActivityChangedBroadcast(userId); } synchronized (mLock) { mSettings.applyDefaultPreferredAppsLPw(userId); mDomainVerificationManager.clearUser(userId); final int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { final AndroidPackage pkg = mPackages.valueAt(i); mPermissionManager.resetRuntimePermissions(pkg, userId); } } updateDefaultHomeNotLocked(userId); resetNetworkPolicies(userId); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } finally { Binder.restoreCallingIdentity(identity); } } @Override public int getPreferredActivities(List outFilters, List outActivities, String packageName) { List temp = WatchedIntentFilter.toWatchedIntentFilterList(outFilters); final int result = getPreferredActivitiesInternal( temp, outActivities, packageName); outFilters.clear(); for (int i = 0; i < temp.size(); i++) { outFilters.add(temp.get(i).getIntentFilter()); } return result; } /** * Variant that takes a {@link WatchedIntentFilter} */ public int getPreferredActivitiesInternal(List outFilters, List outActivities, String packageName) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return 0; } int num = 0; final int userId = UserHandle.getCallingUserId(); // reader synchronized (mLock) { PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); if (pir != null) { final Iterator it = pir.filterIterator(); while (it.hasNext()) { final PreferredActivity pa = it.next(); final String prefPackageName = pa.mPref.mComponent.getPackageName(); if (packageName == null || (prefPackageName.equals(packageName) && pa.mPref.mAlways)) { if (shouldFilterApplicationLocked( mSettings.getPackageLPr(prefPackageName), callingUid, userId)) { continue; } if (outFilters != null) { outFilters.add(new WatchedIntentFilter(pa.getIntentFilter())); } if (outActivities != null) { outActivities.add(pa.mPref.mComponent); } } } } } return num; } @Override public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity, int userId) { addPersistentPreferredActivity(new WatchedIntentFilter(filter), activity, userId); } /** * Variant that takes a {@link WatchedIntentFilter} */ public void addPersistentPreferredActivity(WatchedIntentFilter filter, ComponentName activity, int userId) { int callingUid = Binder.getCallingUid(); if (callingUid != Process.SYSTEM_UID) { throw new SecurityException( "addPersistentPreferredActivity can only be run by the system"); } if (filter.countActions() == 0) { Slog.w(TAG, "Cannot set a preferred activity with no filter actions"); return; } if (DEBUG_PREFERRED) { Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); } synchronized (mLock) { mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter( new PersistentPreferredActivity(filter, activity, true)); scheduleWritePackageRestrictionsLocked(userId); } if (isHomeFilter(filter)) { updateDefaultHomeNotLocked(userId); } postPreferredActivityChangedBroadcast(userId); } @Override public void clearPackagePersistentPreferredActivities(String packageName, int userId) { int callingUid = Binder.getCallingUid(); if (callingUid != Process.SYSTEM_UID) { throw new SecurityException( "clearPackagePersistentPreferredActivities can only be run by the system"); } boolean changed = false; synchronized (mLock) { changed = mSettings.clearPackagePersistentPreferredActivities(packageName, userId); } if (changed) { updateDefaultHomeNotLocked(userId); postPreferredActivityChangedBroadcast(userId); synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); } } } /** * Common machinery for picking apart a restored XML blob and passing * it to a caller-supplied functor to be applied to the running system. */ private void restoreFromXml(TypedXmlPullParser parser, int userId, String expectedStartTag, BlobXmlRestorer functor) throws IOException, XmlPullParserException { int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { } if (type != XmlPullParser.START_TAG) { // oops didn't find a start tag?! if (DEBUG_BACKUP) { Slog.e(TAG, "Didn't find start tag during restore"); } return; } // this is supposed to be TAG_PREFERRED_BACKUP if (!expectedStartTag.equals(parser.getName())) { if (DEBUG_BACKUP) { Slog.e(TAG, "Found unexpected tag " + parser.getName()); } return; } // skip interfering stuff, then we're aligned with the backing implementation while ((type = parser.next()) == XmlPullParser.TEXT) { } functor.apply(parser, userId); } private interface BlobXmlRestorer { void apply(TypedXmlPullParser parser, int userId) throws IOException, XmlPullParserException; } /** * Non-Binder method, support for the backup/restore mechanism: write the * full set of preferred activities in its canonical XML format. Returns the * XML output as a byte array, or null if there is none. */ @Override public byte[] getPreferredActivityBackup(int userId) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system may call getPreferredActivityBackup()"); } ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); try { final TypedXmlSerializer serializer = Xml.newFastSerializer(); serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.startTag(null, TAG_PREFERRED_BACKUP); synchronized (mLock) { mSettings.writePreferredActivitiesLPr(serializer, userId, true); } serializer.endTag(null, TAG_PREFERRED_BACKUP); serializer.endDocument(); serializer.flush(); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Unable to write preferred activities for backup", e); } return null; } return dataStream.toByteArray(); } @Override public void restorePreferredActivities(byte[] backup, int userId) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system may call restorePreferredActivities()"); } try { final TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name()); restoreFromXml(parser, userId, TAG_PREFERRED_BACKUP, (readParser, readUserId) -> { synchronized (mLock) { mSettings.readPreferredActivitiesLPw(readParser, readUserId); } updateDefaultHomeNotLocked(readUserId); }); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage()); } } } /** * Non-Binder method, support for the backup/restore mechanism: write the * default browser (etc) settings in its canonical XML format. Returns the default * browser XML representation as a byte array, or null if there is none. */ @Override public byte[] getDefaultAppsBackup(int userId) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system may call getDefaultAppsBackup()"); } ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); try { final TypedXmlSerializer serializer = Xml.newFastSerializer(); serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); serializer.startTag(null, TAG_DEFAULT_APPS); synchronized (mLock) { mSettings.writeDefaultAppsLPr(serializer, userId); } serializer.endTag(null, TAG_DEFAULT_APPS); serializer.endDocument(); serializer.flush(); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Unable to write default apps for backup", e); } return null; } return dataStream.toByteArray(); } @Override public void restoreDefaultApps(byte[] backup, int userId) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system may call restoreDefaultApps()"); } try { final TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name()); restoreFromXml(parser, userId, TAG_DEFAULT_APPS, (parser1, userId1) -> { final String defaultBrowser; synchronized (mLock) { mSettings.readDefaultAppsLPw(parser1, userId1); defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1); } if (defaultBrowser != null) { mDefaultAppProvider.setDefaultBrowser(defaultBrowser, false, userId1); } }); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Exception restoring default apps: " + e.getMessage()); } } } @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(serializer, true, userId); return output.toByteArray(); } } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Unable to write domain verification for backup", e); } return null; } } @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(parser); input.close(); } catch (Exception e) { if (DEBUG_BACKUP) { Slog.e(TAG, "Exception restoring domain verification: " + e.getMessage()); } } } @Override public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage, int sourceUserId, int targetUserId, int flags) { addCrossProfileIntentFilter(new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId, flags); } /** * Variant that takes a {@link WatchedIntentFilter} */ public void addCrossProfileIntentFilter(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(ownerPackage, callingUid); PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); 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); CrossProfileIntentResolver resolver = mSettings.editCrossProfileIntentResolverLPw(sourceUserId); ArrayList 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(newFilter); scheduleWritePackageRestrictionsLocked(sourceUserId); } } @Override public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); final int callingUid = Binder.getCallingUid(); enforceOwnerRights(ownerPackage, callingUid); PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(), UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId); synchronized (mLock) { CrossProfileIntentResolver resolver = mSettings.editCrossProfileIntentResolverLPw(sourceUserId); ArraySet set = new ArraySet<>(resolver.filterSet()); for (CrossProfileIntentFilter filter : set) { if (filter.getOwnerPackage().equals(ownerPackage)) { resolver.removeFilter(filter); } } scheduleWritePackageRestrictionsLocked(sourceUserId); } } // Enforcing that callingUid is owning pkg on userId private void enforceOwnerRights(String pkg, int callingUid) { // The system owns everything. if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { return; } final String[] callerPackageNames = 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 = getPackageInfo(pkg, 0, callingUserId); if (pi == null) { throw new IllegalArgumentException("Unknown package " + pkg + " on user " + callingUserId); } } @Override public ComponentName getHomeActivities(List allHomeCandidates) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId()); } /** * Send a {@code PackageInstaller.ACTION_SESSION_UPDATED} broadcast intent, containing * the {@code sessionInfo} in the extra field {@code PackageInstaller.EXTRA_SESSION}. */ public void sendSessionUpdatedBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) { if (TextUtils.isEmpty(sessionInfo.installerPackageName)) { return; } Intent sessionUpdatedIntent = new Intent(PackageInstaller.ACTION_SESSION_UPDATED) .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) .setPackage(sessionInfo.installerPackageName); mContext.sendBroadcastAsUser(sessionUpdatedIntent, UserHandle.of(userId)); } public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) { UserManagerService ums = UserManagerService.getInstance(); if (ums != null && !sessionInfo.isStaged()) { final UserInfo parent = ums.getProfileParent(userId); final int launcherUid = (parent != null) ? parent.id : userId; final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid); if (launcherComponent != null) { Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) .setPackage(launcherComponent.getPackageName()); mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid)); } // TODO(b/122900055) Change/Remove this and replace with new permission role. if (mAppPredictionServicePackage != null) { Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) .setPackage(mAppPredictionServicePackage); mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid)); } } } /** * Report the 'Home' activity which is currently set as "always use this one". If non is set * then reports the most likely home activity or null if there are more than one. */ private ComponentName getDefaultHomeActivity(int userId) { return mComputer.getDefaultHomeActivity(userId); } private Intent getHomeIntent() { return mComputer.getHomeIntent(); } private WatchedIntentFilter getHomeFilter() { WatchedIntentFilter filter = new WatchedIntentFilter(Intent.ACTION_MAIN); filter.addCategory(Intent.CATEGORY_HOME); filter.addCategory(Intent.CATEGORY_DEFAULT); return filter; } private boolean isHomeFilter(@NonNull WatchedIntentFilter filter) { return filter.hasAction(Intent.ACTION_MAIN) && filter.hasCategory(Intent.CATEGORY_HOME) && filter.hasCategory(CATEGORY_DEFAULT); } ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId) { return mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId); } /** must not hold {@link #mLock} */ private void updateDefaultHomeNotLocked(SparseBooleanArray userIds) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mLock", new Throwable()); } for (int i = userIds.size() - 1; i >= 0; --i) { final int userId = userIds.keyAt(i); updateDefaultHomeNotLocked(userId); } } /** * must not hold {@link #mLock} * * @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled. */ private boolean updateDefaultHomeNotLocked(int userId) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mLock", new Throwable()); } if (!mSystemReady) { // We might get called before system is ready because of package changes etc, but // finding preferred activity depends on settings provider, so we ignore the update // before that. return false; } final Intent intent = getHomeIntent(); final List resolveInfos = queryIntentActivitiesInternal(intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( intent, null, 0, resolveInfos, 0, true, false, false, userId); final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; final String currentPackageName = mDefaultAppProvider.getDefaultHome(userId); if (TextUtils.equals(currentPackageName, packageName)) { return false; } final String[] callingPackages = getPackagesForUid(Binder.getCallingUid()); if (callingPackages != null && ArrayUtils.contains(callingPackages, mRequiredPermissionControllerPackage)) { // PermissionController manages default home directly. return false; } if (packageName == null) { // Keep the default home package in RoleManager. return false; } return mDefaultAppProvider.setDefaultHome(packageName, userId, mContext.getMainExecutor(), successful -> { if (successful) { postPreferredActivityChangedBroadcast(userId); } }); } @Override public void setHomeActivity(ComponentName comp, int userId) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } ArrayList homeActivities = new ArrayList<>(); getHomeActivitiesAsUser(homeActivities, userId); boolean found = false; final int size = homeActivities.size(); final ComponentName[] set = new ComponentName[size]; for (int i = 0; i < size; i++) { final ResolveInfo candidate = homeActivities.get(i); final ActivityInfo info = candidate.activityInfo; final ComponentName activityName = new ComponentName(info.packageName, info.name); set[i] = activityName; if (!found && activityName.equals(comp)) { found = true; } } if (!found) { throw new IllegalArgumentException("Component " + comp + " cannot be home on user " + userId); } replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY, set, comp, userId); } private @Nullable String getSetupWizardPackageNameImpl() { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); final List matches = 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() { final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); final List matches = 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; } } @Override public String getDefaultTextClassifierPackageName() { return ensureSystemPackageName( mContext.getString(R.string.config_servicesExtensionPackage)); } @Override public String getSystemTextClassifierPackageName() { return ensureSystemPackageName( mContext.getString(R.string.config_defaultTextClassifierPackage)); } @Override public @Nullable String getAttentionServicePackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_defaultAttentionService)); } @Override public @Nullable String getRotationResolverPackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_defaultRotationResolverService)); } private @Nullable String getDocumenterPackageName() { final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver()); final List matches = queryIntentActivitiesInternal(intent, resolvedType, 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 documenter; found " + matches.size() + ": matches=" + matches); return null; } } @Nullable private String getDeviceConfiguratorPackageName() { return ensureSystemPackageName(mContext.getString( R.string.config_deviceConfiguratorPackageName)); } @Override public String getWellbeingPackageName() { final long identity = Binder.clearCallingIdentity(); try { return CollectionUtils.firstOrNull( mContext.getSystemService(RoleManager.class).getRoleHolders( RoleManager.ROLE_SYSTEM_WELLBEING)); } finally { Binder.restoreCallingIdentity(identity); } } @Override public String getAppPredictionServicePackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_defaultAppPredictionService)); } @Override public String getSystemCaptionsServicePackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_defaultSystemCaptionsService)); } @Override public String getSetupWizardPackageName() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Non-system caller"); } return mPmInternal.getSetupWizardPackageName(); } public String getIncidentReportApproverPackageName() { return ensureSystemPackageName(mContext.getString( R.string.config_incidentReportApproverPackage)); } @Override public String getContentCaptureServicePackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_defaultContentCaptureService)); } public String getOverlayConfigSignaturePackageName() { return ensureSystemPackageName(mInjector.getSystemConfig() .getOverlayConfigSignaturePackage()); } @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.signatures != null) { try { final MessageDigest msgDigest = MessageDigest.getInstance("SHA-256"); for (Signature signature : signingDetail.signatures) { 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 private String getRecentsPackageName() { return ensureSystemPackageName( getPackageFromComponentString(R.string.config_recentsComponentName)); } @Nullable private 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 private String ensureSystemPackageName(@Nullable String packageName) { if (packageName == null) { return null; } final long token = Binder.clearCallingIdentity(); try { if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM); if (packageInfo != null) { EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid, ""); } return null; } } finally { Binder.restoreCallingIdentity(token); } return packageName; } @Nullable private String[] ensureSystemPackageNames(@Nullable String[] packageNames) { if (packageNames == null) { return null; } final int packageNamesLength = packageNames.length; for (int i = 0; i < packageNamesLength; i++) { packageNames[i] = ensureSystemPackageName(packageNames[i]); } return ArrayUtils.filterNotNull(packageNames, String[]::new); } @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()); } setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage); } @Override public void setUpdateAvailable(String packageName, boolean updateAvailable) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); synchronized (mLock) { final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting != null) { pkgSetting.setUpdateAvailable(updateAvailable); } } } @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 void restoreLabelAndIcon(@NonNull ComponentName componentName, int userId) { updateComponentLabelIcon(componentName, null, null, userId); } @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(); int componentUid = 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 = 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"); } synchronized (mLock) { AndroidPackage pkg = mPackages.get(componentPkgName); PackageSetting pkgSetting = getPackageSetting(componentPkgName); if (pkg == null || pkgSetting == null || (!pkg.isSystem() && !pkgSetting.getPkgState().isUpdatedSystemApp())) { throw new SecurityException( "Changing the label is not allowed for " + componentName); } if (!mComponentResolver.componentExists(componentName)) { throw new IllegalArgumentException("Component " + componentName + " not found"); } if (!pkgSetting.overrideNonLocalizedLabelAndIcon(componentName, nonLocalizedLabel, icon, userId)) { // Nothing changed return; } } ArrayList components = mPendingBroadcasts.get(userId, componentPkgName); if (components == null) { components = new ArrayList<>(); mPendingBroadcasts.put(userId, componentPkgName, components); } String className = componentName.getClassName(); if (!components.contains(className)) { components.add(className); } if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); } } @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { if (!mUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags, userId, null); } private void setEnabledSetting(final String packageName, String className, int newState, final int flags, int userId, String callingPackage) { 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); } PackageSetting pkgSetting; final int callingUid = Binder.getCallingUid(); final int permission; if (callingUid == Process.SYSTEM_UID) { permission = PackageManager.PERMISSION_GRANTED; } else { permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); } enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, true /* checkShell */, "set enabled"); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); boolean sendNow = false; boolean isApp = (className == null); final boolean isCallerInstantApp = (getInstantAppPackageName(callingUid) != null); String componentName = isApp ? packageName : className; ArrayList components; // reader synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(packageName); if (pkgSetting == null) { if (!isCallerInstantApp) { if (className == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } throw new IllegalArgumentException( "Unknown component: " + packageName + "/" + className); } else { // throw SecurityException to prevent leaking package information throw new SecurityException( "Attempt to change component state; " + "pid=" + Binder.getCallingPid() + ", uid=" + callingUid + (className == null ? ", package=" + packageName : ", component=" + packageName + "/" + className)); } } } // Limit who can change which apps if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) { // Don't allow apps that don't have permission to modify other apps final boolean filterApp; synchronized (mLock) { filterApp = (!allowedByPermission || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)); } if (filterApp) { throw new SecurityException( "Attempt to change component state; " + "pid=" + Binder.getCallingPid() + ", uid=" + callingUid + (className == null ? ", package=" + packageName : ", component=" + packageName + "/" + className)); } // Don't allow changing protected packages. if (mProtectedPackages.isPackageStateProtected(userId, packageName)) { throw new SecurityException("Cannot disable a protected package: " + packageName); } } // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden // app details activity if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className) && !allowedByPermission) { throw new SecurityException("Cannot disable a system-generated component"); } synchronized (mLock) { if (callingUid == Process.SHELL_UID && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { // Shell can only change whole packages between ENABLED and DISABLED_USER states // unless it is a test package. int oldState = pkgSetting.getEnabled(userId); if (className == null && (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 " + packageName + "/" + className + " to " + newState); } } } if (className == null) { // We're dealing with an application/package level state change synchronized (mLock) { if (pkgSetting.getEnabled(userId) == newState) { // Nothing to do return; } } // 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.pkg; final boolean isSystemStub = (deletedPkg != null) && deletedPkg.isStub() && deletedPkg.isSystem(); if (isSystemStub && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { if (!enableCompressedPackage(deletedPkg, pkgSetting)) { return; } } if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { // Don't care about who enables an app. callingPackage = null; } synchronized (mLock) { 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(packageName, userId); removeAllDistractingPackageRestrictions(userId); } } } else { synchronized (mLock) { // We're dealing with a component level state change // First, verify that this is a valid class name. AndroidPackage pkg = pkgSetting.pkg; 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); } } switch (newState) { case COMPONENT_ENABLED_STATE_ENABLED: if (!pkgSetting.enableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DISABLED: if (!pkgSetting.disableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DEFAULT: if (!pkgSetting.restoreComponentLPw(className, userId)) { return; } break; default: Slog.e(TAG, "Invalid new component state: " + newState); return; } } } synchronized (mLock) { if ((flags & PackageManager.SYNCHRONOUS) != 0) { flushPackageRestrictionsAsUserInternalLocked(userId); } else { scheduleWritePackageRestrictionsLocked(userId); } updateSequenceNumberLP(pkgSetting, new int[] { userId }); final long callingId = Binder.clearCallingIdentity(); try { updateInstantAppInstallerLocked(packageName); } finally { Binder.restoreCallingIdentity(callingId); } components = mPendingBroadcasts.get(userId, packageName); final boolean newPackage = components == null; if (newPackage) { components = new ArrayList<>(); } if (!components.contains(componentName)) { components.add(componentName); } if ((flags&PackageManager.DONT_KILL_APP) == 0) { sendNow = true; // Purge entry from pending broadcast list if another one exists already // since we are sending one right away. mPendingBroadcasts.remove(userId, packageName); } else { if (newPackage) { mPendingBroadcasts.put(userId, packageName, components); } 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 { if (sendNow) { int packageUid = UserHandle.getUid(userId, pkgSetting.appId); sendPackageChangedBroadcast(packageName, (flags & PackageManager.DONT_KILL_APP) != 0, components, packageUid, null); } } finally { Binder.restoreCallingIdentity(callingId); } } @WorkerThread @Override public void flushPackageRestrictionsAsUser(int userId) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } if (!mUserManager.exists(userId)) { return; } enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/, false /* checkShell */, "flushPackageRestrictions"); synchronized (mLock) { flushPackageRestrictionsAsUserInternalLocked(userId); } } @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); mDirtyUsers.remove(userId); if (mDirtyUsers.isEmpty()) { mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS); } } private void sendPackageChangedBroadcast(String packageName, boolean dontKillApp, ArrayList componentNames, int packageUid, String reason) { if (DEBUG_INSTALL) Log.v(TAG, "Sending package changed: package=" + packageName + " components=" + componentNames); Bundle extras = new Bundle(4); extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); String nameList[] = new String[componentNames.size()]; componentNames.toArray(nameList); extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp); extras.putInt(Intent.EXTRA_UID, packageUid); if (reason != null) { extras.putString(Intent.EXTRA_REASON, reason); } // If this is not reporting a change of the overall package, then only send it // to registered receivers. We don't want to launch a swath of apps for every // little component state change. final int flags = !componentNames.contains(packageName) ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0; final int userId = UserHandle.getUserId(packageUid); final boolean isInstantApp = isInstantApp(packageName, userId); final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId }; final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; final SparseArray broadcastAllowList; synchronized (mLock) { PackageSetting setting = getPackageSettingInternal(packageName, Process.SYSTEM_UID); if (setting == null) { return; } broadcastAllowList = isInstantApp ? null : mAppsFilter.getVisibilityAllowList(setting, userIds, mSettings.getPackagesLocked()); } sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null, userIds, instantUserIds, broadcastAllowList, null); } @Override public void setPackageStoppedState(String packageName, boolean stopped, int userId) { if (!mUserManager.exists(userId)) return; final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return; } final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); if (!allowedByPermission && !ArrayUtils.contains(getPackagesForUid(callingUid), packageName)) { throw new SecurityException( "Permission Denial: attempt to change stopped state from pid=" + Binder.getCallingPid() + ", uid=" + callingUid + ", package=" + packageName); } enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "stop package"); // writer synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (!shouldFilterApplicationLocked(ps, callingUid, userId) && mSettings.setPackageStoppedStateLPw(this, packageName, stopped, userId)) { scheduleWritePackageRestrictionsLocked(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); } }); } } @Override public String getInstallerPackageName(String packageName) { final int callingUid = Binder.getCallingUid(); synchronized (mLock) { final InstallSource installSource = getInstallSourceLocked(packageName, callingUid); if (installSource == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } String installerPackageName = installSource.installerPackageName; if (installerPackageName != null) { final PackageSetting ps = mSettings.getPackageLPr(installerPackageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) { installerPackageName = null; } } return installerPackageName; } } @Override @Nullable public InstallSourceInfo getInstallSourceInfo(String packageName) { final int callingUid = Binder.getCallingUid(); final int userId = UserHandle.getUserId(callingUid); String installerPackageName; String initiatingPackageName; String originatingPackageName; final InstallSource installSource; synchronized (mLock) { installSource = getInstallSourceLocked(packageName, callingUid); if (installSource == null) { return null; } installerPackageName = installSource.installerPackageName; if (installerPackageName != null) { final PackageSetting ps = mSettings.getPackageLPr(installerPackageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) { installerPackageName = null; } } if (installSource.isInitiatingPackageUninstalled) { // We can't check visibility in the usual way, since the initiating package is no // longer present. So we apply simpler rules to whether to expose the info: // 1. Instant apps can't see it. // 2. Otherwise only the installed app itself can see it. final boolean isInstantApp = getInstantAppPackageName(callingUid) != null; if (!isInstantApp && isCallerSameApp(packageName, callingUid)) { initiatingPackageName = installSource.initiatingPackageName; } else { initiatingPackageName = null; } } else { // All installSource strings are interned, so == is ok here if (installSource.initiatingPackageName == installSource.installerPackageName) { // The installer and initiator will often be the same, and when they are // we can skip doing the same check again. initiatingPackageName = installerPackageName; } else { initiatingPackageName = installSource.initiatingPackageName; final PackageSetting ps = mSettings.getPackageLPr(initiatingPackageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) { initiatingPackageName = null; } } } originatingPackageName = installSource.originatingPackageName; if (originatingPackageName != null) { final PackageSetting ps = mSettings.getPackageLPr(originatingPackageName); if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) { originatingPackageName = null; } } } // Remaining work can safely be done outside the lock. (Note that installSource is // immutable so it's ok to carry on reading from it.) if (originatingPackageName != null && mContext.checkCallingOrSelfPermission( Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) { originatingPackageName = null; } // If you can see the initiatingPackageName, and we have valid signing info for it, // then we let you see that too. final SigningInfo initiatingPackageSigningInfo; final PackageSignatures signatures = installSource.initiatingPackageSignatures; if (initiatingPackageName != null && signatures != null && signatures.mSigningDetails != SigningDetails.UNKNOWN) { initiatingPackageSigningInfo = new SigningInfo(signatures.mSigningDetails); } else { initiatingPackageSigningInfo = null; } return new InstallSourceInfo(initiatingPackageName, initiatingPackageSigningInfo, originatingPackageName, installerPackageName); } @GuardedBy("mLock") @Nullable private InstallSource getInstallSourceLocked(String packageName, int callingUid) { final PackageSetting ps = mSettings.getPackageLPr(packageName); // Installer info for Apex is not stored in PackageManager if (ps == null && mApexManager.isApexPackage(packageName)) { return InstallSource.EMPTY; } if (ps == null || shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) { return null; } return ps.installSource; } public boolean isOrphaned(String packageName) { // reader synchronized (mLock) { if (!mPackages.containsKey(packageName)) { return false; } return mSettings.isOrphaned(packageName); } } @Override public int getApplicationEnabledSetting(String packageName, int userId) { if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get enabled"); // reader synchronized (mLock) { try { if (shouldFilterApplicationLocked( mSettings.getPackageLPr(packageName), callingUid, userId)) { throw new PackageManager.NameNotFoundException(packageName); } return mSettings.getApplicationEnabledSettingLPr(packageName, userId); } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException("Unknown package: " + packageName); } } } @Override public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) { int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled"); return getComponentEnabledSettingInternal(component, callingUid, userId); } private int getComponentEnabledSettingInternal(ComponentName component, int callingUid, int userId) { if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT; if (!mUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; synchronized (mLock) { try { if (shouldFilterApplicationLocked( mSettings.getPackageLPr(component.getPackageName()), callingUid, component, TYPE_UNKNOWN, userId)) { throw new PackageManager.NameNotFoundException(component.getPackageName()); } return mSettings.getComponentEnabledSettingLPr(component, userId); } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException("Unknown component: " + component); } } } /** * @return true if the runtime app user enabled state, runtime component user enabled state, * install-time app manifest enabled state, and install-time component manifest enabled state * are all effectively enabled for the given component. Or if the component cannot be found, * returns false. */ private boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo, @UserIdInt int userId) { synchronized (mLock) { try { String packageName = componentInfo.packageName; int appEnabledSetting = mSettings.getApplicationEnabledSettingLPr(packageName, userId); if (appEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) { if (!componentInfo.applicationInfo.enabled) { return false; } } else if (appEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) { return false; } int componentEnabledSetting = mSettings.getComponentEnabledSettingLPr( componentInfo.getComponentName(), userId); if (componentEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) { return componentInfo.isEnabled(); } else if (componentEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) { return false; } return true; } catch (PackageManager.NameNotFoundException ignored) { return false; } } } @Override public void enterSafeMode() { enforceSystemOrRoot("Only the system can request entering safe mode"); if (!mSystemReady) { mSafeMode = true; } } @Override public void systemReady() { 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(); // 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; PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled); if (DEBUG_SETTINGS) { Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled); } synchronized (mLock) { ArrayList 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(mStorageListener); mInstallerService.systemReady(); mPackageDexOptimizer.systemReady(); // Now that we're mostly running, clean up stale users and apps mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL); mPermissionManager.onSystemReady(); int[] grantPermissionsUserIds = EMPTY_INT_ARRAY; final List 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; if (mPmInternal.isPermissionUpgradeNeeded(userId)) { grantPermissionsUserIds = ArrayUtils.appendInt( grantPermissionsUserIds, userId); } } // If we upgraded grant all default permissions before kicking off. for (int userId : grantPermissionsUserIds) { mLegacyPermissionManager.grantDefaultPermissions(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; } AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { return; } sendPackageChangedBroadcast(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 keyset = properties.getKeyset(); if (keyset.contains(PROPERTY_INCFS_DEFAULT_TIMEOUTS) || keyset.contains( PROPERTY_KNOWN_DIGESTERS_LIST)) { mPerUidReadTimeoutsCache = null; } }); } public void waitForAppDataPrepared() { if (mPrepareAppDataFuture == null) { return; } ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData"); mPrepareAppDataFuture = null; } @Override public boolean isSafeMode() { // allow instant applications return mSafeMode; } @Override public boolean hasSystemUidErrors() { // allow instant applications return mHasSystemUidErrors; } static String arrayToString(int[] array) { StringBuilder stringBuilder = new StringBuilder(128); stringBuilder.append('['); if (array != null) { for (int i=0; i 0) stringBuilder.append(", "); stringBuilder.append(array[i]); } } stringBuilder.append(']'); return stringBuilder.toString(); } @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; DumpState dumpState = new DumpState(); ArraySet permissionNames = null; int opti = 0; while (opti < args.length) { String opt = args[opti]; if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { break; } opti++; if ("-a".equals(opt)) { // Right now we only know how to print all. } else if ("-h".equals(opt)) { pw.println("Package manager dump options:"); pw.println(" [-h] [-f] [--checkin] [--all-components] [cmd] ..."); pw.println(" --checkin: dump for a checkin"); pw.println(" -f: print details of intent filters"); pw.println(" -h: print this help"); pw.println(" --all-components: include all component names in package dump"); pw.println(" cmd may be one of:"); pw.println(" apex: list active APEXes and APEX session state"); pw.println(" l[ibraries]: list known shared libraries"); pw.println(" f[eatures]: list device features"); pw.println(" k[eysets]: print known keysets"); pw.println(" r[esolvers] [activity|service|receiver|content]: dump intent resolvers"); pw.println(" perm[issions]: dump permissions"); pw.println(" permission [name ...]: dump declaration and use of given permission"); pw.println(" pref[erred]: print preferred package settings"); pw.println(" preferred-xml [--full]: print preferred package settings as xml"); pw.println(" prov[iders]: dump content providers"); pw.println(" p[ackages]: dump installed packages"); pw.println(" q[ueries]: dump app queryability calculations"); pw.println(" s[hared-users]: dump shared user IDs"); pw.println(" m[essages]: print collected runtime messages"); pw.println(" v[erifiers]: print package verifier info"); pw.println(" d[omain-preferred-apps]: print domains preferred apps"); pw.println(" i[ntent-filter-verifiers]|ifv: print intent filter verifier info"); pw.println(" t[imeouts]: print read timeouts for known digesters"); pw.println(" version: print database version info"); pw.println(" write: write current settings now"); pw.println(" installs: details about install sessions"); pw.println(" check-permission []: does pkg hold perm?"); pw.println(" dexopt: dump dexopt state"); pw.println(" compiler-stats: dump compiler statistics"); pw.println(" service-permissions: dump permissions required by services"); pw.println(" snapshot: dump snapshot statistics"); pw.println(" known-packages: dump known packages"); pw.println(" : info about given package"); return; } else if ("--checkin".equals(opt)) { dumpState.setCheckIn(true); } else if ("--all-components".equals(opt)) { dumpState.setOptionEnabled(DumpState.OPTION_DUMP_ALL_COMPONENTS); } else if ("-f".equals(opt)) { dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS); } else if ("--proto".equals(opt)) { dumpProto(fd); return; } else { pw.println("Unknown argument: " + opt + "; use -h for help"); } } // Is the caller requesting to dump a particular piece of data? if (opti < args.length) { String cmd = args[opti]; opti++; // Is this a package name? if ("android".equals(cmd) || cmd.contains(".")) { dumpState.setTargetPackageName(cmd); // When dumping a single package, we always dump all of its // filter information since the amount of data will be reasonable. dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS); } else if ("check-permission".equals(cmd)) { if (opti >= args.length) { pw.println("Error: check-permission missing permission argument"); return; } String perm = args[opti]; opti++; if (opti >= args.length) { pw.println("Error: check-permission missing package argument"); return; } String pkg = args[opti]; opti++; int user = UserHandle.getUserId(Binder.getCallingUid()); if (opti < args.length) { try { user = Integer.parseInt(args[opti]); } catch (NumberFormatException e) { pw.println("Error: check-permission user argument is not a number: " + args[opti]); return; } } // Normalize package name to handle renamed packages and static libs pkg = resolveInternalPackageNameLPr(pkg, PackageManager.VERSION_CODE_HIGHEST); pw.println(checkPermission(perm, pkg, user)); return; } else if ("l".equals(cmd) || "libraries".equals(cmd)) { dumpState.setDump(DumpState.DUMP_LIBS); } else if ("f".equals(cmd) || "features".equals(cmd)) { dumpState.setDump(DumpState.DUMP_FEATURES); } else if ("r".equals(cmd) || "resolvers".equals(cmd)) { if (opti >= args.length) { dumpState.setDump(DumpState.DUMP_ACTIVITY_RESOLVERS | DumpState.DUMP_SERVICE_RESOLVERS | DumpState.DUMP_RECEIVER_RESOLVERS | DumpState.DUMP_CONTENT_RESOLVERS); } else { while (opti < args.length) { String name = args[opti]; if ("a".equals(name) || "activity".equals(name)) { dumpState.setDump(DumpState.DUMP_ACTIVITY_RESOLVERS); } else if ("s".equals(name) || "service".equals(name)) { dumpState.setDump(DumpState.DUMP_SERVICE_RESOLVERS); } else if ("r".equals(name) || "receiver".equals(name)) { dumpState.setDump(DumpState.DUMP_RECEIVER_RESOLVERS); } else if ("c".equals(name) || "content".equals(name)) { dumpState.setDump(DumpState.DUMP_CONTENT_RESOLVERS); } else { pw.println("Error: unknown resolver table type: " + name); return; } opti++; } } } else if ("perm".equals(cmd) || "permissions".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PERMISSIONS); } else if ("permission".equals(cmd)) { if (opti >= args.length) { pw.println("Error: permission requires permission name"); return; } permissionNames = new ArraySet<>(); while (opti < args.length) { permissionNames.add(args[opti]); opti++; } dumpState.setDump(DumpState.DUMP_PERMISSIONS | DumpState.DUMP_PACKAGES | DumpState.DUMP_SHARED_USERS); } else if ("pref".equals(cmd) || "preferred".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PREFERRED); } else if ("preferred-xml".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PREFERRED_XML); if (opti < args.length && "--full".equals(args[opti])) { dumpState.setFullPreferred(true); opti++; } } else if ("d".equals(cmd) || "domain-preferred-apps".equals(cmd)) { dumpState.setDump(DumpState.DUMP_DOMAIN_PREFERRED); } else if ("p".equals(cmd) || "packages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PACKAGES); } else if ("q".equals(cmd) || "queries".equals(cmd)) { dumpState.setDump(DumpState.DUMP_QUERIES); } else if ("s".equals(cmd) || "shared-users".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SHARED_USERS); if (opti < args.length && "noperm".equals(args[opti])) { dumpState.setOptionEnabled(DumpState.OPTION_SKIP_PERMISSIONS); } } else if ("prov".equals(cmd) || "providers".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PROVIDERS); } else if ("m".equals(cmd) || "messages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_MESSAGES); } else if ("v".equals(cmd) || "verifiers".equals(cmd)) { dumpState.setDump(DumpState.DUMP_VERIFIERS); } else if ("dv".equals(cmd) || "domain-verifier".equals(cmd)) { dumpState.setDump(DumpState.DUMP_DOMAIN_VERIFIER); } else if ("version".equals(cmd)) { dumpState.setDump(DumpState.DUMP_VERSION); } else if ("k".equals(cmd) || "keysets".equals(cmd)) { dumpState.setDump(DumpState.DUMP_KEYSETS); } else if ("installs".equals(cmd)) { dumpState.setDump(DumpState.DUMP_INSTALLS); } else if ("frozen".equals(cmd)) { dumpState.setDump(DumpState.DUMP_FROZEN); } else if ("volumes".equals(cmd)) { dumpState.setDump(DumpState.DUMP_VOLUMES); } else if ("dexopt".equals(cmd)) { dumpState.setDump(DumpState.DUMP_DEXOPT); } else if ("compiler-stats".equals(cmd)) { dumpState.setDump(DumpState.DUMP_COMPILER_STATS); } else if ("changes".equals(cmd)) { dumpState.setDump(DumpState.DUMP_CHANGES); } else if ("service-permissions".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS); } else if ("known-packages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_KNOWN_PACKAGES); } else if ("t".equals(cmd) || "timeouts".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PER_UID_READ_TIMEOUTS); } else if ("snapshot".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SNAPSHOT_STATISTICS); if (opti < args.length) { if ("--full".equals(args[opti])) { dumpState.setBrief(false); opti++; } else if ("--brief".equals(args[opti])) { dumpState.setBrief(true); opti++; } } } else if ("write".equals(cmd)) { synchronized (mLock) { writeSettingsLPrTEMP(); pw.println("Settings written."); return; } } } final String packageName = dumpState.getTargetPackageName(); final boolean checkin = dumpState.isCheckIn(); if (checkin) { pw.println("vers,1"); } // reader if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) { if (!checkin) { dump(DumpState.DUMP_VERSION, fd, pw, dumpState); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_KNOWN_PACKAGES) && packageName == null) { if (dumpState.onTitlePrinted()) { pw.println(); } final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); ipw.println("Known Packages:"); ipw.increaseIndent(); for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) { final String knownPackage = mPmInternal.knownPackageToString(i); ipw.print(knownPackage); ipw.println(":"); final String[] pkgNames = mPmInternal.getKnownPackageNames(i, UserHandle.USER_SYSTEM); ipw.increaseIndent(); if (ArrayUtils.isEmpty(pkgNames)) { ipw.println("none"); } else { for (String name : pkgNames) { ipw.println(name); } } ipw.decreaseIndent(); } ipw.decreaseIndent(); } if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) { final String requiredVerifierPackage = mRequiredVerifierPackage; if (!checkin) { if (dumpState.onTitlePrinted()) { pw.println(); } pw.println("Verifiers:"); pw.print(" Required: "); pw.print(requiredVerifierPackage); pw.print(" (uid="); pw.print(getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); pw.println(")"); } else if (requiredVerifierPackage != null) { pw.print("vrfy,"); pw.print(requiredVerifierPackage); pw.print(","); pw.println(getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); } } if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) { final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy(); final ComponentName verifierComponent = proxy.getComponentName(); if (verifierComponent != null) { String verifierPackageName = verifierComponent.getPackageName(); if (!checkin) { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Domain Verifier:"); pw.print(" Using: "); pw.print(verifierPackageName); pw.print(" (uid="); pw.print(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); pw.println(")"); } else if (verifierPackageName != null) { pw.print("dv,"); pw.print(verifierPackageName); pw.print(","); pw.println(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); } } else { pw.println(); pw.println("No Domain Verifier available!"); } } if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) { dump(DumpState.DUMP_LIBS, fd, pw, dumpState); } if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) { if (dumpState.onTitlePrinted()) { pw.println(); } if (!checkin) { pw.println("Features:"); } synchronized (mAvailableFeatures) { for (FeatureInfo feat : mAvailableFeatures.values()) { if (checkin) { pw.print("feat,"); pw.print(feat.name); pw.print(","); pw.println(feat.version); } else { pw.print(" "); pw.print(feat.name); if (feat.version > 0) { pw.print(" version="); pw.print(feat.version); } pw.println(); } } } } if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) { dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) { dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { synchronized (mLock) { mComponentResolver.dumpContentProviders(pw, dumpState, packageName); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) { synchronized (mLock) { mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState); } } if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) { // This cannot be moved to ComputerEngine since some variables of the collections // in PackageUserState such as suspendParams, disabledComponents and enabledComponents // do not have a copy. synchronized (mLock) { mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); } } if (dumpState.isDumping(DumpState.DUMP_QUERIES)) { dump(DumpState.DUMP_QUERIES, fd, pw, dumpState); } if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { // This cannot be moved to ComputerEngine since the set of packages in the // SharedUserSetting do not have a copy. synchronized (mLock) { mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin); } } if (dumpState.isDumping(DumpState.DUMP_CHANGES)) { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Package Changes:"); synchronized (mLock) { pw.print(" Sequence number="); pw.println(mChangedPackagesSequenceNumber); final int K = mChangedPackages.size(); for (int i = 0; i < K; i++) { final SparseArray changes = mChangedPackages.valueAt(i); pw.print(" User "); pw.print(mChangedPackages.keyAt(i)); pw.println(":"); final int N = changes.size(); if (N == 0) { pw.print(" "); pw.println("No packages changed"); } else { for (int j = 0; j < N; j++) { final String pkgName = changes.valueAt(j); final int sequenceNumber = changes.keyAt(j); pw.print(" "); pw.print("seq="); pw.print(sequenceNumber); pw.print(", package="); pw.println(pkgName); } } } } } if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) { // XXX should handle packageName != null by dumping only install data that // the given package is involved with. if (dumpState.onTitlePrinted()) pw.println(); final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); ipw.println(); ipw.println("Frozen packages:"); ipw.increaseIndent(); synchronized (mLock) { if (mFrozenPackages.size() == 0) { ipw.println("(none)"); } else { for (int i = 0; i < mFrozenPackages.size(); i++) { ipw.println(mFrozenPackages.valueAt(i)); } } } ipw.decreaseIndent(); } if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) { if (dumpState.onTitlePrinted()) pw.println(); final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); ipw.println(); ipw.println("Loaded volumes:"); ipw.increaseIndent(); synchronized (mLoadedVolumes) { if (mLoadedVolumes.size() == 0) { ipw.println("(none)"); } else { for (int i = 0; i < mLoadedVolumes.size(); i++) { ipw.println(mLoadedVolumes.valueAt(i)); } } } ipw.decreaseIndent(); } if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { synchronized (mLock) { mComponentResolver.dumpServicePermissions(pw, dumpState); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { if (dumpState.onTitlePrinted()) pw.println(); dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) { if (dumpState.onTitlePrinted()) pw.println(); dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) { if (dumpState.onTitlePrinted()) pw.println(); synchronized (mLock) { mSettings.dumpReadMessagesLPr(pw, dumpState); } pw.println(); pw.println("Package warning messages:"); dumpCriticalInfo(pw, null); } if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) { dumpCriticalInfo(pw, "msg,"); } // PackageInstaller should be called outside of mPackages lock if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) { // XXX should handle packageName != null by dumping only install data that // the given package is involved with. if (dumpState.onTitlePrinted()) pw.println(); mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120)); } if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) { mApexManager.dump(pw, packageName); } if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS) && packageName == null) { pw.println(); pw.println("Per UID read timeouts:"); pw.println(" Default timeouts flag: " + getDefaultTimeouts()); pw.println(" Known digesters list flag: " + getKnownDigestersList()); PerUidReadTimeouts[] items = getPerUidReadTimeouts(); pw.println(" Timeouts (" + items.length + "):"); for (PerUidReadTimeouts item : items) { pw.print(" ("); pw.print("uid=" + item.uid + ", "); pw.print("minTimeUs=" + item.minTimeUs + ", "); pw.print("minPendingTimeUs=" + item.minPendingTimeUs + ", "); pw.print("maxPendingTimeUs=" + item.maxPendingTimeUs); pw.println(")"); } } if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) { pw.println("Snapshot statistics"); if (!mSnapshotEnabled) { pw.println(" Snapshots disabled"); } else { int hits = 0; int level = sSnapshotCorked.get(); synchronized (mSnapshotLock) { if (mSnapshotComputer != null) { hits = mSnapshotComputer.getUsed(); } } final long now = SystemClock.currentTimeMicro(); mSnapshotStatistics.dump(pw, " ", now, hits, level, dumpState.isBrief()); } } } /** * Dump package manager states to the file according to a given dumping type of * {@link DumpState}. */ private void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { mComputer.dump(type, fd, pw, dumpState); } //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; } for (String packageName : apkList) { setSystemAppHiddenUntilInstalled(packageName, true); for (UserInfo user : mInjector.getUserManagerInternal().getUsers(false)) { setSystemAppInstallState(packageName, false, user.id); } } } private void dumpProto(FileDescriptor fd) { final ProtoOutputStream proto = new ProtoOutputStream(fd); synchronized (mLock) { final long requiredVerifierPackageToken = proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE); proto.write(PackageServiceDumpProto.PackageShortProto.NAME, mRequiredVerifierPackage); proto.write( PackageServiceDumpProto.PackageShortProto.UID, getPackageUid( mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); proto.end(requiredVerifierPackageToken); DomainVerificationProxy proxy = mDomainVerificationManager.getProxy(); ComponentName verifierComponent = proxy.getComponentName(); if (verifierComponent != null) { String verifierPackageName = verifierComponent.getPackageName(); final long verifierPackageToken = proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE); proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName); proto.write( PackageServiceDumpProto.PackageShortProto.UID, getPackageUid( verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM)); proto.end(verifierPackageToken); } dumpSharedLibrariesProto(proto); dumpFeaturesProto(proto); mSettings.dumpPackagesProto(proto); mSettings.dumpSharedUsersProto(proto); dumpCriticalInfo(proto); } proto.flush(); } private void dumpFeaturesProto(ProtoOutputStream proto) { synchronized (mAvailableFeatures) { final int count = mAvailableFeatures.size(); for (int i = 0; i < count; i++) { mAvailableFeatures.valueAt(i).dumpDebug(proto, PackageServiceDumpProto.FEATURES); } } } private void dumpSharedLibrariesProto(ProtoOutputStream proto) { final int count = mSharedLibraries.size(); for (int i = 0; i < count; i++) { final String libName = mSharedLibraries.keyAt(i); WatchedLongSparseArray versionedLib = mSharedLibraries.get(libName); if (versionedLib == null) { continue; } final int versionCount = versionedLib.size(); for (int j = 0; j < versionCount; j++) { final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j); final long sharedLibraryToken = proto.start(PackageServiceDumpProto.SHARED_LIBRARIES); proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName()); final boolean isJar = (libraryInfo.getPath() != null); proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar); if (isJar) { proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH, libraryInfo.getPath()); } else { proto.write(PackageServiceDumpProto.SharedLibraryProto.APK, libraryInfo.getPackageName()); } proto.end(sharedLibraryToken); } } } // ------- apps on sdcard specific code ------- static final boolean DEBUG_SD_INSTALL = false; private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD"; private static final String SD_ENCRYPTION_ALGORITHM = "AES"; private boolean mMediaMounted = false; static String getEncryptKey() { try { String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString( SD_ENCRYPTION_KEYSTORE_NAME); if (sdEncKey == null) { sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128, SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME); if (sdEncKey == null) { Slog.e(TAG, "Failed to create encryption keys"); return null; } } return sdEncKey; } catch (NoSuchAlgorithmException nsae) { Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae); return null; } catch (IOException ioe) { Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe); return null; } } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList packages, IIntentReceiver finishedReceiver) { final int size = packages.size(); final String[] packageNames = new String[size]; final int[] packageUids = new int[size]; for (int i = 0; i < size; i++) { final AndroidPackage pkg = packages.get(i); packageNames[i] = pkg.getPackageName(); packageUids[i] = pkg.getUid(); } sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, finishedReceiver); } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList pkgList, int uidArr[], IIntentReceiver finishedReceiver) { sendResourcesChangedBroadcast(mediaStatus, replacing, pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver); } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, String[] pkgList, int[] uidArr, IIntentReceiver finishedReceiver) { int size = pkgList.length; if (size > 0) { // Send broadcasts here Bundle extras = new Bundle(); extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); if (uidArr != null) { extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); } if (replacing) { extras.putBoolean(Intent.EXTRA_REPLACING, replacing); } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; // TODO: not sure how to handle this one. sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, null, null, null, null); } } private void loadPrivatePackages(final VolumeInfo vol) { mHandler.post(() -> loadPrivatePackagesInner(vol)); } private void loadPrivatePackagesInner(VolumeInfo vol) { final String volumeUuid = vol.fsUuid; if (TextUtils.isEmpty(volumeUuid)) { Slog.e(TAG, "Loading internal storage is probably a mistake; ignoring"); return; } final ArrayList freezers = new ArrayList<>(); final ArrayList loaded = new ArrayList<>(); final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_EXTERNAL_STORAGE; final VersionInfo ver; final List packages; synchronized (mLock) { ver = mSettings.findOrCreateVersion(volumeUuid); packages = mSettings.getVolumePackagesLPr(volumeUuid); } for (PackageSetting ps : packages) { freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner")); synchronized (mInstallLock) { final AndroidPackage pkg; try { pkg = scanPackageTracedLI(ps.getPath(), parseFlags, SCAN_INITIAL, 0, null); loaded.add(pkg); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to scan " + ps.getPath() + ": " + e.getMessage()); } if (!Build.FINGERPRINT.equals(ver.fingerprint)) { clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); } } } // Reconcile app data for all started/unlocked users final StorageManager sm = mInjector.getSystemService(StorageManager.class); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) { final int flags; if (StorageManager.isUserKeyUnlocked(user.id) && smInternal.isCeStoragePrepared(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (umInternal.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; } else { continue; } try { sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags); synchronized (mInstallLock) { reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */); } } catch (IllegalStateException e) { // Device was probably ejected, and we'll process that event momentarily Slog.w(TAG, "Failed to prepare storage: " + e); } } synchronized (mLock) { final boolean isUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint); if (isUpgrade) { logCriticalInfo(Log.INFO, "Build fingerprint changed from " + ver.fingerprint + " to " + Build.FINGERPRINT + "; regranting permissions for " + volumeUuid); } mPermissionManager.onStorageVolumeMounted(volumeUuid, isUpgrade); // Yay, everything is now upgraded ver.forceCurrent(); writeSettingsLPrTEMP(); } for (PackageFreezer freezer : freezers) { freezer.close(); } if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); sendResourcesChangedBroadcast(true, false, loaded, null); synchronized (mLoadedVolumes) { mLoadedVolumes.add(vol.getId()); } } private void unloadPrivatePackages(final VolumeInfo vol) { mHandler.post(() -> unloadPrivatePackagesInner(vol)); } private void unloadPrivatePackagesInner(VolumeInfo vol) { final String volumeUuid = vol.fsUuid; if (TextUtils.isEmpty(volumeUuid)) { Slog.e(TAG, "Unloading internal storage is probably a mistake; ignoring"); return; } final int[] userIds = mUserManager.getUserIds(); final ArrayList unloaded = new ArrayList<>(); synchronized (mInstallLock) { synchronized (mLock) { final List packages = mSettings.getVolumePackagesLPr(volumeUuid); for (PackageSetting ps : packages) { if (ps.pkg == null) continue; final AndroidPackage pkg = ps.pkg; final int deleteFlags = PackageManager.DELETE_KEEP_DATA; final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, "unloadPrivatePackagesInner")) { if (deletePackageLIF(ps.name, null, false, userIds, deleteFlags, outInfo, false, null)) { unloaded.add(pkg); } else { Slog.w(TAG, "Failed to unload " + ps.getPath()); } } // Try very hard to release any references to this package // so we don't risk the system server being killed due to // open FDs AttributeCache.instance().removePackage(ps.name); } writeSettingsLPrTEMP(); } } if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); synchronized (mLoadedVolumes) { mLoadedVolumes.remove(vol.getId()); } // Try very hard to release any references to this path so we don't risk // the system server being killed due to open FDs ResourcesManager.getInstance().invalidatePath(vol.getPath().getAbsolutePath()); for (int i = 0; i < 3; i++) { System.gc(); System.runFinalization(); } } private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId) throws PackageManagerException { synchronized (mLock) { // Normalize package name to handle renamed packages packageName = normalizePackageNameLPr(packageName); final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { throw new PackageManagerException("Package " + packageName + " is unknown"); } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) { throw new PackageManagerException( "Package " + packageName + " found on unknown volume " + volumeUuid + "; expected volume " + ps.volumeUuid); } else if (!ps.getInstalled(userId)) { throw new PackageManagerException( "Package " + packageName + " not installed for user " + userId); } } } private List collectAbsoluteCodePaths() { synchronized (mLock) { List codePaths = new ArrayList<>(); final int packageCount = mSettings.getPackagesLocked().size(); for (int i = 0; i < packageCount; i++) { final PackageSetting ps = mSettings.getPackagesLocked().valueAt(i); codePaths.add(ps.getPath().getAbsolutePath()); } return codePaths; } } private void executeBatchLI(@NonNull Installer.Batch batch) { try { batch.execute(mInstaller); } catch (InstallerException e) { Slog.w(TAG, "Failed to execute pending operations", e); } } /** * Examine all apps present on given mounted volume, and destroy apps that * aren't expected, either due to uninstallation or reinstallation on * another volume. */ private void reconcileApps(String volumeUuid) { List absoluteCodePaths = collectAbsoluteCodePaths(); List filesToDelete = null; final File[] files = FileUtils.listFilesOrEmpty( Environment.getDataAppDirectory(volumeUuid)); for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } String absolutePath = file.getAbsolutePath(); boolean pathValid = false; final int absoluteCodePathCount = absoluteCodePaths.size(); for (int i = 0; i < absoluteCodePathCount; i++) { String absoluteCodePath = absoluteCodePaths.get(i); if (absoluteCodePath.startsWith(absolutePath)) { pathValid = true; break; } } if (!pathValid) { if (filesToDelete == null) { filesToDelete = new ArrayList<>(); } filesToDelete.add(file); } } if (filesToDelete != null) { final int fileToDeleteCount = filesToDelete.size(); for (int i = 0; i < fileToDeleteCount; i++) { File fileToDelete = filesToDelete.get(i); logCriticalInfo(Log.WARN, "Destroying orphaned at " + fileToDelete); synchronized (mInstallLock) { removeCodePathLI(fileToDelete); } } } } /** * Reconcile all app data for the given user. *

    * Verifies that directories exist and that ownership and labeling is * correct for all installed apps on all mounted volumes. */ void reconcileAppsData(int userId, int flags, boolean migrateAppsData) { final StorageManager storage = mInjector.getSystemService(StorageManager.class); for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { final String volumeUuid = vol.getFsUuid(); synchronized (mInstallLock) { reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppsData); } } } @GuardedBy("mInstallLock") private void reconcileAppsDataLI(String volumeUuid, int userId, int flags, boolean migrateAppData) { reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */); } /** * Reconcile all app data on given mounted volume. *

    * Destroys app data that isn't expected, either due to uninstallation or * reinstallation on another volume. *

    * Verifies that directories exist and that ownership and labeling is * correct for all installed apps. * @return list of skipped non-core packages (if {@code onlyCoreApps} is true) */ @GuardedBy("mInstallLock") private List reconcileAppsDataLI(String volumeUuid, int userId, int flags, boolean migrateAppData, boolean onlyCoreApps) { Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x" + Integer.toHexString(flags) + " migrateAppData=" + migrateAppData); List result = onlyCoreApps ? new ArrayList<>() : null; final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId); final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId); // First look for stale data that doesn't belong, and check if things // have changed since we did our last restorecon if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(userId)) { throw new RuntimeException( "Yikes, someone asked us to reconcile CE storage while " + userId + " was still locked; this would have caused massive data loss!"); } final File[] files = FileUtils.listFilesOrEmpty(ceDir); for (File file : files) { final String packageName = file.getName(); try { assertPackageKnownAndInstalled(volumeUuid, packageName, userId); } catch (PackageManagerException e) { logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e); try { mInstaller.destroyAppData(volumeUuid, packageName, userId, StorageManager.FLAG_STORAGE_CE, 0); } catch (InstallerException e2) { logCriticalInfo(Log.WARN, "Failed to destroy: " + e2); } } } } if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { final File[] files = FileUtils.listFilesOrEmpty(deDir); for (File file : files) { final String packageName = file.getName(); try { assertPackageKnownAndInstalled(volumeUuid, packageName, userId); } catch (PackageManagerException e) { logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e); try { mInstaller.destroyAppData(volumeUuid, packageName, userId, StorageManager.FLAG_STORAGE_DE, 0); } catch (InstallerException e2) { logCriticalInfo(Log.WARN, "Failed to destroy: " + e2); } } } } // Ensure that data directories are ready to roll for all packages // installed for this volume and user Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "prepareAppDataAndMigrate"); Installer.Batch batch = new Installer.Batch(); final List packages; synchronized (mLock) { packages = mSettings.getVolumePackagesLPr(volumeUuid); } int preparedCount = 0; for (PackageSetting ps : packages) { final String packageName = ps.name; if (ps.pkg == null) { Slog.w(TAG, "Odd, missing scanned package " + packageName); // TODO: might be due to legacy ASEC apps; we should circle back // and reconcile again once they're scanned continue; } // Skip non-core apps if requested if (onlyCoreApps && !ps.pkg.isCoreApp()) { result.add(packageName); continue; } if (ps.getInstalled(userId)) { prepareAppDataAndMigrate(batch, ps.pkg, userId, flags, migrateAppData); preparedCount++; } } executeBatchLI(batch); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages"); return result; } /** * Prepare app data for the given app just after it was installed or * upgraded. This method carefully only touches users that it's installed * for, and it forces a restorecon to handle any seinfo changes. *

    * Verifies that directories exist and that ownership and labeling is * correct for all installed apps. If there is an ownership mismatch, it * will try recovering system apps by wiping data; third-party app data is * left intact. *

    * Note: To avoid a deadlock, do not call this method with {@code mLock} lock held */ private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(pkg.getPackageName()); mSettings.writeKernelMappingLPr(ps); } Installer.Batch batch = new Installer.Batch(); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class); for (UserInfo user : mUserManager.getUsers(false /*excludeDying*/)) { final int flags; if (StorageManager.isUserKeyUnlocked(user.id) && smInternal.isCeStoragePrepared(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (umInternal.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; } else { continue; } if (ps.getInstalled(user.id)) { // TODO: when user data is locked, mark that we're still dirty prepareAppData(batch, pkg, user.id, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (umInternal.isUserUnlockingOrUnlocked(user.id)) { // Prepare app data on external storage; currently this is used to // setup any OBB dirs that were created by the installer correctly. int uid = UserHandle.getUid(user.id, UserHandle.getAppId(pkg.getUid())); smInternal.prepareAppDataAfterInstall(pkg.getPackageName(), uid); } }); } } executeBatchLI(batch); } /** * Prepare app data for the given app. *

    * Verifies that directories exist and that ownership and labeling is * correct for all installed apps. If there is an ownership mismatch, this * will try recovering system apps by wiping data; third-party app data is * left intact. */ private @NonNull CompletableFuture prepareAppData(@NonNull Installer.Batch batch, @Nullable AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return CompletableFuture.completedFuture(null); } return prepareAppDataLeaf(batch, pkg, userId, flags); } private @NonNull CompletableFuture prepareAppDataAndMigrate(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { return prepareAppData(batch, pkg, userId, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (maybeMigrateAppData && maybeMigrateAppDataLIF(pkg, userId)) { // We may have just shuffled around app data directories, so // prepare them one more time final Installer.Batch batchInner = new Installer.Batch(); prepareAppData(batchInner, pkg, userId, flags); executeBatchLI(batchInner); } }); } private @NonNull CompletableFuture prepareAppDataLeaf(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags) { if (DEBUG_APP_DATA) { Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); } final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(pkg.getPackageName()); } final String volumeUuid = pkg.getVolumeUuid(); final String packageName = pkg.getPackageName(); final int appId = UserHandle.getAppId(pkg.getUid()); String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps); Preconditions.checkNotNull(pkgSeInfo); final String seInfo = pkgSeInfo + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); final int targetSdkVersion = pkg.getTargetSdkVersion(); return batch.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, targetSdkVersion).whenComplete((ceDataInode, e) -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() if (e != null) { logCriticalInfo(Log.WARN, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); } } else if (e != null) { Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); } // Prepare the application profiles only for upgrades and // first boot (so that we don't repeat the same operation at // each boot). // // We only have to cover the upgrade and first boot here // because for app installs we prepare the profiles before // invoking dexopt (in installPackageLI). // // We also have to cover non system users because we do not // call the usual install package methods for them. // // NOTE: in order to speed up first boot time we only create // the current profile and do not update the content of the // reference profile. A system image should already be // configured with the right profile keys and the profiles // for the speed-profile prebuilds should already be copied. // That's done in #performDexOptUpgrade. // // TODO(calin, mathieuc): We should use .dm files for // prebuilds profiles instead of manually copying them in // #performDexOptUpgrade. When we do that we should have a // more granular check here and only update the existing // profiles. if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) { mArtManagerService.prepareAppProfiles(pkg, userId, /* updateReferenceProfileContent= */ false); } if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) { // TODO: mark this structure as dirty so we persist it! synchronized (mLock) { if (ps != null) { ps.setCeDataInode(ceDataInode, userId); } } } prepareAppDataContentsLeafLIF(pkg, ps, userId, flags); }); } private void prepareAppDataContentsLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } prepareAppDataContentsLeafLIF(pkg, pkgSetting, userId, flags); } private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, @Nullable PackageSetting pkgSetting, int userId, int flags) { final String volumeUuid = pkg.getVolumeUuid(); final String packageName = pkg.getPackageName(); if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. String primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting); if (primaryCpuAbi != null && !VMRuntime.is64BitAbi(primaryCpuAbi)) { final String nativeLibPath = pkg.getNativeLibraryDir(); try { mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName, nativeLibPath, userId); } catch (InstallerException e) { Slog.e(TAG, "Failed to link native for " + packageName + ": " + e); } } } } /** * For system apps on non-FBE devices, this method migrates any existing * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag * requested by the app. */ private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) { if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated() && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { final int storageTarget = pkg.isDefaultToDeviceProtectedStorage() ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE; try { mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId, storageTarget); } catch (InstallerException e) { logCriticalInfo(Log.WARN, "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage()); } return true; } else { return false; } } public PackageFreezer freezePackage(String packageName, String killReason) { return freezePackage(packageName, UserHandle.USER_ALL, killReason); } public PackageFreezer freezePackage(String packageName, int userId, String killReason) { return new PackageFreezer(packageName, userId, killReason); } public PackageFreezer freezePackageForInstall(String packageName, int installFlags, String killReason) { return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason); } public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags, String killReason) { if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { return new PackageFreezer(); } else { return freezePackage(packageName, userId, killReason); } } public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags, String killReason) { return freezePackageForDelete(packageName, UserHandle.USER_ALL, deleteFlags, killReason); } public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags, String killReason) { if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) { return new PackageFreezer(); } else { return freezePackage(packageName, userId, killReason); } } /** * Class that freezes and kills the given package upon creation, and * unfreezes it upon closing. This is typically used when doing surgery on * app code/data to prevent the app from running while you're working. */ private class PackageFreezer implements AutoCloseable { private final String mPackageName; private final boolean mWeFroze; private final AtomicBoolean mClosed = new AtomicBoolean(); private final CloseGuard mCloseGuard = CloseGuard.get(); /** * Create and return a stub freezer that doesn't actually do anything, * typically used when someone requested * {@link PackageManager#INSTALL_DONT_KILL_APP} or * {@link PackageManager#DELETE_DONT_KILL_APP}. */ public PackageFreezer() { mPackageName = null; mWeFroze = false; mCloseGuard.open("close"); } public PackageFreezer(String packageName, int userId, String killReason) { synchronized (mLock) { mPackageName = packageName; mWeFroze = mFrozenPackages.add(mPackageName); final PackageSetting ps = mSettings.getPackageLPr(mPackageName); if (ps != null) { killApplication(ps.name, ps.appId, userId, killReason); } } mCloseGuard.open("close"); } @Override protected void finalize() throws Throwable { try { mCloseGuard.warnIfOpen(); close(); } finally { super.finalize(); } } @Override public void close() { mCloseGuard.close(); if (mClosed.compareAndSet(false, true)) { synchronized (mLock) { if (mWeFroze) { mFrozenPackages.remove(mPackageName); } } } } } /** * Verify that given package is currently frozen. */ private void checkPackageFrozen(String packageName) { synchronized (mLock) { if (!mFrozenPackages.contains(packageName)) { Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable()); } } } @Override public int movePackage(final String packageName, final String volumeUuid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); final int callingUid = Binder.getCallingUid(); final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid)); final int moveId = mNextMoveId.getAndIncrement(); mHandler.post(() -> { try { movePackageInternal(packageName, volumeUuid, moveId, callingUid, user); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to move " + packageName, e); mMoveCallbacks.notifyStatusChanged(moveId, e.error); } }); return moveId; } private void movePackageInternal(final String packageName, final String volumeUuid, final int moveId, final int callingUid, UserHandle user) throws PackageManagerException { final StorageManager storage = mInjector.getSystemService(StorageManager.class); final PackageManager pm = mContext.getPackageManager(); final String currentVolumeUuid; final File codeFile; final InstallSource installSource; final String packageAbiOverride; final int appId; final String seinfo; final String label; final int targetSdkVersion; final PackageFreezer freezer; final int[] installedUserIds; final boolean isCurrentLocationExternal; final String fromCodePath; // reader synchronized (mLock) { final AndroidPackage pkg = mPackages.get(packageName); final PackageSetting ps = mSettings.getPackageLPr(packageName); if (pkg == null || ps == null || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) { throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } if (pkg.isSystem()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); } final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid); final boolean allow3rdPartyOnInternal = mContext.getResources().getBoolean( com.android.internal.R.bool.config_allow3rdPartyAppOnInternal); if (isInternalStorage && !allow3rdPartyOnInternal) { throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL, "3rd party apps are not allowed on internal storage"); } currentVolumeUuid = ps.volumeUuid; final File probe = new File(pkg.getPath()); final File probeOat = new File(probe, "oat"); if (!probe.isDirectory() || !probeOat.isDirectory()) { throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Move only supported for modern cluster style installs"); } if (Objects.equals(currentVolumeUuid, volumeUuid)) { throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Package already moved to " + volumeUuid); } if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) { throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN, "Device admin cannot be moved"); } if (mFrozenPackages.contains(packageName)) { throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING, "Failed to move already frozen package"); } isCurrentLocationExternal = pkg.isExternalStorage(); codeFile = new File(pkg.getPath()); installSource = ps.installSource; packageAbiOverride = ps.cpuAbiOverrideString; appId = UserHandle.getAppId(pkg.getUid()); seinfo = AndroidPackageUtils.getSeInfo(pkg, ps); label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState())); targetSdkVersion = pkg.getTargetSdkVersion(); freezer = freezePackage(packageName, "movePackageInternal"); installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true); if (codeFile.getParentFile().getName().startsWith(RANDOM_DIR_PREFIX)) { fromCodePath = codeFile.getParentFile().getAbsolutePath(); } else { fromCodePath = codeFile.getAbsolutePath(); } } final Bundle extras = new Bundle(); extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName); extras.putString(Intent.EXTRA_TITLE, label); mMoveCallbacks.notifyCreated(moveId, extras); int installFlags; final boolean moveCompleteApp; final File measurePath; installFlags = INSTALL_INTERNAL; if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { moveCompleteApp = true; measurePath = Environment.getDataAppDirectory(volumeUuid); } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { moveCompleteApp = false; measurePath = storage.getPrimaryPhysicalVolume().getPath(); } else { final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid); if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE || !volume.isMountedWritable()) { freezer.close(); throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Move location not mounted private volume"); } moveCompleteApp = true; measurePath = Environment.getDataAppDirectory(volumeUuid); } // If we're moving app data around, we need all the users unlocked if (moveCompleteApp) { for (int userId : installedUserIds) { if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(userId)) { throw new PackageManagerException(MOVE_FAILED_LOCKED_USER, "User " + userId + " must be unlocked"); } } } final PackageStats stats = new PackageStats(null, -1); synchronized (mInstaller) { for (int userId : installedUserIds) { if (!getPackageSizeInfoLI(packageName, userId, stats)) { freezer.close(); throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Failed to measure package size"); } } } if (DEBUG_INSTALL) Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size " + stats.dataSize); final long startFreeBytes = measurePath.getUsableSpace(); final long sizeBytes; if (moveCompleteApp) { sizeBytes = stats.codeSize + stats.dataSize; } else { sizeBytes = stats.codeSize; } if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) { freezer.close(); throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Not enough free space to move"); } mMoveCallbacks.notifyStatusChanged(moveId, 10); final CountDownLatch installedLatch = new CountDownLatch(1); final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() { @Override public void onUserActionRequired(Intent intent) throws RemoteException { throw new IllegalStateException(); } @Override public void onPackageInstalled(String basePackageName, int returnCode, String msg, Bundle extras) throws RemoteException { if (DEBUG_INSTALL) Slog.d(TAG, "Install result for move: " + PackageManager.installStatusToString(returnCode, msg)); installedLatch.countDown(); freezer.close(); final int status = PackageManager.installStatusToPublicStatus(returnCode); switch (status) { case PackageInstaller.STATUS_SUCCESS: mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_SUCCEEDED); logAppMovedStorage(packageName, isCurrentLocationExternal); break; case PackageInstaller.STATUS_FAILURE_STORAGE: mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE); break; default: mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INTERNAL_ERROR); break; } } }; final MoveInfo move; if (moveCompleteApp) { // Kick off a thread to report progress estimates new Thread(() -> { while (true) { try { if (installedLatch.await(1, TimeUnit.SECONDS)) { break; } } catch (InterruptedException ignored) { } final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace(); final int progress = 10 + (int) MathUtils.constrain( ((deltaFreeBytes * 80) / sizeBytes), 0, 80); mMoveCallbacks.notifyStatusChanged(moveId, progress); } }).start(); move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName, appId, seinfo, targetSdkVersion, fromCodePath); } else { move = null; } installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; final Message msg = mHandler.obtainMessage(INIT_COPY); final OriginInfo origin = OriginInfo.fromExistingFile(codeFile); final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult ret = ApkLiteParseUtils.parsePackageLite(input, new File(origin.resolvedPath), /* flags */ 0); final PackageLite lite = ret.isSuccess() ? ret.getResult() : null; final InstallParams params = new InstallParams(origin, move, installObserver, installFlags, installSource, volumeUuid, user, packageAbiOverride, lite); params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params)); msg.obj = params; Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage", System.identityHashCode(msg.obj)); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", System.identityHashCode(msg.obj)); mHandler.sendMessage(msg); } /** * Logs that an app has been moved from internal to external storage and vice versa. * @param packageName The package that was moved. */ private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) { final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } if (pkg == null) { return; } final StorageManager storage = mInjector.getSystemService(StorageManager.class);; VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage()); if (!isPreviousLocationExternal && pkg.isExternalStorage()) { // Move from internal to external storage. FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType, FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL, packageName); } else if (isPreviousLocationExternal && !pkg.isExternalStorage()) { // Move from external to internal storage. FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType, FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL, packageName); } } @Override public int movePrimaryStorage(String volumeUuid) throws RemoteException { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); 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 int getMoveStatus(int moveId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null); return mMoveCallbacks.mLastStatus.get(moveId); } @Override public void registerMoveCallback(IPackageMoveObserver callback) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null); mMoveCallbacks.register(callback); } @Override public void unregisterMoveCallback(IPackageMoveObserver callback) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null); mMoveCallbacks.unregister(callback); } @Override public boolean setInstallLocation(int loc) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, null); if (getInstallLocation() == loc) { return true; } if (loc == PackageHelper.APP_INSTALL_AUTO || loc == PackageHelper.APP_INSTALL_INTERNAL || loc == PackageHelper.APP_INSTALL_EXTERNAL) { android.provider.Settings.Global.putInt(mContext.getContentResolver(), android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION, loc); return true; } return false; } @Override public int getInstallLocation() { // allow instant app access return android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO); } /** Called by UserManagerService */ void cleanUpUser(UserManagerService userManager, @UserIdInt int userId) { synchronized (mLock) { mDirtyUsers.remove(userId); mUserNeedsBadging.delete(userId); mPermissionManager.onUserRemoved(userId); mSettings.removeUserLPw(userId); mPendingBroadcasts.remove(userId); mInstantAppRegistry.onUserRemovedLPw(userId); removeUnusedPackagesLPw(userManager, userId); } } /** * We're removing userId and would like to remove any downloaded packages * that are no longer in use by any other user. * @param userId the user being removed */ @GuardedBy("mLock") private void removeUnusedPackagesLPw(UserManagerService userManager, final int userId) { final boolean DEBUG_CLEAN_APKS = false; int [] users = userManager.getUserIds(); final int numPackages = mSettings.getPackagesLocked().size(); for (int index = 0; index < numPackages; index++) { final PackageSetting ps = mSettings.getPackagesLocked().valueAt(index); if (ps.pkg == null) { continue; } final String packageName = ps.pkg.getPackageName(); // Skip over if system app or static shared library if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 || !TextUtils.isEmpty(ps.pkg.getStaticSharedLibName())) { continue; } if (DEBUG_CLEAN_APKS) { Slog.i(TAG, "Checking package " + packageName); } boolean keep = shouldKeepUninstalledPackageLPr(packageName); if (keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Keeping package " + packageName + " - requested by DO"); } } else { for (int i = 0; i < users.length; i++) { if (users[i] != userId && ps.getInstalled(users[i])) { keep = true; if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Keeping package " + packageName + " for user " + users[i]); } break; } } } if (!keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Removing package " + packageName); } //end run mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, userId, 0, true /*removedBySystem*/)); } } } /** * 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 userTypeInstallablePackages, String[] disallowedPackages) { synchronized (mInstallLock) { mSettings.createNewUserLI(this, mInstaller, userId, userTypeInstallablePackages, disallowedPackages); } synchronized (mLock) { scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageListLocked(userId); mAppsFilter.onUsersChanged(); } } 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); mDomainVerificationManager.clearUser(userId); } } boolean readPermissionStateForUser(@UserIdInt int userId) { synchronized (mLock) { mPermissionManager.writeLegacyPermissionStateTEMP(); mSettings.readPermissionStateForUserSyncLPr(userId); mPermissionManager.readLegacyPermissionStateTEMP(); return mPmInternal.isPermissionUpgradeNeeded(userId); } } @Override public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, "Only package verification agents can read the verifier device identity"); synchronized (mLock) { return mSettings.getVerifierDeviceIdentityLPw(); } } @Override 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); } } @Override public IPackageInstaller getPackageInstaller() { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } return mInstallerService; } @Override public IArtManager getArtManager() { return mArtManagerService; } private boolean userNeedsBadging(int userId) { int index = mUserNeedsBadging.indexOfKey(userId); if (index < 0) { final UserInfo userInfo; final long token = Binder.clearCallingIdentity(); try { userInfo = mUserManager.getUserInfo(userId); } finally { Binder.restoreCallingIdentity(token); } final boolean b; if (userInfo != null && userInfo.isManagedProfile()) { b = true; } else { b = false; } mUserNeedsBadging.put(userId, b); return b; } return mUserNeedsBadging.valueAt(index); } @Override public KeySet getKeySetByAlias(String packageName, String alias) { if (packageName == null || alias == null) { return null; } synchronized (mLock) { final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), Binder.getCallingUid(), UserHandle.getCallingUserId())) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } final KeySetManagerService ksms = mSettings.getKeySetManagerService(); return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias)); } } @Override public KeySet getSigningKeySet(String packageName) { if (packageName == null) { return null; } synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), callingUid, callingUserId)) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName + ", uid:" + callingUid); throw new IllegalArgumentException("Unknown package: " + packageName); } if (pkg.getUid() != callingUid && Process.SYSTEM_UID != callingUid) { throw new SecurityException("May not access signing KeySet of other apps."); } final KeySetManagerService ksms = mSettings.getKeySetManagerService(); return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName)); } } @Override public boolean isPackageSignedByKeySet(String packageName, KeySet ks) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return false; } if (packageName == null || ks == null) { return false; } synchronized (mLock) { final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } IBinder ksh = ks.getToken(); if (ksh instanceof KeySetHandle) { final KeySetManagerService ksms = mSettings.getKeySetManagerService(); return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh); } return false; } } @Override public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return false; } if (packageName == null || ks == null) { return false; } synchronized (mLock) { final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } IBinder ksh = ks.getToken(); if (ksh instanceof KeySetHandle) { final KeySetManagerService ksms = mSettings.getKeySetManagerService(); return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh); } return false; } } @GuardedBy("mLock") private void deletePackageIfUnusedLPr(final String packageName) { PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps == null) { return; } if (!ps.isAnyInstalled(mUserManager.getUserIds())) { // 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(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, 0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/)); } } private int verifyReplacingVersionCode(PackageInfoLite pkgLite, long requiredInstalledVersionCode, int installFlags) { String packageName = pkgLite.packageName; synchronized (mLock) { // Package which currently owns the data that the new package will own if installed. // If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg // will be null whereas dataOwnerPkg will contain information about the package // which was uninstalled while keeping its data. AndroidPackage dataOwnerPkg = mPackages.get(packageName); if (dataOwnerPkg == null) { PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { dataOwnerPkg = ps.pkg; } } if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) { if (dataOwnerPkg == null) { Slog.w(TAG, "Required installed version code was " + requiredInstalledVersionCode + " but package is not installed"); return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION; } if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) { Slog.w(TAG, "Required installed version code was " + requiredInstalledVersionCode + " but actual installed version is " + dataOwnerPkg.getLongVersionCode()); return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION; } } if (dataOwnerPkg != null) { if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, dataOwnerPkg.isDebuggable())) { try { checkDowngrade(dataOwnerPkg, pkgLite); } catch (PackageManagerException e) { Slog.w(TAG, "Downgrade detected: " + e.getMessage()); return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; } } } } return PackageManager.INSTALL_SUCCEEDED; } /** * Check and throw if the given before/after packages would be considered a * downgrade. */ private static void checkDowngrade(AndroidPackage before, PackageInfoLite after) throws PackageManagerException { if (after.getLongVersionCode() < before.getLongVersionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update version code " + after.versionCode + " is older than current " + before.getLongVersionCode()); } else if (after.getLongVersionCode() == before.getLongVersionCode()) { if (after.baseRevisionCode < before.getBaseRevisionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update base revision code " + after.baseRevisionCode + " is older than current " + before.getBaseRevisionCode()); } if (!ArrayUtils.isEmpty(after.splitNames)) { for (int i = 0; i < after.splitNames.length; i++) { final String splitName = after.splitNames[i]; final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName); if (j != -1) { if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update split " + splitName + " revision code " + after.splitRevisionCodes[i] + " is older than current " + before.getSplitRevisionCodes()[j]); } } } } } } private static class MoveCallbacks extends Handler { private static final int MSG_CREATED = 1; private static final int MSG_STATUS_CHANGED = 2; private final RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); private final SparseIntArray mLastStatus = new SparseIntArray(); public MoveCallbacks(Looper looper) { super(looper); } public void register(IPackageMoveObserver callback) { mCallbacks.register(callback); } public void unregister(IPackageMoveObserver callback) { mCallbacks.unregister(callback); } @Override public void handleMessage(Message msg) { final SomeArgs args = (SomeArgs) msg.obj; final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { final IPackageMoveObserver callback = mCallbacks.getBroadcastItem(i); try { invokeCallback(callback, msg.what, args); } catch (RemoteException ignored) { } } mCallbacks.finishBroadcast(); args.recycle(); } private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args) throws RemoteException { switch (what) { case MSG_CREATED: { callback.onCreated(args.argi1, (Bundle) args.arg2); break; } case MSG_STATUS_CHANGED: { callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3); break; } } } private void notifyCreated(int moveId, Bundle extras) { Slog.v(TAG, "Move " + moveId + " created " + extras.toString()); final SomeArgs args = SomeArgs.obtain(); args.argi1 = moveId; args.arg2 = extras; obtainMessage(MSG_CREATED, args).sendToTarget(); } private void notifyStatusChanged(int moveId, int status) { notifyStatusChanged(moveId, status, -1); } private void notifyStatusChanged(int moveId, int status, long estMillis) { Slog.v(TAG, "Move " + moveId + " status " + status); final SomeArgs args = SomeArgs.obtain(); args.argi1 = moveId; args.argi2 = status; args.arg3 = estMillis; obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget(); synchronized (mLastStatus) { mLastStatus.put(moveId, status); } } } private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient { private final IPackageChangeObserver mObserver; PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) { mObserver = observer; } @Override public void binderDied() { synchronized (mPackageChangeObservers) { mPackageChangeObservers.remove(mObserver); Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is " + mPackageChangeObservers.size()); } } } private class PackageManagerNative extends IPackageManagerNative.Stub { @Override public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) { synchronized (mPackageChangeObservers) { try { observer.asBinder().linkToDeath( new PackageChangeObserverDeathRecipient(observer), 0); } catch (RemoteException e) { Log.e(TAG, e.getMessage()); } mPackageChangeObservers.add(observer); Log.d(TAG, "Size of mPackageChangeObservers after registry is " + mPackageChangeObservers.size()); } } @Override public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) { synchronized (mPackageChangeObservers) { mPackageChangeObservers.remove(observer); Log.d(TAG, "Size of mPackageChangeObservers after unregistry is " + mPackageChangeObservers.size()); } } @Override public String[] getAllPackages() { return PackageManagerService.this.getAllPackages().toArray(new String[0]); } @Override public String[] getNamesForUids(int[] uids) throws RemoteException { String[] names = null; String[] results = null; try { if (uids == null || uids.length == 0) { return null; } names = PackageManagerService.this.getNamesForUids(uids); results = (names != null) ? names : new String[uids.length]; // massage results so they can be parsed by the native binder for (int i = results.length - 1; i >= 0; --i) { if (results[i] == null) { results[i] = ""; } } return results; } catch (Throwable t) { // STOPSHIP(186558987): revert addition of try/catch/log Slog.e(TAG, "uids: " + Arrays.toString(uids)); Slog.e(TAG, "names: " + Arrays.toString(names)); Slog.e(TAG, "results: " + Arrays.toString(results)); Slog.e(TAG, "throwing exception", t); throw t; } } // NB: this differentiates between preloads and sideloads @Override public String getInstallerForPackage(String packageName) throws RemoteException { final String installerName = getInstallerPackageName(packageName); if (!TextUtils.isEmpty(installerName)) { return installerName; } // differentiate between preload and sideload int callingUser = UserHandle.getUserId(Binder.getCallingUid()); ApplicationInfo appInfo = getApplicationInfo(packageName, /*flags*/ 0, /*userId*/ callingUser); if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { return "preload"; } return ""; } @Override public long getVersionCodeForPackage(String packageName) throws RemoteException { try { int callingUser = UserHandle.getUserId(Binder.getCallingUid()); PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser); if (pInfo != null) { return pInfo.getLongVersionCode(); } } catch (Exception e) { } return 0; } @Override public int getTargetSdkVersionForPackage(String packageName) throws RemoteException { int targetSdk = getTargetSdkVersion(packageName); if (targetSdk != -1) { return targetSdk; } throw new RemoteException("Couldn't get targetSdkVersion for package " + packageName); } @Override public boolean isPackageDebuggable(String packageName) throws RemoteException { int callingUser = UserHandle.getCallingUserId(); ApplicationInfo appInfo = getApplicationInfo(packageName, 0, callingUser); if (appInfo != null) { return (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)); } throw new RemoteException("Couldn't get debug flag for package " + packageName); } @Override public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames) throws RemoteException { int callingUser = UserHandle.getUserId(Binder.getCallingUid()); boolean[] results = new boolean[packageNames.length]; for (int i = results.length - 1; i >= 0; --i) { ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser); results[i] = appInfo == null ? false : appInfo.isAudioPlaybackCaptureAllowed(); } return results; } @Override public int getLocationFlags(String packageName) throws RemoteException { int callingUser = UserHandle.getUserId(Binder.getCallingUid()); ApplicationInfo appInfo = getApplicationInfo(packageName, /*flags*/ 0, /*userId*/ callingUser); if (appInfo == null) { throw new RemoteException( "Couldn't get ApplicationInfo for package " + packageName); } return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0) | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0) | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0)); } @Override public String getModuleMetadataPackageName() throws RemoteException { return PackageManagerService.this.mModuleInfoProvider.getPackageName(); } @Override public boolean hasSha256SigningCertificate(String packageName, byte[] certificate) throws RemoteException { return PackageManagerService.this.hasSigningCertificate( packageName, certificate, CERT_INPUT_SHA256); } @Override public boolean hasSystemFeature(String featureName, int version) { return PackageManagerService.this.hasSystemFeature(featureName, version); } } private AndroidPackage getPackage(String packageName) { return mComputer.getPackage(packageName); } private AndroidPackage getPackage(int uid) { return mComputer.getPackage(uid); } private SigningDetails getSigningDetails(@NonNull String packageName) { return mComputer.getSigningDetails(packageName); } private SigningDetails getSigningDetails(int uid) { return mComputer.getSigningDetails(uid); } private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { return mComputer.filterAppAccess(pkg, callingUid, userId); } private boolean filterAppAccess(String packageName, int callingUid, int userId) { return mComputer.filterAppAccess(packageName, callingUid, userId); } private class PackageManagerInternalImpl extends PackageManagerInternal { @Override public List getInstalledApplications(int flags, int userId, int callingUid) { return PackageManagerService.this.getInstalledApplicationsListInternal(flags, userId, callingUid); } @Override public boolean isPlatformSigned(String packageName) { PackageSetting packageSetting = mSettings.getPackageLPr(packageName); if (packageSetting == null) { return false; } AndroidPackage pkg = packageSetting.pkg; if (pkg == null) { // May happen if package in on a removable sd card return false; } return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails()) || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION); } @Override public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) { SigningDetails sd = getSigningDetails(packageName); if (sd == null) { return false; } return sd.hasSha256Certificate(restoringFromSigHash, SigningDetails.CertCapabilities.INSTALLED_DATA); } @Override public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) { SigningDetails sd = 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) { SigningDetails serverSigningDetails = getSigningDetails(serverUid); SigningDetails clientSigningDetails = getSigningDetails(clientUid); return serverSigningDetails.checkCapability(clientSigningDetails, capability) || clientSigningDetails.hasAncestorOrSelf(serverSigningDetails); } private SigningDetails getSigningDetails(@NonNull String packageName) { return PackageManagerService.this.getSigningDetails(packageName); } private SigningDetails getSigningDetails(int uid) { return PackageManagerService.this.getSigningDetails(uid); } @Override public boolean isInstantApp(String packageName, int userId) { return PackageManagerService.this.isInstantApp(packageName, userId); } @Override public String getInstantAppPackageName(int uid) { return PackageManagerService.this.getInstantAppPackageName(uid); } @Override public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId); } @Override public boolean filterAppAccess(String packageName, int callingUid, int userId) { return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId); } @Override public AndroidPackage getPackage(String packageName) { return PackageManagerService.this.getPackage(packageName); } @Override public AndroidPackage getPackage(int uid) { return PackageManagerService.this.getPackage(uid); } @Nullable @Override public PackageSetting getPackageSetting(String packageName) { return PackageManagerService.this.getPackageSetting(packageName); } @Override public PackageList getPackageList(PackageListObserver observer) { synchronized (mLock) { final int N = mPackages.size(); final ArrayList list = new ArrayList<>(N); for (int i = 0; i < N; i++) { list.add(mPackages.keyAt(i)); } final PackageList packageList = new PackageList(list, observer); if (observer != null) { mPackageListObservers.add(packageList); } return packageList; } } @Override public void removePackageListObserver(PackageListObserver observer) { synchronized (mLock) { mPackageListObservers.remove(observer); } } @Override public PackageSetting getDisabledSystemPackage(@NonNull String packageName) { synchronized (mLock) { return mSettings.getDisabledSystemPkgLPr(packageName); } } @Override public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) { PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage( packageName); AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg; return disabledPkg == null ? null : disabledPkg.getPackageName(); } /** * Only keep package names that refer to {@link PackageParser.Package#isSystem system} * packages. * * @param pkgNames The packages to filter * * @return The filtered packages */ private @NonNull String[] filterOnlySystemPackages(@Nullable String... pkgNames) { if (pkgNames == null) { return ArrayUtils.emptyArray(String.class); } ArrayList systemPackageNames = new ArrayList<>(pkgNames.length); for (String pkgName: pkgNames) { synchronized (mLock) { if (pkgName == null) { continue; } AndroidPackage pkg = getPackage(pkgName); if (pkg == null) { Log.w(TAG, "Could not find package " + pkgName); continue; } if (!pkg.isSystem()) { Log.w(TAG, pkgName + " is not system"); continue; } systemPackageNames.add(pkgName); } } return systemPackageNames.toArray(new String[]{}); } @Override public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) { return getKnownPackageNamesInternal(knownPackage, userId); } private String[] getKnownPackageNamesInternal(int knownPackage, int userId) { switch (knownPackage) { case PackageManagerInternal.PACKAGE_BROWSER: return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) }; case PackageManagerInternal.PACKAGE_INSTALLER: return filterOnlySystemPackages(mRequiredInstallerPackage); case PackageManagerInternal.PACKAGE_SETUP_WIZARD: return filterOnlySystemPackages(mSetupWizardPackage); case PackageManagerInternal.PACKAGE_SYSTEM: return new String[]{"android"}; case PackageManagerInternal.PACKAGE_VERIFIER: return filterOnlySystemPackages(mRequiredVerifierPackage); case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER: return filterOnlySystemPackages( mDefaultTextClassifierPackage, mSystemTextClassifierPackageName); case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: return filterOnlySystemPackages(mRequiredPermissionControllerPackage); case PackageManagerInternal.PACKAGE_DOCUMENTER: return filterOnlySystemPackages(mDocumenterPackage); case PackageManagerInternal.PACKAGE_CONFIGURATOR: return filterOnlySystemPackages(mConfiguratorPackage); case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER: return filterOnlySystemPackages(mIncidentReportApproverPackage); case PackageManagerInternal.PACKAGE_APP_PREDICTOR: return filterOnlySystemPackages(mAppPredictionServicePackage); case PackageManagerInternal.PACKAGE_COMPANION: return filterOnlySystemPackages(COMPANION_PACKAGE_NAME); case PackageManagerInternal.PACKAGE_RETAIL_DEMO: return TextUtils.isEmpty(mRetailDemoPackage) ? ArrayUtils.emptyArray(String.class) : new String[] {mRetailDemoPackage}; case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE: return filterOnlySystemPackages(getOverlayConfigSignaturePackageName()); case PackageManagerInternal.PACKAGE_RECENTS: return filterOnlySystemPackages(mRecentsPackage); default: return ArrayUtils.emptyArray(String.class); } } @Override public boolean isResolveActivityComponent(ComponentInfo component) { return mResolveActivity.packageName.equals(component.packageName) && mResolveActivity.name.equals(component.name); } @Override public void setKeepUninstalledPackages(final List packageList) { PackageManagerService.this.setKeepUninstalledPackagesInternal(packageList); } @Override public boolean isPermissionsReviewRequired(String packageName, int userId) { return mPermissionManager.isPermissionsReviewRequired(packageName, userId); } @Override public PackageInfo getPackageInfo( String packageName, int flags, int filterCallingUid, int userId) { return PackageManagerService.this .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST, flags, filterCallingUid, userId); } @Override public long getCeDataInode(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { return ps.getCeDataInode(userId); } return 0; } } @Override public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); final Bundle allExtras = new Bundle(); if (ps != null) { final PackageUserState pus = ps.readUserState(userId); if (pus.suspended) { for (int i = 0; i < pus.suspendParams.size(); i++) { final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i); if (params != null && params.launcherExtras != null) { allExtras.putAll(params.launcherExtras); } } } } return (allExtras.size() > 0) ? allExtras : null; } } @Override public boolean isPackageSuspended(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); return (ps != null) ? ps.getSuspended(userId) : false; } } @Override public void removeAllNonSystemPackageSuspensions(int userId) { final String[] allPackages; synchronized (mLock) { allPackages = mPackages.keySet().toArray(new String[mPackages.size()]); } PackageManagerService.this.removeSuspensionsBySuspendingPackage(allPackages, (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage), userId); } @Override public void removeNonSystemPackageSuspensions(String packageName, int userId) { PackageManagerService.this.removeSuspensionsBySuspendingPackage( new String[]{packageName}, (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage), userId); } @Override public void flushPackageRestrictions(int userId) { synchronized (mLock) { PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId); } } @Override public void removeDistractingPackageRestrictions(String packageName, int userId) { PackageManagerService.this.removeDistractingPackageRestrictions( new String[]{packageName}, userId); } @Override public void removeAllDistractingPackageRestrictions(int userId) { PackageManagerService.this.removeAllDistractingPackageRestrictions(userId); } @Override public String getSuspendingPackage(String suspendedPackage, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage); if (ps != null) { final PackageUserState pus = ps.readUserState(userId); if (pus.suspended) { String suspendingPackage = null; for (int i = 0; i < pus.suspendParams.size(); i++) { suspendingPackage = pus.suspendParams.keyAt(i); if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) { return suspendingPackage; } } return suspendingPackage; } } return null; } } @Override public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, String suspendingPackage, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage); if (ps != null) { final PackageUserState pus = ps.readUserState(userId); if (pus.suspended) { final PackageUserState.SuspendParams suspendParams = pus.suspendParams.get(suspendingPackage); return (suspendParams != null) ? suspendParams.dialogInfo : null; } } } return null; } @Override public int getDistractingPackageRestrictions(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE; } } @Override public int getPackageUid(String packageName, int flags, int userId) { return PackageManagerService.this .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID); } @Override public ApplicationInfo getApplicationInfo( String packageName, int flags, int filterCallingUid, int userId) { return PackageManagerService.this .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId); } @Override public ActivityInfo getActivityInfo( ComponentName component, int flags, int filterCallingUid, int userId) { return PackageManagerService.this .getActivityInfoInternal(component, flags, filterCallingUid, userId); } @Override public List queryIntentActivities( Intent intent, String resolvedType, int flags, int filterCallingUid, int userId) { return PackageManagerService.this .queryIntentActivitiesInternal(intent, resolvedType, flags, 0, filterCallingUid, userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); } @Override public List queryIntentServices( Intent intent, int flags, int callingUid, int userId) { final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver()); return PackageManagerService.this .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid, false); } @Override public ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId) { return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId); } @Override public ComponentName getDefaultHomeActivity(int userId) { return PackageManagerService.this.getDefaultHomeActivity(userId); } @Override public ComponentName getSystemUiServiceComponent() { return ComponentName.unflattenFromString(mContext.getResources().getString( com.android.internal.R.string.config_systemUIServiceComponent)); } @Override public void setDeviceAndProfileOwnerPackages( int deviceOwnerUserId, String deviceOwnerPackage, SparseArray profileOwnerPackages) { mProtectedPackages.setDeviceAndProfileOwnerPackages( deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages); final ArraySet 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) { usersWithPoOrDo.add(profileOwnerPackages.keyAt(i)); } } } @Override public void setDeviceOwnerProtectedPackages( String deviceOwnerPackageName, List packageNames) { mProtectedPackages.setDeviceOwnerProtectedPackages( deviceOwnerPackageName, packageNames); } @Override public boolean isPackageDataProtected(int userId, String packageName) { return mProtectedPackages.isPackageDataProtected(userId, packageName); } @Override public boolean isPackageStateProtected(String packageName, int userId) { return mProtectedPackages.isPackageStateProtected(userId, packageName); } @Override public boolean isPackageEphemeral(int userId, String packageName) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); return ps != null ? ps.getInstantApp(userId) : false; } } @Override public boolean wasPackageEverLaunched(String packageName, int userId) { synchronized (mLock) { return mSettings.wasPackageEverLaunchedLPr(packageName, userId); } } // TODO(188814480) should be able to remove the NPE check when snapshot // "recursion" is fixed. @Override public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) { synchronized (mLock) { AndroidPackage pkg = getPackage(component.getPackageName()); if (pkg == null) { return false; } else { return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId); } } } @Override public boolean userNeedsBadging(int userId) { synchronized (mLock) { return PackageManagerService.this.userNeedsBadging(userId); } } @Override public String getNameForUid(int uid) { return PackageManagerService.this.getNameForUid(uid); } @Override public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, Intent origIntent, String resolvedType, String callingPackage, @Nullable String callingFeatureId, boolean isRequesterInstantApp, Bundle verificationBundle, int userId) { PackageManagerService.this.requestInstantAppResolutionPhaseTwo(responseObj, origIntent, resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp, verificationBundle, userId); } @Override public void grantImplicitAccess(int userId, Intent intent, int recipientAppId, int visibleUid, boolean direct) { synchronized (mLock) { final AndroidPackage visiblePackage = getPackage(visibleUid); final int recipientUid = UserHandle.getUid(userId, recipientAppId); if (visiblePackage == null || getPackage(recipientUid) == null) { return; } final boolean instantApp = 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.grantInstantAccessLPw(userId, intent, recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/); } else { accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid); } if (accessGranted) { ApplicationPackageManager.invalidateGetPackagesForUidCache(); } } } @Override public boolean isInstantAppInstallerComponent(ComponentName component) { synchronized (mLock) { return mInstantAppInstallerActivity != null && mInstantAppInstallerActivity.getComponentName().equals(component); } } @Override public void pruneInstantApps() { mInstantAppRegistry.pruneInstantApps(); } @Override public void pruneCachedApksInApex(@NonNull List apexPackages) { if (mCacheDir == null) { return; } final PackageCacher cacher = new PackageCacher(mCacheDir); synchronized (mLock) { for (int i = 0, size = apexPackages.size(); i < size; i++) { final List apkNames = mApexManager.getApksInApex(apexPackages.get(i).packageName); for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) { final AndroidPackage pkg = getPackage(apkNames.get(j)); cacher.cleanCachedResult(new File(pkg.getPath())); } } } } @Override public String getSetupWizardPackageName() { return mSetupWizardPackage; } public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) { if (policy != null) { mExternalSourcesPolicy = policy; } } @Override public boolean isPackagePersistent(String packageName) { synchronized (mLock) { AndroidPackage pkg = mPackages.get(packageName); return pkg != null && pkg.isSystem() && pkg.isPersistent(); } } @Override public List getOverlayPackages(int userId) { final ArrayList overlayPackages = new ArrayList(); synchronized (mLock) { for (AndroidPackage p : mPackages.values()) { if (p.getOverlayTarget() != null) { PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()), 0, userId); if (pkg != null) { overlayPackages.add(pkg); } } } } return overlayPackages; } @Override public List getTargetPackageNames(int userId) { List targetPackages = new ArrayList<>(); synchronized (mLock) { for (AndroidPackage p : mPackages.values()) { if (p.getOverlayTarget() == null) { targetPackages.add(p.getPackageName()); } } } return targetPackages; } @Override public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName, @Nullable OverlayPaths overlayPaths, @NonNull Set outUpdatedPackageNames) { boolean modified = false; synchronized (mLock) { final AndroidPackage targetPkg = mPackages.get(targetPackageName); if (targetPackageName == null || targetPkg == null) { Slog.e(TAG, "failed to find package " + targetPackageName); return false; } if (targetPkg.getLibraryNames() != null) { // Set the overlay paths for dependencies of the shared library. for (final String libName : targetPkg.getLibraryNames()) { final SharedLibraryInfo info = getSharedLibraryInfoLPr(libName, SharedLibraryInfo.VERSION_UNDEFINED); if (info == null) { continue; } final List dependents = getPackagesUsingSharedLibraryLPr( info, 0, Process.SYSTEM_UID, userId); if (dependents == null) { continue; } for (final VersionedPackage dependent : dependents) { final PackageSetting ps = mSettings.getPackageLPr( dependent.getPackageName()); if (ps == null) { continue; } if (ps.setOverlayPathsForLibrary(libName, overlayPaths, userId)) { outUpdatedPackageNames.add(dependent.getPackageName()); modified = true; } } } } final PackageSetting ps = mSettings.getPackageLPr(targetPackageName); if (ps.setOverlayPaths(overlayPaths, userId)) { outUpdatedPackageNames.add(targetPackageName); modified = true; } if (modified) { invalidatePackageInfoCache(); } } return true; } @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid) { return resolveIntentInternal( intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart, filterCallingUid); } @Override public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId, int callingUid) { return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid); } @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId) { return PackageManagerService.this.resolveContentProviderInternal( name, flags, userId); } @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId, int callingUid) { return PackageManagerService.this.resolveContentProviderInternal( name, flags, userId, callingUid); } @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 int getUidTargetSdkVersion(int uid) { synchronized (mLock) { return getUidTargetSdkVersionLockedLPr(uid); } } @Override public int getPackageTargetSdkVersion(String packageName) { synchronized (mLock) { return getPackageTargetSdkVersionLockedLPr(packageName); } } @Override public boolean canAccessInstantApps(int callingUid, int userId) { return PackageManagerService.this.canViewInstantApps(callingUid, userId); } @Override public boolean canAccessComponent(int callingUid, ComponentName component, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(component.getPackageName()); return ps != null && !PackageManagerService.this.shouldFilterApplicationLocked( ps, callingUid, component, TYPE_UNKNOWN, userId); } } @Override public boolean hasInstantApplicationMetadata(String packageName, int userId) { synchronized (mLock) { return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId); } } @Override public void notifyPackageUse(String packageName, int reason) { synchronized (mLock) { PackageManagerService.this.notifyPackageUseLocked(packageName, reason); } } @Override public SparseArray getAppsWithSharedUserIds() { synchronized (mLock) { return getAppsWithSharedUserIdsLocked(); } } @Override @NonNull public String[] getSharedUserPackagesForPackage(String packageName, int userId) { synchronized (mLock) { return getSharedUserPackagesForPackageLocked(packageName, userId); } } @Override public ArrayMap getProcessesForUid(int uid) { synchronized (mLock) { return getProcessesForUidLocked(uid); } } @Override public int[] getPermissionGids(String permissionName, int userId) { return mPermissionManager.getPermissionGids(permissionName, userId); } @Override public boolean isOnlyCoreApps() { return PackageManagerService.this.isOnlyCoreApps(); } @Override public void freeStorage(String volumeUuid, long bytes, int storageFlags) throws IOException { PackageManagerService.this.freeStorage(volumeUuid, bytes, storageFlags); } @Override public void forEachPackage(Consumer actionLocked) { PackageManagerService.this.forEachPackage(actionLocked); } @Override public void forEachPackageSetting(Consumer actionLocked) { synchronized (mLock) { for (int index = 0; index < mSettings.getPackagesLocked().size(); index++) { actionLocked.accept(mSettings.getPackagesLocked().valueAt(index)); } } } @Override public void forEachInstalledPackage(@NonNull Consumer actionLocked, @UserIdInt int userId) { PackageManagerService.this.forEachInstalledPackage(actionLocked, userId); } @Override public ArraySet getEnabledComponents(String packageName, int userId) { synchronized (mLock) { PackageSetting setting = mSettings.getPackageLPr(packageName); if (setting == null) { return new ArraySet<>(); } return setting.getEnabledComponents(userId); } } @Override public ArraySet getDisabledComponents(String packageName, int userId) { synchronized (mLock) { PackageSetting setting = mSettings.getPackageLPr(packageName); if (setting == null) { return new ArraySet<>(); } return setting.getDisabledComponents(userId); } } @Override public @PackageManager.EnabledState int getApplicationEnabledState( String packageName, int userId) { synchronized (mLock) { PackageSetting setting = mSettings.getPackageLPr(packageName); if (setting == null) { return COMPONENT_ENABLED_STATE_DEFAULT; } return setting.getEnabled(userId); } } @Override public @PackageManager.EnabledState int getComponentEnabledSetting( @NonNull ComponentName componentName, int callingUid, int userId) { return PackageManagerService.this.getComponentEnabledSettingInternal(componentName, callingUid, userId); } @Override public void setEnableRollbackCode(int token, int enableRollbackCode) { PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode); } /** * Ask the package manager to compile layouts in the given package. */ @Override public boolean compileLayouts(String packageName) { AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { return false; } } return mArtManagerService.compileLayouts(pkg); } @Override public void finishPackageInstall(int token, boolean didLaunch) { PackageManagerService.this.finishPackageInstall(token, didLaunch); } @Nullable @Override public String removeLegacyDefaultBrowserPackageName(int userId) { synchronized (mLock) { return mSettings.removeDefaultBrowserPackageNameLPw(userId); } } @Override public boolean isApexPackage(String packageName) { return PackageManagerService.this.mApexManager.isApexPackage(packageName); } @Override public List getApksInApex(String apexPackageName) { return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName); } @Override public void uninstallApex(String packageName, long versionCode, int userId, IntentSender intentSender, int flags) { final int callerUid = Binder.getCallingUid(); if (callerUid != Process.ROOT_UID && callerUid != Process.SHELL_UID) { 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 = am.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); 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); } } @Override public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) { synchronized (mLock) { mSettings.updateRuntimePermissionsFingerprintLPr(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) { scheduleWriteSettingsLocked(); } else { writeSettingsLPrTEMP(); } } } @Override public void writePermissionSettings(int[] userIds, boolean async) { synchronized (mLock) { for (int userId : userIds) { mSettings.writePermissionStateForUserLPr(userId, !async); } } } @Override public boolean isCallerInstallerOfRecord( @NonNull AndroidPackage pkg, int callingUid) { synchronized (mLock) { if (pkg == null) { return false; } final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName()); if (packageSetting == null) { return false; } final PackageSetting installerPackageSetting = mSettings.getPackageLPr(packageSetting.installSource.installerPackageName); return installerPackageSetting != null && UserHandle.isSameApp(installerPackageSetting.appId, callingUid); } } @Override public boolean isPermissionUpgradeNeeded(int userId) { synchronized (mLock) { return mSettings.isPermissionUpgradeNeededLPr(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 List getMimeGroup(String packageName, String mimeGroup) { return PackageManagerService.this.getMimeGroupInternal(packageName, mimeGroup); } @Override public void setVisibilityLogging(String packageName, boolean enable) { final PackageSetting pkg; synchronized (mLock) { pkg = mSettings.getPackageLPr(packageName); } if (pkg == null) { throw new IllegalStateException("No package found for " + packageName); } mAppsFilter.getFeatureConfig().enableLogging(pkg.appId, enable); } @Override public boolean isSystemPackage(@NonNull String packageName) { return packageName.equals( PackageManagerService.this.ensureSystemPackageName(packageName)); } @Override public void clearBlockUninstallForUser(@UserIdInt int userId) { synchronized (mLock) { mSettings.clearBlockUninstallLPw(userId); mSettings.writePackageRestrictionsLPr(userId); } } @Override public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) { PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser); } @Override public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) { return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId); } @Override public boolean registerInstalledLoadingProgressCallback(String packageName, PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) { final PackageSetting ps = getPackageSettingForUser(packageName, Binder.getCallingUid(), userId); if (ps == null) { return false; } if (!ps.isPackageLoading()) { 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 PackageSetting ps = getPackageSettingForUser(packageName, filterCallingUid, userId); if (ps == null) { return null; } return ps.getIncrementalStates(); } @Override public void requestChecksums(@NonNull String packageName, boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required, @Nullable List trustedInstallers, @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId, @NonNull Executor executor, @NonNull Handler handler) { requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers, onChecksumsReadyListener, userId, executor, handler); } @Override public boolean isPackageFrozen(@NonNull String packageName, int callingUid, int userId) { return PackageManagerService.this.getPackageStartability( packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN; } @Override public long deleteOatArtifactsOfPackage(String packageName) { return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName); } @Override public void withPackageSettingsSnapshot( @NonNull Consumer> block) { final Computer snapshot = snapshotComputer(); // This method needs to either lock or not lock consistently throughout the method, // so if the live computer is returned, force a wrapping sync block. if (snapshot == mLiveComputer) { synchronized (mLock) { block.accept(snapshot::getPackageSetting); } } else { block.accept(snapshot::getPackageSetting); } } @Override public Output withPackageSettingsSnapshotReturning( @NonNull FunctionalUtils.ThrowingFunction, Output> block) { final Computer snapshot = snapshotComputer(); // This method needs to either lock or not lock consistently throughout the method, // so if the live computer is returned, force a wrapping sync block. if (snapshot == mLiveComputer) { synchronized (mLock) { return block.apply(snapshot::getPackageSetting); } } else { return block.apply(snapshot::getPackageSetting); } } @Override public void withPackageSettingsSnapshotThrowing( @NonNull FunctionalUtils.ThrowingCheckedConsumer, ExceptionType> block) throws ExceptionType { final Computer snapshot = snapshotComputer(); // This method needs to either lock or not lock consistently throughout the method, // so if the live computer is returned, force a wrapping sync block. if (snapshot == mLiveComputer) { synchronized (mLock) { block.accept(snapshot::getPackageSetting); } } else { block.accept(snapshot::getPackageSetting); } } @Override public void withPackageSettingsSnapshotThrowing2( @NonNull FunctionalUtils.ThrowingChecked2Consumer< Function, ExceptionOne, ExceptionTwo> block) throws ExceptionOne, ExceptionTwo { final Computer snapshot = snapshotComputer(); // This method needs to either lock or not lock consistently throughout the method, // so if the live computer is returned, force a wrapping sync block. if (snapshot == mLiveComputer) { synchronized (mLock) { block.accept(snapshot::getPackageSetting); } } else { block.accept(snapshot::getPackageSetting); } } @Override public Output withPackageSettingsSnapshotReturningThrowing( @NonNull FunctionalUtils.ThrowingCheckedFunction< Function, Output, ExceptionType> block) throws ExceptionType { final Computer snapshot = snapshotComputer(); // This method needs to either lock or not lock consistently throughout the method, // so if the live computer is returned, force a wrapping sync block. if (snapshot == mLiveComputer) { synchronized (mLock) { return block.apply(snapshot::getPackageSetting); } } else { return block.apply(snapshot::getPackageSetting); } } } @GuardedBy("mLock") private SparseArray getAppsWithSharedUserIdsLocked() { final SparseArray sharedUserIds = new SparseArray<>(); synchronized (mLock) { for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { sharedUserIds.put(UserHandle.getAppId(setting.userId), setting.name); } } return sharedUserIds; } @GuardedBy("mLock") @NonNull private String[] getSharedUserPackagesForPackageLocked(String packageName, int userId) { final PackageSetting packageSetting = mSettings.getPackageLPr(packageName); if (packageSetting == null || !packageSetting.isSharedUser()) { return EmptyArray.STRING; } ArraySet packages = packageSetting.sharedUser.packages; final int numPackages = packages.size(); String[] res = new String[numPackages]; int i = 0; for (int index = 0; index < numPackages; index++) { final PackageSetting ps = packages.valueAt(index); if (ps.getInstalled(userId)) { res[i++] = ps.name; } } res = ArrayUtils.trimToSize(res, i); return res != null ? res : EmptyArray.STRING; } @GuardedBy("mLock") public ArrayMap getProcessesForUidLocked(int uid) { final int appId = UserHandle.getAppId(uid); final SettingBase obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return PackageInfoUtils.generateProcessInfo(sus.processes, 0); } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; return PackageInfoUtils.generateProcessInfo(ps.pkg.getProcesses(), 0); } return null; } @Override public int getRuntimePermissionsVersion(@UserIdInt int userId) { Preconditions.checkArgumentNonnegative(userId); enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( "getRuntimePermissionVersion"); synchronized (mLock) { return mSettings.getDefaultRuntimePermissionsVersionLPr(userId); } } @Override public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) { Preconditions.checkArgumentNonnegative(version); Preconditions.checkArgumentNonnegative(userId); enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( "setRuntimePermissionVersion"); synchronized (mLock) { mSettings.setDefaultRuntimePermissionsVersionLPr(version, userId); } } 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); } } @Nullable public PackageSetting getPackageSetting(String packageName) { return mComputer.getPackageSetting(packageName); } private PackageSetting getPackageSettingInternal(String packageName, int callingUid) { return mComputer.getPackageSettingInternal(packageName, callingUid); } void forEachPackage(Consumer actionLocked) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { actionLocked.accept(mPackages.valueAt(i)); } } } void forEachInstalledPackage(@NonNull Consumer actionLocked, @UserIdInt int userId) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { AndroidPackage pkg = mPackages.valueAt(i); PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName()); if (setting == null || !setting.getInstalled(userId)) { continue; } actionLocked.accept(pkg); } } } boolean isHistoricalPackageUsageAvailable() { synchronized (mLock) { return mPackageUsage.isHistoricalPackageUsageAvailable(); } } /** * Return a copy of the collection of packages known to the package manager. * @return A copy of the values of mPackages. */ Collection getPackages() { synchronized (mLock) { return new ArrayList<>(mPackages.values()); } } /** * 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) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } if (!SecurityLog.isLoggingEnabled()) { return; } mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName, processName, uid, seinfo, pid); } public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) { return mCompilerStats.getPackageStats(pkgName); } public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) { return getOrCreateCompilerPackageStats(pkg.getPackageName()); } public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) { return mCompilerStats.getOrCreatePackageStats(pkgName); } public void deleteCompilerPackageStats(String pkgName) { mCompilerStats.deletePackageStats(pkgName); } @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 int getInstallReason(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "get install reason"); synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return PackageManager.INSTALL_REASON_UNKNOWN; } if (ps != null) { return ps.getInstallReason(userId); } } return PackageManager.INSTALL_REASON_UNKNOWN; } @Override public boolean canRequestPackageInstalls(String packageName, int userId) { return canRequestPackageInstallsInternal(packageName, Binder.getCallingUid(), userId, true /* throwIfPermNotDeclared*/); } private boolean canRequestPackageInstallsInternal(String packageName, int callingUid, int userId, boolean throwIfPermNotDeclared) { int uid = getPackageUidInternal(packageName, 0, userId, callingUid); if (callingUid != uid && callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID) { throw new SecurityException( "Caller uid " + callingUid + " does not own package " + packageName); } if (isInstantAppInternal(packageName, userId, callingUid)) { return false; } final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } if (pkg == null) { return false; } if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { return false; } if (!pkg.getRequestedPermissions().contains( android.Manifest.permission.REQUEST_INSTALL_PACKAGES)) { final String message = "Need to declare " + android.Manifest.permission.REQUEST_INSTALL_PACKAGES + " to call this api"; if (throwIfPermNotDeclared) { throw new SecurityException(message); } else { Slog.e(TAG, message); return false; } } return !isInstallDisabledForPackage(packageName, uid, userId); } /** * Returns true if the system or user is explicitly preventing an otherwise valid installer to * complete an install. This includes checks like unknown sources and user restrictions. */ public boolean isInstallDisabledForPackage(String packageName, int uid, int userId) { if (mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId) || mUserManager.hasUserRestriction( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) { return true; } if (mExternalSourcesPolicy != null) { int isTrusted = mExternalSourcesPolicy.getPackageTrustedToInstallApps(packageName, uid); return isTrusted != PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED; } return false; } @Override public ComponentName getInstantAppResolverSettingsComponent() { return mInstantAppResolverSettingsComponent; } @Override public ComponentName getInstantAppInstallerComponent() { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return null; } return mInstantAppInstallerActivity == null ? null : mInstantAppInstallerActivity.getComponentName(); } @Override public String getInstantAppAndroidId(String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS, "getInstantAppAndroidId"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "getInstantAppAndroidId"); // Make sure the target is an Instant App. if (!isInstantApp(packageName, userId)) { return null; } synchronized (mLock) { return mInstantAppRegistry.getInstantAppAndroidIdLPw(packageName, userId); } } @Override public void grantImplicitAccess(int recipientUid, String visibleAuthority) { // This API is exposed temporarily to only the contacts provider. (b/158688602) final int callingUid = Binder.getCallingUid(); ProviderInfo contactsProvider = resolveContentProviderInternal( ContactsContract.AUTHORITY, 0, UserHandle.getUserId(callingUid)); if (contactsProvider == null || contactsProvider.applicationInfo == null || !UserHandle.isSameApp(contactsProvider.applicationInfo.uid, callingUid)) { throw new SecurityException(callingUid + " is not allow to call grantImplicitAccess"); } final int userId = UserHandle.getUserId(recipientUid); final long token = Binder.clearCallingIdentity(); final ProviderInfo providerInfo; try { providerInfo = resolveContentProvider(visibleAuthority, 0 /*flags*/, userId); } finally { Binder.restoreCallingIdentity(token); } if (providerInfo == null) { return; } int visibleUid = providerInfo.applicationInfo.uid; mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid, false); } boolean canHaveOatDir(String packageName) { synchronized (mLock) { AndroidPackage p = mPackages.get(packageName); PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); if (p == null || pkgSetting == null) { return false; } return AndroidPackageUtils.canHaveOatDir(p, pkgSetting.getPkgState().isUpdatedSystemApp()); } } long deleteOatArtifactsOfPackage(String packageName) { final AndroidPackage pkg; final PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); pkgSetting = mSettings.getPackageLPr(packageName); } return mDexManager.deleteOptimizedFiles(ArtUtils.createArtPackageInfo(pkg, pkgSetting)); } Set getUnusedPackages(long downgradeTimeThresholdMillis) { Set unusedPackages = new HashSet<>(); long currentTimeInMillis = System.currentTimeMillis(); synchronized (mLock) { for (AndroidPackage pkg : mPackages.values()) { PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName()); if (ps == null) { continue; } PackageDexUsage.PackageUseInfo packageUseInfo = getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName()); if (PackageManagerServiceUtils .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo, ps.getPkgState().getLatestPackageUseTimeInMills(), ps.getPkgState().getLatestForegroundPackageUseTimeInMills())) { unusedPackages.add(pkg.getPackageName()); } } } return unusedPackages; } @Override public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning, int userId) { final int callingUid = Binder.getCallingUid(); final int callingAppId = UserHandle.getAppId(callingUid); enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/, true /*checkShell*/, "setHarmfulAppInfo"); if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID && checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) { throw new SecurityException("Caller must have the " + SET_HARMFUL_APP_WARNINGS + " permission."); } synchronized (mLock) { mSettings.setHarmfulAppWarningLPw(packageName, warning, userId); scheduleWritePackageRestrictionsLocked(userId); } } @Nullable @Override public CharSequence getHarmfulAppWarning(@NonNull String packageName, int userId) { final int callingUid = Binder.getCallingUid(); final int callingAppId = UserHandle.getAppId(callingUid); enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/, true /*checkShell*/, "getHarmfulAppInfo"); if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID && checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) { throw new SecurityException("Caller must have the " + SET_HARMFUL_APP_WARNINGS + " permission."); } synchronized (mLock) { return mSettings.getHarmfulAppWarningLPr(packageName, userId); } } @Override public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) { final int callingUid = Binder.getCallingUid(); final int callingAppId = UserHandle.getAppId(callingUid); enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, true /*checkShell*/, "isPackageStateProtected"); if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID && 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 void sendDeviceCustomizationReadyBroadcast() { mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY, "sendDeviceCustomizationReadyBroadcast"); final long ident = Binder.clearCallingIdentity(); try { final Intent intent = new Intent(Intent.ACTION_DEVICE_CUSTOMIZATION_READY); intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); final IActivityManager am = ActivityManager.getService(); final String[] requiredPermissions = { Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY, }; try { am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null, requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false, false, UserHandle.USER_ALL); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } finally { Binder.restoreCallingIdentity(ident); } } private void applyMimeGroupChanges(String packageName, String mimeGroup) { if (mComponentResolver.updateMimeGroup(packageName, mimeGroup)) { Binder.withCleanCallingIdentity(() -> clearPackagePreferredActivities(packageName, UserHandle.USER_ALL)); } mPmInternal.writeSettings(false); } @Override public void setMimeGroup(String packageName, String mimeGroup, List mimeTypes) { enforceOwnerRights(packageName, Binder.getCallingUid()); final boolean changed; synchronized (mLock) { changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup, mimeTypes); } if (changed) { applyMimeGroupChanges(packageName, mimeGroup); } } @Override public List getMimeGroup(String packageName, String mimeGroup) { enforceOwnerRights(packageName, Binder.getCallingUid()); return getMimeGroupInternal(packageName, mimeGroup); } private List getMimeGroupInternal(String packageName, String mimeGroup) { synchronized (mLock) { return mSettings.getPackageLPr(packageName).getMimeGroup(mimeGroup); } } @Override public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId, int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "setSplashScreenTheme"); enforceOwnerRights(packageName, callingUid); final PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId); if (packageSetting != null) { packageSetting.setSplashScreenTheme(userId, themeId); } } @Override public String getSplashScreenTheme(@NonNull String packageName, int userId) { int callingUid = Binder.getCallingUid(); PackageSetting packageSetting = getPackageSettingForUser(packageName, callingUid, userId); return packageSetting != null ? packageSetting.getSplashScreenTheme(userId) : null; } /** * Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's * writeLegacyPermissionsTEMP() beforehand. * * TODO(zhanghai): This should be removed once we finish migration of permission storage. */ private void writeSettingsLPrTEMP() { mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions); mSettings.writeLPr(); } @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; } @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"); } } @Override public void holdLock(IBinder token, int durationMs) { mTestUtilityService.verifyHoldLockToken(token); synchronized (mLock) { SystemClock.sleep(durationMs); } } private static String getDefaultTimeouts() { final long token = Binder.clearCallingIdentity(); try { return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, PROPERTY_INCFS_DEFAULT_TIMEOUTS, ""); } finally { Binder.restoreCallingIdentity(token); } } private static String getKnownDigestersList() { final long token = Binder.clearCallingIdentity(); try { return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE, PROPERTY_KNOWN_DIGESTERS_LIST, ""); } finally { Binder.restoreCallingIdentity(token); } } /** * Returns the array containing per-uid timeout configuration. * This is derived from DeviceConfig flags. */ public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts() { PerUidReadTimeouts[] result = mPerUidReadTimeoutsCache; if (result == null) { result = parsePerUidReadTimeouts(); mPerUidReadTimeoutsCache = result; } return result; } private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts() { final String defaultTimeouts = getDefaultTimeouts(); final String knownDigestersList = getKnownDigestersList(); final List perPackageReadTimeouts = PerPackageReadTimeouts.parseDigestersList(defaultTimeouts, knownDigestersList); if (perPackageReadTimeouts.size() == 0) { return EMPTY_PER_UID_READ_TIMEOUTS_ARRAY; } final int[] allUsers = mInjector.getUserManagerService().getUserIds(); List result = new ArrayList<>(perPackageReadTimeouts.size()); synchronized (mLock) { for (int i = 0, size = perPackageReadTimeouts.size(); i < size; ++i) { final PerPackageReadTimeouts perPackage = perPackageReadTimeouts.get(i); final PackageSetting ps = mSettings.mPackages.get(perPackage.packageName); if (ps == null) { if (DEBUG_PER_UID_READ_TIMEOUTS) { Slog.i(TAG, "PerUidReadTimeouts: package not found = " + perPackage.packageName); } continue; } if (ps.appId < Process.FIRST_APPLICATION_UID) { if (DEBUG_PER_UID_READ_TIMEOUTS) { Slog.i(TAG, "PerUidReadTimeouts: package is system, appId=" + ps.appId); } 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.getInstalled(userId)) { continue; } final int uid = UserHandle.getUid(userId, ps.appId); 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()]); } static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions( @PowerWhitelistManager.ReasonCode int reasonCode) { long duration = 10_000; final ActivityManagerInternal amInternal = LocalServices.getService(ActivityManagerInternal.class); if (amInternal != null) { duration = amInternal.getBootTimeTempAllowListDuration(); } final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); bOptions.setTemporaryAppAllowlist(duration, TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, reasonCode, ""); return bOptions; } @NonNull public DomainVerificationService.Connection getDomainVerificationConnection() { return mDomainVerificationConnection; } @Override public void setKeepUninstalledPackages(List packageList) { mContext.enforceCallingPermission( Manifest.permission.KEEP_UNINSTALLED_PACKAGES, "setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission"); Objects.requireNonNull(packageList); setKeepUninstalledPackagesInternal(packageList); } private void setKeepUninstalledPackagesInternal(List packageList) { Preconditions.checkNotNull(packageList); List removedFromList = null; synchronized (mLock) { if (mKeepUninstalledPackages != null) { final int packagesCount = mKeepUninstalledPackages.size(); for (int i = 0; i < packagesCount; i++) { String oldPackage = mKeepUninstalledPackages.get(i); if (packageList != null && packageList.contains(oldPackage)) { continue; } if (removedFromList == null) { removedFromList = new ArrayList<>(); } removedFromList.add(oldPackage); } } mKeepUninstalledPackages = new ArrayList<>(packageList); if (removedFromList != null) { final int removedCount = removedFromList.size(); for (int i = 0; i < removedCount; i++) { deletePackageIfUnusedLPr(removedFromList.get(i)); } } } } private static class TempUserState { public final int enabledState; @Nullable public final String lastDisableAppCaller; public final boolean installed; private TempUserState(int enabledState, @Nullable String lastDisableAppCaller, boolean installed) { this.enabledState = enabledState; this.lastDisableAppCaller = lastDisableAppCaller; this.installed = installed; } } } interface PackageSender { /** * @param userIds User IDs where the action occurred on a full application * @param instantUserIds User IDs where the action occurred on an instant application */ void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, @Nullable SparseArray broadcastAllowList, @Nullable Bundle bOptions); void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds, int[] instantUserIds, int dataLoaderType); void notifyPackageAdded(String packageName, int uid); void notifyPackageChanged(String packageName, int uid); void notifyPackageRemoved(String packageName, int uid); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy