blob: 498485f5525c39332734cfc707e1bd151b880690 [file] [log] [blame]
/*
* 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.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_IGNORED;
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.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.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_UNKNOWN;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.Manifest;
import android.annotation.AppIdInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
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.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.IStagedApexObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
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.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ComponentEnabledSetting;
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.PackagePartitions;
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.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.StagedApexInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ParsingPackageUtils;
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.ParsedProvider;
import android.content.pm.pkg.PackageUserState;
import android.content.pm.pkg.PackageUserStateInternal;
import android.content.pm.pkg.PackageUserStateUtils;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.IncrementalManager;
import android.os.incremental.PerUidReadTimeouts;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
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.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.F2fsUtils;
import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
import com.android.permission.persistence.RuntimePermissionsPersistence;
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.Watchdog;
import com.android.server.apphibernation.AppHibernationManagerInternal;
import com.android.server.apphibernation.AppHibernationService;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.Installer.InstallerException;
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.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
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.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateImpl;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
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 dalvik.system.VMRuntime;
import libcore.util.EmptyArray;
import libcore.util.HexEncoding;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.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.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.
* <p>
* Internally there are three important locks:
* <ul>
* <li>{@link #mLock} is used to guard all in-memory parsed package details
* and other related state. It is a fine-grained lock that should only be held
* momentarily, as it's one of the most contended locks in the system.
* <li>{@link #mInstallLock} is used to guard all {@code installd} access, whose
* operations typically involve heavy lifting of application data on disk. Since
* {@code installd} is single-threaded, and it's operations can often be slow,
* this lock should never be acquired while already holding {@link #mLock}.
* Conversely, it's safe to acquire {@link #mLock} momentarily while already
* holding {@link #mInstallLock}.
* <li>{@link #mSnapshotLock} is used to guard access to two snapshot fields: the snapshot
* itself and the snapshot invalidation flag. This lock should never be acquired while
* already holding {@link #mLock}. Conversely, it's safe to acquire {@link #mLock}
* momentarily while already holding {@link #mSnapshotLock}.
* </ul>
* Many internal methods rely on the caller to hold the appropriate locks, and
* this contract is expressed through method name suffixes:
* <ul>
* <li>fooLI(): the caller must hold {@link #mInstallLock}
* <li>fooLIF(): the caller must hold {@link #mInstallLock} and the package
* being modified must be frozen
* <li>fooLPr(): the caller must hold {@link #mLock} for reading
* <li>fooLPw(): the caller must hold {@link #mLock} for writing
* </ul>
* {@link #mSnapshotLock} is taken in exactly one place - {@code snapshotComputer()}. It
* should not be taken anywhere else or used for any other purpose.
* <p>
* Because this class is very central to the platform's security; please run all
* CTS and unit tests whenever making modifications:
*
* <pre>
* $ runtest -c android.content.pm.PackageManagerTests frameworks-core
* $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
* </pre>
*/
public class PackageManagerService 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;
static final boolean DEBUG_BACKUP = false;
public static final boolean DEBUG_INSTALL = false;
public static final boolean DEBUG_REMOVE = false;
static final boolean DEBUG_PACKAGE_INFO = false;
static final boolean DEBUG_INTENT_MATCHING = false;
public static final boolean DEBUG_PACKAGE_SCANNING = false;
static final boolean DEBUG_VERIFY = false;
public static final boolean DEBUG_PERMISSIONS = false;
public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
public static final boolean TRACE_SNAPSHOTS = false;
private static final boolean DEBUG_PER_UID_READ_TIMEOUTS = false;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
// user, but by default initialize to this.
public static final boolean DEBUG_DEXOPT = false;
static final boolean DEBUG_ABI_SELECTION = false;
public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
static final boolean HIDE_EPHEMERAL_APIS = false;
static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
private static final int SE_UID = Process.SE_UID;
private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID;
private static final int UWB_UID = Process.UWB_UID;
static final int SCAN_NO_DEX = 1 << 0;
static final int SCAN_UPDATE_SIGNATURE = 1 << 1;
static final int SCAN_NEW_INSTALL = 1 << 2;
static final int SCAN_UPDATE_TIME = 1 << 3;
static final int SCAN_BOOTING = 1 << 4;
static final int SCAN_REQUIRE_KNOWN = 1 << 7;
static final int SCAN_MOVE = 1 << 8;
static final int SCAN_INITIAL = 1 << 9;
static final int SCAN_DONT_KILL_APP = 1 << 10;
static final int SCAN_IGNORE_FROZEN = 1 << 11;
static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
static final int SCAN_AS_INSTANT_APP = 1 << 13;
static final int SCAN_AS_FULL_APP = 1 << 14;
static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
static final int SCAN_AS_SYSTEM = 1 << 16;
static final int SCAN_AS_PRIVILEGED = 1 << 17;
static final int SCAN_AS_OEM = 1 << 18;
static final int SCAN_AS_VENDOR = 1 << 19;
static final int SCAN_AS_PRODUCT = 1 << 20;
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
@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 <b>not</b> 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 <b>not</b> 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 <b>not</b> 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 <b>not</b> 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";
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;
/**
* Default IncFs timeouts. Maximum values in IncFs is 1hr.
*
* <p>If flag value is empty, the default value will be assigned.
*
* Flag type: {@code String}
* Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
*/
private static final String PROPERTY_INCFS_DEFAULT_TIMEOUTS = "incfs_default_timeouts";
/**
* Known digesters with optional timeouts.
*
* Flag type: {@code String}
* Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE
*/
private static final String PROPERTY_KNOWN_DIGESTERS_LIST = "known_digesters_list";
/**
* The default response for package verification timeout.
*
* This can be either PackageManager.VERIFICATION_ALLOW or
* PackageManager.VERIFICATION_REJECT.
*/
static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
/**
* Adding an installer package name to a package that does not have one set requires the
* INSTALL_PACKAGES permission.
*
* If the caller targets R, this will throw a SecurityException. Otherwise the request will
* fail silently. In both cases, and regardless of whether this change is enabled, the
* installer package will remain unchanged.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
150857253;
public static final String PLATFORM_PACKAGE_NAME = "android";
static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
static final String PACKAGE_SCHEME = "package";
private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager";
// 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;
static final String RANDOM_DIR_PREFIX = "~~";
final Handler mHandler;
final ProcessLoggingHandler mProcessLoggingHandler;
private final boolean mEnableFreeCacheV2;
private 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;
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<String, AndroidPackage> mPackages = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, AndroidPackage>> mPackagesSnapshot =
new SnapshotCache.Auto(mPackages, mPackages, "PackageManagerService.mPackages");
// Keys are isolated uids and values are the uid of the application
// that created the isolated process.
@Watched
@GuardedBy("mLock")
final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
private final SnapshotCache<WatchedSparseIntArray> mIsolatedOwnersSnapshot =
new SnapshotCache.Auto(mIsolatedOwners, mIsolatedOwners,
"PackageManagerService.mIsolatedOwners");
/**
* Tracks 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 ArrayMap<String, File> 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<String> mExistingPackages = null;
/**
* List of code paths that need to be released when the system becomes ready.
* <p>
* NOTE: We have to delay releasing cblocks for no other reason than we cannot
* retrieve the setting {@link Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL}. When
* we no longer need to read that setting, cblock release can occur in the
* constructor.
*
* @see Secure#RELEASE_COMPRESS_BLOCKS_ON_INSTALL
* @see #systemReady()
*/
@Nullable List<File> mReleaseOnSystemReady;
/**
* Whether or not system app permissions should be promoted from install to runtime.
*/
boolean mPromoteSystemApps;
private final 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<String> mFrozenPackages = new ArraySet<>();
final ProtectedPackages mProtectedPackages;
@GuardedBy("mLoadedVolumes")
final ArraySet<String> mLoadedVolumes = new ArraySet<>();
boolean mFirstBoot;
final boolean mIsEngBuild;
private final boolean mIsUserDebugBuild;
private final String mIncrementalVersion;
PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
@GuardedBy("mAvailableFeatures")
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
@Watched
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<SparseArray<String>> 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<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
@GuardedBy("mLock")
final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
private final ModuleInfoProvider mModuleInfoProvider;
final ApexManager mApexManager;
final PackageManagerServiceInjector mInjector;
/**
* The list of all system partitions that may contain packages in ascending order of
* specificity (the more generic, the earlier in the list a partition appears).
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static final List<ScanPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
PackagePartitions.getOrderedPartitions(ScanPartition::new));
private final List<ScanPartition> mDirsToScanAsSystem;
final OverlayConfig mOverlayConfig;
@GuardedBy("itself")
final private ArrayList<IPackageChangeObserver> mPackageChangeObservers =
new ArrayList<>();
// Cached parsed flag value. Invalidated on each flag change.
PerUidReadTimeouts[] mPerUidReadTimeoutsCache;
private static final PerUidReadTimeouts[] EMPTY_PER_UID_READ_TIMEOUTS_ARRAY = {};
private static class DefaultSystemWrapper implements
PackageManagerServiceInjector.SystemWrapper {
@Override
public void disablePackageCaches() {
// disable all package caches that shouldn't apply within system server
PackageManager.disableApplicationInfoCache();
PackageManager.disablePackageInfoCache();
ApplicationPackageManager.invalidateGetPackagesForUidCache();
ApplicationPackageManager.disableGetPackagesForUidCache();
ApplicationPackageManager.invalidateHasSystemFeatureCache();
// 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();
}
}
@Watched
final AppsFilter mAppsFilter;
final PackageParser2.Callback mPackageParserCallback;
// Currently known shared libraries.
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mSharedLibraries = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mSharedLibrariesSnapshot =
new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
"PackageManagerService.mSharedLibraries");
@Watched
final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
mStaticLibsByDeclaringPackageSnapshot =
new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
"PackageManagerService.mStaticLibsByDeclaringPackage");
// Mapping from instrumentation class names to info about them.
@Watched
private final WatchedArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
new WatchedArrayMap<>();
private final SnapshotCache<WatchedArrayMap<ComponentName, ParsedInstrumentation>>
mInstrumentationSnapshot =
new SnapshotCache.Auto<>(mInstrumentation, mInstrumentation,
"PackageManagerService.mInstrumentation");
// Packages whose data we have transfered into another package, thus
// should no longer exist.
final ArraySet<String> mTransferredPackages = new ArraySet<>();
// Broadcast actions that are only available to the system.
@GuardedBy("mProtectedBroadcasts")
final ArraySet<String> mProtectedBroadcasts = new ArraySet<>();
/** List of packages waiting for verification. */
final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
/** List of packages waiting for rollback to be enabled. */
final SparseArray<VerificationParams> mPendingEnableRollback = new SparseArray<>();
final PackageInstallerService mInstallerService;
final ArtManagerService mArtManagerService;
final PackageDexOptimizer mPackageDexOptimizer;
final BackgroundDexOptService mBackgroundDexOptService;
// 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;
final ViewCompiler mViewCompiler;
private final AtomicInteger mNextMoveId = new AtomicInteger();
final MovePackageHelper.MoveCallbacks mMoveCallbacks;
// Cache of users who need badging.
private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
/** Token for keys in mPendingVerification. */
int mPendingVerificationToken = 0;
/** Token for keys in mPendingEnableRollback. */
int mPendingEnableRollbackToken = 0;
@Watched(manual = true)
volatile boolean mSystemReady;
@Watched(manual = true)
private volatile boolean mSafeMode;
@Watched
private final WatchedSparseBooleanArray mWebInstantAppsDisabled =
new WatchedSparseBooleanArray();
@Watched(manual = true)
ApplicationInfo mAndroidApplication;
@Watched(manual = true)
final ActivityInfo mResolveActivity = new ActivityInfo();
final ResolveInfo mResolveInfo = new ResolveInfo();
@Watched(manual = true)
ComponentName mResolveComponentName;
AndroidPackage mPlatformPackage;
ComponentName mCustomResolverComponentName;
boolean mResolverReplaced = false;
@NonNull
final DomainVerificationManagerInternal mDomainVerificationManager;
/** The service connection to the ephemeral resolver */
final InstantAppResolverConnection mInstantAppResolverConnection;
/** Component used to show resolver settings for Instant Apps */
final ComponentName mInstantAppResolverSettingsComponent;
/** Activity used to install instant applications */
@Watched(manual = true)
ActivityInfo mInstantAppInstallerActivity;
@Watched(manual = true)
private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
private final Map<String, Pair<PackageInstalledInfo, IPackageInstallObserver2>>
mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
// Internal interface for permission manager
final PermissionManagerServiceInternal mPermissionManager;
@Watched
final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
private List<String> mKeepUninstalledPackages;
// Cached reference to IDevicePolicyManager.
private IDevicePolicyManager mDevicePolicyManager = null;
private File mCacheDir;
private Future<?> mPrepareAppDataFuture;
final IncrementalManager mIncrementalManager;
private final DefaultAppProvider mDefaultAppProvider;
private final LegacyPermissionManagerInternal mLegacyPermissionManager;
private final PackageProperty mPackageProperty = new PackageProperty();
final PendingPackageBroadcasts mPendingBroadcasts;
static final int SEND_PENDING_BROADCAST = 1;
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;
private 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
final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<>();
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
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 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();
final CompilerStats mCompilerStats = new CompilerStats();
private final DomainVerificationConnection mDomainVerificationConnection;
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
private final AppDataHelper mAppDataHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
private final ResolveIntentHelper mResolveIntentHelper;
/**
* Invalidate the package info cache, which includes updating the cached computer.
* @hide
*/
public static void invalidatePackageInfoCache() {
PackageManager.invalidatePackageInfoCache();
onChanged();
}
private final Watcher mWatcher = new Watcher() {
@Override
public void onChange(@Nullable Watchable what) {
PackageManagerService.onChange(what);
}
};
/**
* A Snapshot is a subset of PackageManagerService state. A snapshot is either live
* or snapped. Live snapshots directly reference PackageManagerService attributes.
* Snapped snapshots contain deep copies of the attributes.
*/
class Snapshot {
public static final int LIVE = 1;
public static final int SNAPPED = 2;
public final Settings settings;
public final WatchedSparseIntArray isolatedOwners;
public final WatchedArrayMap<String, AndroidPackage> packages;
public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibs;
public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> staticLibs;
public final WatchedArrayMap<ComponentName, ParsedInstrumentation> instrumentation;
public final WatchedSparseBooleanArray webInstantAppsDisabled;
public final ComponentName resolveComponentName;
public final ActivityInfo resolveActivity;
public final ActivityInfo instantAppInstallerActivity;
public final ResolveInfo instantAppInstallerInfo;
public final InstantAppRegistry instantAppRegistry;
public final ApplicationInfo androidApplication;
public final String appPredictionServicePackage;
public final 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;
}
}
// 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 final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
// 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.
static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
static final ThreadLocal<ThreadComputer> sThreadComputer =
ThreadLocal.withInitial(ThreadComputer::new);
/**
* 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 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.
*/
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.
*/
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 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 <what> parameter is left null,
* but it signifies that the change was detected by PackageManagerService itself.
*/
static void onChanged() {
onChange(null);
}
@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);
}
}
}
void notifyInstallObserver(String packageName) {
Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
mNoKillInstallObservers.remove(packageName);
if (pair != null) {
notifyInstallObserver(pair.first, pair.second);
}
}
void notifyInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(info);
installObserver.onPackageInstalled(info.mName, info.mReturnCode,
info.mReturnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
String packageName = info.mPkg.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<Pair<String, File>> filesToChecksum = new ArrayList<>();
// Adding base split.
filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir)));
// Adding other splits.
if (includeSplits && applicationInfo.splitNames != null) {
for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) {
filesToChecksum.add(Pair.create(applicationInfo.splitNames[i],
new File(applicationInfo.splitSourceDirs[i])));
}
}
final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
trustedInstallers) : null;
executor.execute(() -> {
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
() -> mInjector.getIncrementalManager(),
() -> 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);
}
}
private static Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
switch (res.mReturnCode) {
case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
extras = new Bundle();
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
res.mOrigPermission);
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
res.mOrigPackage);
break;
}
case PackageManager.INSTALL_SUCCEEDED: {
extras = new Bundle();
extras.putBoolean(Intent.EXTRA_REPLACING,
res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != 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);
}
}
private void scheduleWritePackageListLocked(int userId) {
invalidatePackageInfoCache();
if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST);
msg.arg1 = userId;
mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
}
}
void 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());
PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
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 new PackageHandler(thread.getLooper(), pm);
},
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService,
(i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager()));
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.getPkg();
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.mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
}
}
};
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
selinuxChangeListener);
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES,
selinuxChangeListener);
m.installAllowlistedSystemPackages();
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 installAllowlistedSystemPackages() {
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() {
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");
}
}
// 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 PackageManagerServiceInjector injector,
@NonNull PackageManagerServiceTestParams testParams) {
mInjector = injector;
mInjector.bootstrap(this);
mAppsFilter = injector.getAppsFilter();
mComponentResolver = injector.getComponentResolver();
mContext = injector.getContext();
mInstaller = injector.getInstaller();
mInstallLock = injector.getInstallLock();
mLock = injector.getLock();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mUserManager = injector.getUserManagerService();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mHandler = injector.getHandler();
mApexManager = testParams.apexManager;
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mBackgroundDexOptService = testParams.backgroundDexOptService;
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;
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;
mAppInstallDir = testParams.appInstallDir;
mAppLib32InstallDir = testParams.appLib32InstallDir;
mIsEngBuild = testParams.isEngBuild;
mIsUserDebugBuild = testParams.isUserDebugBuild;
mIncrementalVersion = testParams.incrementalVersion;
mDomainVerificationConnection = new DomainVerificationConnection(this);
mBroadcastHelper = new BroadcastHelper(mInjector);
mAppDataHelper = new AppDataHelper(this);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mInitAndSystemPackageHelper, mAppDataHelper);
mPreferredActivityHelper = new PreferredActivityHelper(this);
mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
invalidatePackageInfoCache();
}
public PackageManagerService(PackageManagerServiceInjector 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());
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();
mBackgroundDexOptService = injector.getBackgroundDexOptService();
mArtManagerService = injector.getArtManagerService();
mMoveCallbacks = new MovePackageHelper.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<ScanPartition> scanPartitions = new ArrayList<>();
final List<ApexManager.ActiveApexInfo> 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, mPmInternal);
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();
mDomainVerificationConnection = new DomainVerificationConnection(this);
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mDomainVerificationManager.setConnection(mDomainVerificationConnection);
mBroadcastHelper = new BroadcastHelper(mInjector);
mAppDataHelper = new AppDataHelper(this);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mInitAndSystemPackageHelper, mAppDataHelper);
mPreferredActivityHelper = new PreferredActivityHelper(this);
mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
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();
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<String, SystemConfig.SharedLibraryEntry> 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();
}
String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivityName);
}
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath == null) {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath == null) {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade =
!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<String, PackageSetting> 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.getPackageName());
}
}
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);
mInitAndSystemPackageHelper.scanSystemDirs(mDirsToScanAsSystem, mIsUpgrade,
packageParser, executorService, mPlatformPackage, mIsPreNMR1Upgrade,
systemParseFlags, systemScanFlags);
// 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())));
final int[] userIds = mUserManager.getUserIds();
mInitAndSystemPackageHelper.cleanupSystemPackagesAndInstallStubs(mDirsToScanAsSystem,
mIsUpgrade, packageParser, executorService, mOnlyCore, packageSettings,
startTime, mAppInstallDir, mPlatformPackage, mIsPreNMR1Upgrade,
scanFlags, systemParseFlags, systemScanFlags, userIds);
packageParser.close();
// 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();
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<String> changedAbiCodePath =
ScanPackageHelper.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);
}
}
mPrepareAppDataFuture = mAppDataHelper.fixAppsDataOnBoot();
// 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.getVolumeUuid())) {
// No apps are running this early, so no need to freeze
mAppDataHelper.clearAppDataLIF(ps.getPkg(), UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
// Legacy existing (installed before Q) non-system apps to hide
// their icons in launcher.
if (!mOnlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Allowlisting all existing apps to hide their icons");
int size = packageSettings.size();
for (int i = 0; i < size; i++) {
final PackageSetting ps = packageSettings.valueAt(i);
if ((ps.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.getAppId());
}
}
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<Integer, List<PackageInfo>> 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");
}
@GuardedBy("mLock")
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<ResolveInfo> matches =
mResolveIntentHelper.queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, Binder.getCallingUid());
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<ResolveInfo> 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<ResolveInfo> 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<ResolveInfo> matches =
mResolveIntentHelper.queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, Binder.getCallingUid());
ResolveInfo best = null;
final int N = matches.size();
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
}
if (best == null || cur.priority > best.priority) {
best = cur;
}
}
if (best != null) {
return best.getComponentInfo().getComponentName();
}
Slog.w(TAG, "Intent filter verifier not found");
return null;
}
@Nullable
private ComponentName getDomainVerificationAgentComponentNameLPr() {
Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION);
List<ResolveInfo> matches =
mResolveIntentHelper.queryIntentReceiversInternal(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.USER_SYSTEM, Binder.getCallingUid());
ResolveInfo best = null;
final int N = matches.size();
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Domain verification agent found but does not hold permission: "
+ packageName);
continue;
}
if (best == null || cur.priority > best.priority) {
if (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) {
return getInstantAppResolverLPr();
}
}
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<ResolveInfo> 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<String> possiblePackages = new ArraySet<>(Arrays.asList(packageArray));
for (int i = 0; i < N; i++) {
final ResolveInfo info = resolvers.get(i);
if (info.serviceInfo == null) {
continue;
}
final String packageName = info.serviceInfo.packageName;
if (!possiblePackages.contains(packageName) && !Build.IS_DEBUGGABLE) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver not in allowed package list;"
+ " pkg: " + packageName + ", info:" + info);
}
continue;
}
if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver found;"
+ " pkg: " + packageName + ", info:" + info);
}
return new ComponentName(packageName, info.serviceInfo.name);
}
if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver NOT found");
}
return null;
}
@GuardedBy("mLock")
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
String[] orderedActions = mIsEngBuild
? new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST",
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE}
: new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE};
final int resolveFlags =
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| Intent.FLAG_IGNORE_EPHEMERAL
| (mIsEngBuild ? 0 : MATCH_SYSTEM_ONLY);
final Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
List<ResolveInfo> matches = null;
for (String action : orderedActions) {
intent.setAction(action);
matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
resolveFlags, UserHandle.USER_SYSTEM);
if (matches.isEmpty()) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Instant App installer not found with " + action);
}
} else {
break;
}
}
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
if (checkPermission(
Manifest.permission.INSTALL_PACKAGES,
rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
continue;
}
iter.remove();
}
if (matches.size() == 0) {
return null;
} else if (matches.size() == 1) {
return (ActivityInfo) matches.get(0).getComponentInfo();
} else {
throw new RuntimeException(
"There must be at most one ephemeral installer; found " + matches);
}
}
private @Nullable ComponentName getInstantAppResolverSettingsLPr(
@NonNull ComponentName resolver) {
final Intent intent = new Intent(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS)
.addCategory(Intent.CATEGORY_DEFAULT)
.setPackage(resolver.getPackageName());
final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
List<ResolveInfo> matches = 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.
* <p>
* Currently, there are four cases in which this can occur:
* <ol>
* <li>The calling application is a "special" process. Special processes
* are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
* <li>The calling application has the permission
* {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
* <li>The calling application is the default launcher on the
* system partition.</li>
* <li>The calling application is the default app prediction service.</li>
* </ol>
*/
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:
}
}
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.getPkg())) {
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 PackageUserStateUtils.isAvailable(state, 0);
}
}
}
}
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);
}
/**
* Returns whether or not access to the application should be filtered.
* <p>
* 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")
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.getRealName() != null) {
final boolean targetIsInstantApp = ps.getInstantApp(callingUserId);
translateName = !targetIsInstantApp
|| canViewInstantApps
|| mInstantAppRegistry.isInstantAccessGranted(callingUserId,
UserHandle.getAppId(callingUid), ps.getAppId());
}
out[i] = translateName ? ps.getRealName() : 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.getAppId());
}
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)) {
final PackageSetting ps = getPackageSetting(p.getPackageName());
if (ps != null && ps.getInstalled(userId)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return mPermissionManager.getGidsForUid(UserHandle.getUid(userId,
ps.getAppId()));
}
}
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.getAppId()));
}
}
}
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);
}
@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);
} 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<VersionedPackage> packagesToDelete = null;
final long now = System.currentTimeMillis();
synchronized (mLock) {
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
final WatchedLongSparseArray<SharedLibraryInfo> 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.getLastUpdateTime() < maxCachePeriod) {
continue;
}
if (ps.getPkg().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 (mDeletePackageHelper.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 flags when being used to request {@link ResolveInfo}.
* <p>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:
* <ul>
* <li>when called from a system process</li>
* <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
* <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
* action and a {@code android.intent.category.BROWSABLE} category</li>
* </ul>
*/
int updateFlagsForResolve(int flags, int userId, int callingUid,
boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return mComputer.updateFlagsForResolve(flags, userId, callingUid,
wantInstantApps, 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<SharedLibraryInfo> 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<SharedLibraryInfo> result = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
WatchedLongSparseArray<SharedLibraryInfo> 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<SharedLibraryInfo> 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<SharedLibraryInfo> result = null;
int libraryCount = mSharedLibraries.size();
for (int i = 0; i < libraryCount; i++) {
WatchedLongSparseArray<SharedLibraryInfo> 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")
List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
SharedLibraryInfo libInfo, int flags, int callingUid, int userId) {
List<VersionedPackage> 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 (!PackageUserStateUtils.isAvailable(ps.readUserState(userId), 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.getPackageName();
if (ps.getPkg() != null && ps.getPkg().isStaticSharedLibrary()) {
dependentPackageName = ps.getPkg().getManifestPackageName();
}
versionedPackages.add(new VersionedPackage(dependentPackageName,
ps.getLongVersionCode()));
} else if (ps.getPkg() != null) {
if (ArrayUtils.contains(ps.getPkg().getUsesLibraries(), libName)
|| ArrayUtils.contains(ps.getPkg().getUsesOptionalLibraries(), libName)) {
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
if (versionedPackages == null) {
versionedPackages = new ArrayList<>();
}
versionedPackages.add(new VersionedPackage(ps.getPackageName(),
ps.getLongVersionCode()));
}
}
}
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<ModuleInfo> getInstalledModules(int flags) {
return mModuleInfoProvider.getInstalledModules(flags);
}
@Override
public String[] getSystemSharedLibraryNames() {
// allow instant applications
synchronized (mLock) {
Set<String> libs = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
WatchedLongSparseArray<SharedLibraryInfo> 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")
void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
SparseArray<String> changedPackages = mChangedPackages.get(userId);
if (changedPackages == null) {
changedPackages = new SparseArray<>();
mChangedPackages.put(userId, changedPackages);
}
Map<String, Integer> sequenceNumbers = mChangedPackagesSequenceNumbers.get(userId);
if (sequenceNumbers == null) {
sequenceNumbers = new HashMap<>();
mChangedPackagesSequenceNumbers.put(userId, sequenceNumbers);
}
final Integer sequenceNumber = sequenceNumbers.get(pkgSetting.getPackageName());
if (sequenceNumber != null) {
changedPackages.remove(sequenceNumber);
}
changedPackages.put(mChangedPackagesSequenceNumber, pkgSetting.getPackageName());
sequenceNumbers.put(pkgSetting.getPackageName(), 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<String> changedPackages = mChangedPackages.get(userId);
if (changedPackages == null) {
return null;
}
final List<String> 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<FeatureInfo> getSystemAvailableFeatures() {
// allow instant applications
ArrayList<FeatureInfo> res;
synchronized (mAvailableFeatures) {
res = new ArrayList<>(mAvailableFeatures.size() + 1);
res.addAll(mAvailableFeatures.values());
}
final FeatureInfo fi = new FeatureInfo();
fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
FeatureInfo.GL_ES_VERSION_UNDEFINED);
res.add(fi);
return new ParceledListSlice<>(res);
}
@Override
public 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.getSigningDetails();
} 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.getSigningDetails();
} 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.getSignatures(),
p2SigningDetails.getSignatures());
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.getPastSigningCertificates()[0]}
: p1SigningDetails.getSignatures();
Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
? new Signature[]{p2SigningDetails.getPastSigningCertificates()[0]}
: p2SigningDetails.getSignatures();
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 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.getSigningDetails();
} 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;
}
}
}
@Override
public List<String> 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<String> 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.getAppId())) {
continue;
}
result.add(pkg.getPackageName());
}
}
return result;
}
}
/**
* <em>IMPORTANT:</em> Not all packages returned by this method may be known
* to the system. There are two conditions in which this may occur:
* <ol>
* <li>The package is on adoptable storage and the device has been removed</li>
* <li>The package is being removed and the internal structures are partially updated</li>
* </ol>
* 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.getPackageName();
}
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.getPackageName();
}
} else {
names[i] = null;
}
}
}
return names;
}
@Override
public int getUidForSharedUser(String sharedUserName) {
if (sharedUserName == null) {
return Process.INVALID_UID;
}
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
return Process.INVALID_UID;
}
// reader
synchronized (mLock) {
try {
final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName,
0 /* pkgFlags */, 0 /* pkgPrivateFlags */, false /* create */);
if (suid != null && !shouldFilterApplicationLocked(suid, callingUid,
UserHandle.getUserId(callingUid))) {
return suid.userId;
}
} catch (PackageManagerException ignore) {
// can't happen, but, still need to catch it
}
return Process.INVALID_UID;
}
}
@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;
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final ArraySet<String> packageNames = new ArraySet(
mPermissionManager.getAppOpPermissionPackages(permissionName));
synchronized (mLock) {
for (int i = packageNames.size() - 1; i >= 0; i--) {
final String packageName = packageNames.valueAt(i);
if (!shouldFilterApplicationLocked(mSettings.getPackageLPr(packageName),
callingUid, callingUserId)) {
continue;
}
packageNames.removeAt(i);
}
}
return packageNames.toArray(new String[packageNames.size()]);
}
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
return mResolveIntentHelper.resolveIntentInternal(intent, resolvedType, flags,
0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid());
}
@Override
public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
return mPreferredActivityHelper.findPersistentPreferredActivity(intent, userId);
}
@Override
public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
IntentFilter filter, int match, ComponentName activity) {
mPreferredActivityHelper.setLastChosenActivity(intent, resolvedType, flags,
new WatchedIntentFilter(filter), match, activity);
}
@Override
public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
return mPreferredActivityHelper.getLastChosenActivity(intent, resolvedType, flags);
}
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);
}
/**
* 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")
boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
String resolvedType, int flags) {
return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
resolvedType, flags);
}
@GuardedBy("mLock")
ResolveInfo findPersistentPreferredActivityLP(Intent intent,
String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
return mComputer.findPersistentPreferredActivityLP(intent,
resolvedType,
flags, query, debug, userId);
}
// findPreferredActivityBody returns two items: a "things changed" flag and a
// ResolveInfo, which is the preferred activity itself.
static class FindPreferredActivityBodyResult {
boolean mChanged;
ResolveInfo mPreferredResolveInfo;
}
FindPreferredActivityBodyResult findPreferredActivityInternal(
Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
return mComputer.findPreferredActivityInternal(
intent, resolvedType, flags,
query, always,
removeMatches, debug, userId, queryMayBeFiltered);
}
/*
* 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<CrossProfileIntentFilter> 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<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId) {
return mComputer.getMatchingCrossProfileIntentFilters(intent,
resolvedType, userId);
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> 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}.
*/
String getInstantAppPackageName(int callingUid) {
return mComputer.getInstantAppPackageName(callingUid);
}
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
return mComputer.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
}
@NonNull List<ResolveInfo> 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 CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
String resolvedType, int flags, int sourceUserId, int parentUserId) {
return mComputer.getCrossProfileDomainPreferredLpr(intent,
resolvedType, flags, sourceUserId, parentUserId);
}
/**
* Filters out ephemeral activities.
* <p>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.
*/
List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> 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<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
caller, specifics, specificTypes, intent, resolvedType, flags, userId));
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(intent,
resolvedType, flags, userId, Binder.getCallingUid()));
}
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
final int callingUid = Binder.getCallingUid();
return mResolveIntentHelper.resolveServiceInternal(intent, resolvedType, flags, userId,
callingUid);
}
@Override
public @NonNull ParceledListSlice<ResolveInfo> 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*/));
}
@NonNull List<ResolveInfo> 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<ResolveInfo> queryIntentContentProviders(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
intent, resolvedType, flags, userId));
}
@Override
public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
return mComputer.getInstalledPackages(flags, userId);
}
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
for (int i=0; i<permissions.length; i++) {
final String permission = permissions[i];
if (checkPermission(permission, ps.getPackageName(), userId) == PERMISSION_GRANTED) {
tmp[i] = true;
numMatch++;
} else {
tmp[i] = false;
}
}
if (numMatch == 0) {
return;
}
final PackageInfo pi = generatePackageInfo(ps, flags, userId);
// The above might return null in cases of uninstalled apps or install-state
// skew across users/profiles.
if (pi != null) {
if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
if (numMatch == permissions.length) {
pi.requestedPermissions = permissions;
} else {
pi.requestedPermissions = new String[numMatch];
numMatch = 0;
for (int i=0; i<permissions.length; i++) {
if (tmp[i]) {
pi.requestedPermissions[numMatch] = permissions[i];
numMatch++;
}
}
}
}
list.add(pi);
}
}
@Override
public ParceledListSlice<PackageInfo> 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<PackageInfo> 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<ApplicationInfo> getInstalledApplications(int flags, int userId) {
final int callingUid = Binder.getCallingUid();
return new ParceledListSlice<>(
getInstalledApplicationsListInternal(flags, userId, callingUid));
}
private List<ApplicationInfo> 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<ApplicationInfo> 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.getPkg() != null) {
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
ai = PackageInfoUtils.generateApplicationInfo(ps.getPkg(), effectiveFlags,
ps.readUserState(userId), userId, ps);
if (ai != null) {
ai.packageName = resolveExternalPackageNameLPr(ps.getPkg());
}
} else {
// Shared lib filtering done in generateApplicationInfoFromSettingsLPw
// and already converts to externally visible package name
ai = generateApplicationInfoFromSettingsLPw(ps.getPackageName(),
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<InstantAppInfo> 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<InstantAppInfo> 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);
}
}
boolean isCallerSameApp(String packageName, int uid) {
return mComputer.isCallerSameApp(packageName, uid);
}
@Override
public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return ParceledListSlice.emptyList();
}
return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
}
private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
final ArrayList<ApplicationInfo> 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, 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<String> outNames, List<ProviderInfo> outInfo) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
final List<String> names = new ArrayList<>();
final List<ProviderInfo> 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<ProviderInfo> 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<ProviderInfo> finalList = null;
final List<ProviderInfo> 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<InstrumentationInfo> 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<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
int flags, int userId) {
ArrayList<InstrumentationInfo> 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;
}
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
// TODO:(b/135203078): Move to parsing
static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
// Derive the new package synthetic package name
parsedPackage.setPackageName(toStaticSharedLibraryPackageName(
parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibVersion()));
}
private static String toStaticSharedLibraryPackageName(
String packageName, long libraryVersion) {
return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
}
/**
* 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);
}
/**
* Checks if the request is from the system or an app that has the appropriate cross-user
* permissions defined as follows:
* <ul>
* <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
* <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
* to the caller.</li>
* <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
* group as the caller.</li>
* </ul>
*
* @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);
}
@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<PackageSetting> pkgSettings;
synchronized (mLock) {
pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt(
mSettings.getPackagesLocked().values(), this);
}
List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
for (int index = 0; index < pkgSettings.size(); index++) {
pkgs.add(pkgSettings.get(index).getPkg());
}
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<AndroidPackage> 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.getPkg().isStub()) {
// The package is the stub one, remove the stub suffix to get the normal
// package and APK names.
String systemProfilePath = getPrebuildProfilePath(disabledPs.getPkg())
.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 (!PackageDexOptimizer.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_CANCELLED:
// ignore this case
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 (isInstantApp(packageName, callingUserId)) {
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<String, String> 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;
}
}
/*package*/ void controlDexOptBlocking(boolean block) {
mPackageDexOptimizer.controlDexOptBlocking(block);
}
/**
* 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_CANCELLED}
* {@link PackageDexOptimizer#DEX_OPT_FAILED}
*/
@PackageDexOptimizer.DexOptResult
/* 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<String> getOptimizablePackages() {
ArraySet<String> pkgs = new ArraySet<>();
synchronized (mLock) {
for (AndroidPackage p : mPackages.values()) {
if (PackageDexOptimizer.canOptimizePackage(p)) {
pkgs.add(p.getPackageName());
}
}
}
if (AppHibernationService.isAppHibernationEnabled()) {
AppHibernationManagerInternal appHibernationManager =
mInjector.getLocalService(AppHibernationManagerInternal.class);
pkgs.removeIf(pkgName -> appHibernationManager.isHibernatingGlobally(pkgName));
}
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<SharedLibraryInfo> 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);
}
/*package*/ DexManager getDexManager() {
return mDexManager;
}
private static List<SharedLibraryInfo> findSharedLibraries(PackageSetting pkgSetting) {
if (!pkgSetting.getPkgState().getUsesLibraryInfos().isEmpty()) {
ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
Set<String> 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<SharedLibraryInfo> collected, Set<String> 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<PackageSetting> findSharedNonSystemLibraries(PackageSetting pkgSetting) {
List<SharedLibraryInfo> deps = findSharedLibraries(pkgSetting);
if (!deps.isEmpty()) {
List<PackageSetting> retValue = new ArrayList<>();
synchronized (mLock) {
for (SharedLibraryInfo info : deps) {
PackageSetting depPackageSetting =
mSettings.getPackageLPr(info.getPackageName());
if (depPackageSetting != null && depPackageSetting.getPkg() != null) {
retValue.add(depPackageSetting);
}
}
}
return retValue;
} else {
return Collections.emptyList();
}
}
@Nullable
SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
return mComputer.getSharedLibraryInfoLPr(name, version);
}
SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
WatchedLongSparseArray<SharedLibraryInfo> 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
PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
PackageSetting sharedLibPackage = null;
synchronized (mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
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);
}
}
}
int[] resolveUserIds(int userId) {
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
@GuardedBy("mLock")
private void applyDefiningSharedLibraryUpdateLocked(
AndroidPackage pkg, SharedLibraryInfo libInfo,
BiConsumer<SharedLibraryInfo, SharedLibraryInfo> 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<String> 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")
void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
@Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
Map<String, AndroidPackage> availablePackages)
throws PackageManagerException {
final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
SharedLibraryHelper.collectSharedLibraryInfos(
pkgSetting.getPkg(), availablePackages, mSharedLibraries,
null /* newLibraries */, mInjector.getCompatibility());
executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting,
sharedLibraryInfos, mUserManager.getUserIds());
}
void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
@Nullable PackageSetting changingLibSetting,
ArrayList<SharedLibraryInfo> 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<String> 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());
}
}
private static boolean hasString(List<String> list, List<String> 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")
ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
@Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
Map<String, AndroidPackage> availablePackages) {
ArrayList<AndroidPackage> resultList = null;
// Set of all descendants of a library; used to eliminate cycles
ArraySet<String> descendants = null;
// The current list of packages that need updating
List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
if (updatedPkg != null && updatedPkgSetting != null) {
needsUpdating = new ArrayList<>(1);
needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
}
do {
final Pair<AndroidPackage, PackageSetting> 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;
mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
mUserManager.getUserIds(), flags, null,
true);
}
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
} while (needsUpdating != null && needsUpdating.size() > 0);
return resultList;
}
@GuardedBy("mLock")
private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
if (nonStaticSharedLibExistsLocked(entry.name)) {
return;
}
SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN,
new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
entry.isNative);
commitSharedLibraryInfoLocked(libraryInfo);
}
@GuardedBy("mLock")
private boolean nonStaticSharedLibExistsLocked(String name) {
return SharedLibraryHelper.sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED,
mSharedLibraries);
}
@GuardedBy("mLock")
void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) {
final String name = libraryInfo.getName();
WatchedLongSparseArray<SharedLibraryInfo> 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);
}
@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<Property> queryProperty(
String propertyName, @PropertyLocation int componentType) {
Objects.requireNonNull(propertyName);
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getCallingUserId();
final List<Property> 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);
}
private void setUpInstantAppInstallerActivityLP(ActivityInfo installerActivity) {
if (installerActivity == null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Clear ephemeral installer activity");
}
mInstantAppInstallerActivity = null;
onChanged();
return;
}
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral installer activity: "
+ installerActivity.getComponentName());
}
// Set up information for ephemeral installer activity
mInstantAppInstallerActivity = installerActivity;
mInstantAppInstallerActivity.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
mInstantAppInstallerActivity.exported = true;
mInstantAppInstallerActivity.enabled = true;
mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity;
mInstantAppInstallerInfo.priority = 1;
mInstantAppInstallerInfo.preferredOrder = 1;
mInstantAppInstallerInfo.isDefault = true;
mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
onChanged();
}
void killApplication(String pkgName, @AppIdInt int appId, String reason) {
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
}
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);
}
}
@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<int[]> broadcastAllowList,
@Nullable Bundle bOptions) {
mHandler.post(() -> mBroadcastHelper.sendPackageBroadcast(action, pkg, extras, flags,
targetPkg, finishedReceiver, userIds, instantUserIds, broadcastAllowList,
bOptions));
}
@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<ProviderInfo> 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);
}
}
void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId, int dataLoaderType) {
final boolean isSystem = PackageManagerServiceUtils.isSystemApp(pkgSetting)
|| PackageManagerServiceUtils.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.getAppId(), 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;
}
SparseArray<int[]> broadcastAllowList = mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(packageName, Process.SYSTEM_UID),
userIds, mSettings.getPackagesLocked());
mHandler.post(() -> mBroadcastHelper.sendPackageAddedForNewUsers(
packageName, appId, userIds, instantUserIds, dataLoaderType, broadcastAllowList));
if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
mHandler.post(() -> {
for (int userId : userIds) {
mBroadcastHelper.sendBootCompletedBroadcastToSystemApp(
packageName, includeStopped, userId);
}
}
);
}
}
@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.getAppId())
&& 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.getAppId(), 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.mRemovedPackage = packageName;
info.mInstallerPackageName = pkgSetting.getInstallSource().installerPackageName;
info.mRemovedUsers = new int[] {userId};
info.mBroadcastUsers = new int[] {userId};
info.mUid = UserHandle.getUid(userId, pkgSetting.getAppId());
info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/);
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
void sendPackagesSuspendedForUser(String intent, String[] pkgList, int[] uidList, int userId) {
final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
final List<SparseArray<int[]>> 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<int[]> 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<int[]> 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<String> whiteListedPermissions) {
final InstallPackageHelper installPackageHelper = new InstallPackageHelper(
this, mAppDataHelper);
return installPackageHelper.installExistingPackageAsUser(packageName, userId, installFlags,
installReason, whiteListedPermissions, null);
}
static void setInstantAppForUser(PackageManagerServiceInjector 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<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
final List<String> 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.getAppId()));
}
}
}
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(
new String[changedPackagesList.size()]);
mHandler.post(() -> mBroadcastHelper.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<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
final List<String> modifiedPackagesList = new ArrayList<>(packageNames.length);
final IntArray modifiedUids = new IntArray(packageNames.length);
final List<String> 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.getAppId()));
}
if (packageModified) {
modifiedPackagesList.add(packageName);
modifiedUids.add(UserHandle.getUid(userId, pkgSetting.getAppId()));
}
}
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 PackageUserStateInternal pus = ps.readUserState(userId);
final Bundle allExtras = new Bundle();
if (pus.isSuspended()) {
for (int i = 0; i < pus.getSuspendParams().size(); i++) {
final PackageUserState.SuspendParams params = pus.getSuspendParams().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;
}
mHandler.post(() -> mBroadcastHelper.doSendBroadcast(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);
}
private 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.
*
* <p> 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.
*/
private void removeSuspensionsBySuspendingPackage(String[] packagesToChange,
Predicate<String> suspendingPackagePredicate, int userId) {
final List<String> 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.getPackageName());
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.
*
* <p> 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.
*/
private void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) {
final List<String> 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.getPackageName());
changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
}
}
if (!changedPackages.isEmpty()) {
final String[] packageArray = changedPackages.toArray(
new String[changedPackages.size()]);
mHandler.post(() -> mBroadcastHelper.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<String> 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 = getActiveLauncherPackageName(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 ((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 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);
}
@Deprecated
@Override
public void verifyIntentFilter(int id, int verificationCode, List<String> 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<IntentFilterVerificationInfo> getIntentFilterVerifications(
String packageName) {
return ParceledListSlice.emptyList();
}
@Override
public @NonNull ParceledListSlice<IntentFilter> 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<IntentFilter> result = new ArrayList<>();
for (int n=0; n<count; n++) {
ParsedActivity activity = pkg.getActivities().get(n);
if (activity.getIntents() != null && activity.getIntents().size() > 0) {
result.addAll(activity.getIntents());
}
}
return new ParceledListSlice<IntentFilter>(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());
}
};
}
}
@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.getSignatures();
} else if (obj instanceof PackageSetting) {
callerSignature =
((PackageSetting) obj).getSigningDetails().getSignatures();
} 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.getSigningDetails().getSignatures())
!= 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.getInstallSource().installerPackageName;
PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
mSettings.getPackageLPr(targetInstallerPackageName);
if (targetInstallerPkgSetting != null) {
if (compareSignatures(callerSignature,
targetInstallerPkgSetting.getSigningDetails().getSignatures())
!= 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.getInstallSource());
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.getInstallSource().installerPackageName)) {
throw new IllegalArgumentException("Calling package " + callerPackageName
+ " is not installer for " + packageName);
}
if (ps.getCategoryOverride() != categoryHint) {
ps.setCategoryOverride(categoryHint);
scheduleWriteSettingsLocked();
}
}
}
/**
* 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.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
if (packageName.equals(data.res.mPkg.getPackageName())) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.mNewUsers.length; uIndex++) {
if (userId == data.res.mNewUsers[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;
mBroadcastHelper.sendFirstLaunchBroadcast(
packageName, installerPackage, userIds, instantUserIds);
});
}
private @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;
}
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);
}
}
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) {
mDeletePackageHelper.deleteExistingPackageAsUser(
versionedPackage, observer, userId);
}
@Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
mDeletePackageHelper.deletePackageVersionedInternal(
versionedPackage, observer, userId, deleteFlags, false);
}
private String resolveExternalPackageNameLPr(AndroidPackage pkg) {
return mComputer.resolveExternalPackageNameLPr(pkg);
}
@GuardedBy("mLock")
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);
}
@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);
}
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 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;
}
@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;
}
@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) {
mAppDataHelper.clearAppProfilesLIF(pkg);
}
}
}
@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.getPkg();
}
}
}
if (pkg == null) {
Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
}
mPermissionManager.resetRuntimePermissions(pkg, userId);
mAppDataHelper.clearAppDataLIF(pkg, userId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
final int appId = UserHandle.getAppId(pkg.getUid());
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;
}
mAppDataHelper.prepareAppDataContentsLIF(pkg, ps, userId, flags);
return true;
}
/**
* Remove entries from the keystore daemon. Will only remove it if the
* {@code appId} is valid.
*/
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
mAppDataHelper.clearAppDataLIF(pkg, userId,
flags | Installer.FLAG_CLEAR_CACHE_ONLY);
mAppDataHelper.clearAppDataLIF(pkg, userId,
flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
if (observer != null) {
try {
observer.onRemoveCompleted(packageName, true);
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
}
}
});
}
@Override
public void getPackageSizeInfo(final String packageName, int userId,
final IPackageStatsObserver observer) {
throw new UnsupportedOperationException(
"Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
}
@GuardedBy("mLock")
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.getPkg() != null) {
int v = ps.getPkg().getTargetSdkVersion();
if (v < vers) vers = v;
}
}
return vers;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (ps.getPkg() != null) {
return ps.getPkg().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) {
mPreferredActivityHelper.addPreferredActivity(
new WatchedIntentFilter(filter), match, set, activity, true, userId,
"Adding preferred", removeExisting);
}
void postPreferredActivityChangedBroadcast(int userId) {
mHandler.post(() -> mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId));
}
@Override
public void replacePreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
mPreferredActivityHelper.replacePreferredActivity(new WatchedIntentFilter(filter), match,
set, activity, userId);
}
@Override
public void clearPackagePreferredActivities(String packageName) {
mPreferredActivityHelper.clearPackagePreferredActivities(packageName);
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@GuardedBy("mLock")
void clearPackagePreferredActivitiesLPw(String packageName,
@NonNull SparseBooleanArray outUserChanged, int userId) {
mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId);
}
void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
@UserIdInt int userId) {
// We may also need to apply pending (restored) runtime permission grants
// within these users.
mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
// Persistent preferred activity might have came into effect due to this
// install.
mPreferredActivityHelper.updateDefaultHomeNotLocked(userId);
}
@Override
public void resetApplicationPreferences(int userId) {
mPreferredActivityHelper.resetApplicationPreferences(userId);
}
@Override
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
return mPreferredActivityHelper.getPreferredActivities(outFilters, outActivities,
packageName);
}
@Override
public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
int userId) {
mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
activity, userId);
}
@Override
public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
}
/**
* 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) {
return mPreferredActivityHelper.getPreferredActivityBackup(userId);
}
@Override
public void restorePreferredActivities(byte[] backup, int userId) {
mPreferredActivityHelper.restorePreferredActivities(backup, userId);
}
/**
* 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) {
return mPreferredActivityHelper.getDefaultAppsBackup(userId);
}
@Override
public void restoreDefaultApps(byte[] backup, int userId) {
mPreferredActivityHelper.restoreDefaultApps(backup, userId);
}
@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<CrossProfileIntentFilter> existing = resolver.findFilters(intentFilter);
// We have all those whose filter is equal. Now checking if the rest is equal as well.
if (existing != null) {
int size = existing.size();
for (int i = 0; i < size; i++) {
if (newFilter.equalsIgnoreFilter(existing.get(i))) {
return;
}
}
}
resolver.addFilter(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<CrossProfileIntentFilter> 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<ResolveInfo> allHomeCandidates) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
UserManagerService ums = UserManagerService.getInstance();
if (ums == null || sessionInfo.isStaged()) {
return;
}
final UserInfo parent = ums.getProfileParent(userId);
final int launcherUid = (parent != null) ? parent.id : userId;
final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
mBroadcastHelper.sendSessionCommitBroadcast(sessionInfo, userId, launcherUid,
launcherComponent, mAppPredictionServicePackage);
}
/**
* 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);
}
Intent getHomeIntent() {
return mComputer.getHomeIntent();
}
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
return mComputer.getHomeActivitiesAsUser(allHomeCandidates,
userId);
}
@Override
public void setHomeActivity(ComponentName comp, int userId) {
mPreferredActivityHelper.setHomeActivity(comp, userId);
}
private @Nullable String getSetupWizardPackageNameImpl() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
final List<ResolveInfo> 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<ResolveInfo> 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));
}
@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.getSignatures() != null) {
try {
final MessageDigest msgDigest = MessageDigest.getInstance("SHA-256");
for (Signature signature : signingDetail.getSignatures()) {
if (TextUtils.equals(predefinedSignature,
HexEncoding.encodeToString(msgDigest.digest(
signature.toByteArray()), false))) {
return predefinedPkgName;
}
}
} catch (NoSuchAlgorithmException e) {
Slog.e(
TAG,
"Unable to verify signatures as getting the retail demo package name",
e);
}
}
}
return null;
}
@Nullable
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;
}
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!mUserManager.exists(userId)) return;
if (callingPackage == null) {
callingPackage = Integer.toString(Binder.getCallingUid());
}
setEnabledSettings(List.of(new ComponentEnabledSetting(appPackageName, 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<String> 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;
setEnabledSettings(List.of(new ComponentEnabledSetting(componentName, newState, flags)),
userId, null /* callingPackage */);
}
@Override
public void setComponentEnabledSettings(List<ComponentEnabledSetting> settings, int userId) {
if (!mUserManager.exists(userId)) return;
if (settings == null || settings.isEmpty()) {
throw new IllegalArgumentException("The list of enabled settings is empty");
}
setEnabledSettings(settings, userId, null /* callingPackage */);
}
private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
String callingPackage) {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
true /* checkShell */, "set enabled");
final int targetSize = settings.size();
for (int i = 0; i < targetSize; i++) {
final int newState = settings.get(i).getEnabledState();
if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
|| newState == COMPONENT_ENABLED_STATE_ENABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
throw new IllegalArgumentException("Invalid new component state: " + newState);
}
}
if (targetSize > 1) {
final ArraySet<String> checkDuplicatedPackage = new ArraySet<>();
final ArraySet<ComponentName> checkDuplicatedComponent = new ArraySet<>();
final ArrayMap<String, Integer> checkConflictFlag = new ArrayMap<>();
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
final String packageName = setting.getPackageName();
if (setting.isComponent()) {
final ComponentName componentName = setting.getComponentName();
if (checkDuplicatedComponent.contains(componentName)) {
throw new IllegalArgumentException("The component " + componentName
+ " is duplicated");
}
checkDuplicatedComponent.add(componentName);
// check if there is a conflict of the DONT_KILL_APP flag between components
// in the package
final Integer enabledFlags = checkConflictFlag.get(packageName);
if (enabledFlags == null) {
checkConflictFlag.put(packageName, setting.getEnabledFlags());
} else if ((enabledFlags & PackageManager.DONT_KILL_APP)
!= (setting.getEnabledFlags() & PackageManager.DONT_KILL_APP)) {
throw new IllegalArgumentException("A conflict of the DONT_KILL_APP flag "
+ "between components in the package " + packageName);
}
} else {
if (checkDuplicatedPackage.contains(packageName)) {
throw new IllegalArgumentException("The package " + packageName
+ " is duplicated");
}
checkDuplicatedPackage.add(packageName);
}
}
}
final boolean allowedByPermission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE) == PERMISSION_GRANTED;
final boolean[] updateAllowed = new boolean[targetSize];
Arrays.fill(updateAllowed, true);
final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize);
// reader
synchronized (mLock) {
// Checks for target packages
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
final String packageName = setting.getPackageName();
if (pkgSettings.containsKey(packageName)) {
// this package has verified
continue;
}
final boolean isCallerTargetApp = ArrayUtils.contains(
getPackagesForUid(callingUid), packageName);
final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
// Limit who can change which apps
if (!isCallerTargetApp) {
// Don't allow apps that don't have permission to modify other apps
if (!allowedByPermission
|| shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
throw new SecurityException("Attempt to change component state; "
+ "pid=" + Binder.getCallingPid()
+ ", uid=" + callingUid
+ (!setting.isComponent() ? ", package=" + packageName
: ", component=" + setting.getComponentName()));
}
// Don't allow changing protected packages.
if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
throw new SecurityException(
"Cannot disable a protected package: " + packageName);
}
}
if (pkgSetting == null) {
throw new IllegalArgumentException(setting.isComponent()
? "Unknown component: " + setting.getComponentName()
: "Unknown package: " + packageName);
}
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.
final int oldState = pkgSetting.getEnabled(userId);
final int newState = setting.getEnabledState();
if (!setting.isComponent()
&&
(oldState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| oldState == COMPONENT_ENABLED_STATE_DEFAULT
|| oldState == COMPONENT_ENABLED_STATE_ENABLED)
&&
(newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DEFAULT
|| newState == COMPONENT_ENABLED_STATE_ENABLED)) {
// ok
} else {
throw new SecurityException(
"Shell cannot change component state for "
+ setting.getComponentName() + " to " + newState);
}
}
pkgSettings.put(packageName, pkgSetting);
}
// Checks for target components
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
// skip if it's application
if (!setting.isComponent()) continue;
// Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
// app details activity
final String packageName = setting.getPackageName();
final String className = setting.getClassName();
if (!allowedByPermission
&& PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
throw new SecurityException("Cannot disable a system-generated component");
}
// Verify that this is a valid class name.
final AndroidPackage pkg = pkgSettings.get(packageName).getPkg();
if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
if (pkg != null
&& pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) {
throw new IllegalArgumentException("Component class " + className
+ " does not exist in " + packageName);
} else {
Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
+ className + " does not exist in " + packageName);
updateAllowed[i] = false;
}
}
}
}
// More work for application enabled setting updates
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
// skip if it's component
if (setting.isComponent()) continue;
final PackageSetting pkgSetting = pkgSettings.get(setting.getPackageName());
final int newState = setting.getEnabledState();
synchronized (mLock) {
if (pkgSetting.getEnabled(userId) == newState) {
// Nothing to do
updateAllowed[i] = false;
continue;
}
}
// If we're enabling a system stub, there's a little more work to do.
// Prior to enabling the package, we need to decompress the APK(s) to the
// data partition and then replace the version on the system partition.
final AndroidPackage deletedPkg = pkgSetting.getPkg();
final boolean isSystemStub = (deletedPkg != null)
&& deletedPkg.isStub()
&& deletedPkg.isSystem();
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
if (!mInitAndSystemPackageHelper.enableCompressedPackage(deletedPkg, pkgSetting,
mDefParseFlags, mDirsToScanAsSystem)) {
Slog.w(TAG, "Failed setApplicationEnabledSetting: failed to enable "
+ "commpressed package " + setting.getPackageName());
updateAllowed[i] = false;
}
}
}
// packageName -> list of components to send broadcasts now
final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize);
synchronized (mLock) {
boolean scheduleBroadcastMessage = false;
boolean isSynchronous = false;
boolean anyChanged = false;
for (int i = 0; i < targetSize; i++) {
if (!updateAllowed[i]) {
continue;
}
// update enabled settings
final ComponentEnabledSetting setting = settings.get(i);
final String packageName = setting.getPackageName();
if (!setEnabledSettingInternalLocked(pkgSettings.get(packageName), setting,
userId, callingPackage)) {
continue;
}
anyChanged = true;
if ((setting.getEnabledFlags() & PackageManager.SYNCHRONOUS) != 0) {
isSynchronous = true;
}
// collect broadcast list for the package
final String componentName = setting.isComponent()
? setting.getClassName() : packageName;
ArrayList<String> componentList = sendNowBroadcasts.get(packageName);
if (componentList == null) {
componentList = mPendingBroadcasts.get(userId, packageName);
}
final boolean newPackage = componentList == null;
if (newPackage) {
componentList = new ArrayList<>();
}
if (!componentList.contains(componentName)) {
componentList.add(componentName);
}
if ((setting.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) {
sendNowBroadcasts.put(packageName, componentList);
// Purge entry from pending broadcast list if another one exists already
// since we are sending one right away.
mPendingBroadcasts.remove(userId, packageName);
} else {
if (newPackage) {
mPendingBroadcasts.put(userId, packageName, componentList);
}
scheduleBroadcastMessage = true;
}
}
if (!anyChanged) {
// nothing changed, return immediately
return;
}
if (isSynchronous) {
flushPackageRestrictionsAsUserInternalLocked(userId);
} else {
scheduleWritePackageRestrictionsLocked(userId);
}
if (scheduleBroadcastMessage) {
if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
// Schedule a message - if it has been a "reasonably long time" since the
// service started, send the broadcast with a delay of one second to avoid
// delayed reactions from the receiver, else keep the default ten second delay
// to avoid extreme thrashing on service startup.
final long broadcastDelay = SystemClock.uptimeMillis() > mServiceStartWithDelay
? BROADCAST_DELAY
: BROADCAST_DELAY_DURING_STARTUP;
mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, broadcastDelay);
}
}
}
final long callingId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < sendNowBroadcasts.size(); i++) {
final String packageName = sendNowBroadcasts.keyAt(i);
final ArrayList<String> components = sendNowBroadcasts.valueAt(i);
final int packageUid = UserHandle.getUid(
userId, pkgSettings.get(packageName).getAppId());
sendPackageChangedBroadcast(packageName, false /* dontKillApp */,
components, packageUid, null /* reason */);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
private boolean setEnabledSettingInternalLocked(PackageSetting pkgSetting,
ComponentEnabledSetting setting, int userId, String callingPackage) {
final int newState = setting.getEnabledState();
final String packageName = setting.getPackageName();
boolean success = false;
if (!setting.isComponent()) {
// We're dealing with an application/package level state change
if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
// Don't care about who enables an app.
callingPackage = null;
}
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);
}
success = true;
} else {
// We're dealing with a component level state change
final String className = setting.getClassName();
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
success = pkgSetting.enableComponentLPw(className, userId);
break;
case COMPONENT_ENABLED_STATE_DISABLED:
success = pkgSetting.disableComponentLPw(className, userId);
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
success = pkgSetting.restoreComponentLPw(className, userId);
break;
default:
Slog.e(TAG, "Failed setComponentEnabledSetting: component "
+ packageName + "/" + className
+ " requested an invalid new component state: " + newState);
break;
}
}
if (!success) {
return false;
}
updateSequenceNumberLP(pkgSetting, new int[] { userId });
final long callingId = Binder.clearCallingIdentity();
try {
updateInstantAppInstallerLocked(packageName);
} finally {
Binder.restoreCallingIdentity(callingId);
}
return true;
}
@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);
}
}
void sendPackageChangedBroadcast(String packageName,
boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
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<int[]> broadcastAllowList = getBroadcastAllowList(
packageName, userIds, isInstantApp);
mHandler.post(() -> mBroadcastHelper.sendPackageChangedBroadcast(
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
instantUserIds, broadcastAllowList));
}
private SparseArray<int[]> getBroadcastAllowList(String packageName, int[] userIds,
boolean isInstantApp) {
if (isInstantApp) {
return null;
}
final SparseArray<int[]> broadcastAllowList;
synchronized (mLock) {
PackageSetting setting = getPackageSettingInternal(packageName, Process.SYSTEM_UID);
if (setting == null) {
return null;
}
broadcastAllowList = mAppsFilter.getVisibilityAllowList(
setting, userIds, mSettings.getPackagesLocked());
}
return broadcastAllowList;
}
@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");
boolean shouldUnhibernate = false;
// writer
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && ps.getStopped(userId) && !stopped) {
shouldUnhibernate = true;
}
if (!shouldFilterApplicationLocked(ps, callingUid, userId)
&& mSettings.setPackageStoppedStateLPw(this, packageName, stopped, userId)) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
if (shouldUnhibernate) {
mHandler.post(() -> {
AppHibernationManagerInternal ah =
mInjector.getLocalService(AppHibernationManagerInternal.class);
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.getInstallSource();
}
@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 return componentEnabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
} 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;
ParsingPackageUtils.setCompatibilityModeEnabled(compatibilityModeEnabled);
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
synchronized (mLock) {
ArrayList<Integer> changed = mSettings.systemReady(mComponentResolver);
for (int i = 0; i < changed.size(); i++) {
mSettings.writePackageRestrictionsLPr(changed.get(i));
}
}
mUserManager.systemReady();
// Watch for external volumes that come and go over time
final StorageEventHelper storageEventHelper = new StorageEventHelper(this,
mDeletePackageHelper, mRemovePackageHelper);
final StorageManager storage = mInjector.getSystemService(StorageManager.class);
storage.registerListener(storageEventHelper);
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
// Now that we're mostly running, clean up stale users and apps
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
storageEventHelper.reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.onSystemReady();
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
final List<UserInfo> livingUsers = mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ true,
/* excludePreCreated= */ false);
final int livingUserCount = livingUsers.size();
for (int i = 0; i < livingUserCount; i++) {
final int userId = livingUsers.get(i).id;
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<String> keyset = properties.getKeyset();
if (keyset.contains(PROPERTY_INCFS_DEFAULT_TIMEOUTS) || keyset.contains(
PROPERTY_KNOWN_DIGESTERS_LIST)) {
mPerUidReadTimeoutsCache = null;
}
});
mBackgroundDexOptService.systemReady();
}
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 false;
}
@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;
new DumpHelper(this).doDump(fd, pw, args);
}
void dumpSnapshotStats(PrintWriter pw, boolean isBrief) {
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, isBrief);
}
}
/**
* Dump package manager states to the file according to a given dumping type of
* {@link DumpState}.
*/
void dumpComputer(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);
}
}
}
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, this);
}
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(this);
} else {
return freezePackage(packageName, userId, killReason);
}
}
/**
* Verify that given package is currently frozen.
*/
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 {
MovePackageHelper movePackageHelper = new MovePackageHelper(this);
movePackageHelper.movePackageInternal(
packageName, volumeUuid, moveId, callingUid, user);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to move " + packageName, e);
mMoveCallbacks.notifyStatusChanged(moveId, e.error);
}
});
return moveId;
}
@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);
mDeletePackageHelper.removeUnusedPackagesLPw(userManager, userId);
mAppsFilter.onUserDeleted(userId);
}
}
/**
* Called by UserManagerService.
*
* @param userTypeInstallablePackages system packages that should be initially installed for
* this type of user, or {@code null} if all system packages
* should be installed
* @param disallowedPackages packages that should not be initially installed. Takes precedence
* over installablePackages.
*/
void createNewUser(int userId, @Nullable Set<String> userTypeInstallablePackages,
String[] disallowedPackages) {
synchronized (mInstallLock) {
mSettings.createNewUserLI(this, mInstaller, userId,
userTypeInstallablePackages, disallowedPackages);
}
synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
scheduleWritePackageListLocked(userId);
mAppsFilter.onUserCreated(userId);
}
}
void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) {
if (DEBUG_PERMISSIONS) {
Slog.d(TAG, "onNewUserCreated(id=" + userId
+ ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
}
if (!convertedFromPreCreated || !readPermissionStateForUser(userId)) {
mPermissionManager.onUserCreated(userId);
mLegacyPermissionManager.grantDefaultPermissions(userId);
mDomainVerificationManager.clearUser(userId);
}
}
private 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;
}
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;
b = userInfo != null && userInfo.isManagedProfile();
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(() -> mDeletePackageHelper.deletePackageX(
packageName, PackageManager.VERSION_CODE_HIGHEST,
0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/));
}
}
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 && 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);
}
@Override
public void registerStagedApexObserver(IStagedApexObserver observer) {
mInstallerService.getStagingManager().registerStagedApexObserver(observer);
}
@Override
public void unregisterStagedApexObserver(IStagedApexObserver observer) {
mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
}
@Override
public String[] getStagedApexModuleNames() {
return mInstallerService.getStagingManager()
.getStagedApexModuleNames().toArray(new String[0]);
}
@Override
@Nullable
public StagedApexInfo getStagedApexInfo(String moduleName) {
return mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
}
}
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 boolean filterAppAccess(int uid, int callingUid) {
return mComputer.filterAppAccess(uid, callingUid);
}
private int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
synchronized (mLock) {
final PackageSetting ps = getPackageSettingInternal(packageName, Process.SYSTEM_UID);
if (ps == null) {
return null;
}
final SparseArray<int[]> visibilityAllowList = mAppsFilter.getVisibilityAllowList(ps,
new int[]{userId}, mSettings.getPackagesLocked());
return visibilityAllowList != null ? visibilityAllowList.get(userId) : null;
}
}
/**
* Returns whether the given UID either declares &lt;queries&gt; element with the given package
* name in its app's manifest, has {@link android.Manifest.permission.QUERY_ALL_PACKAGES}, or
* package visibility filtering is enabled on it. If the UID is part of a shared user ID,
* return {@code true} if any one application belongs to the shared user ID meets the criteria.
*/
boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
if (targetPackageName == null) {
return true;
}
synchronized (mLock) {
final Object setting = mSettings.getSettingLPr(UserHandle.getAppId(callingUid));
if (setting == null) {
return false;
}
final int userId = UserHandle.getUserId(callingUid);
final int targetAppId = UserHandle.getAppId(
getPackageUid(targetPackageName, 0 /* flags */, userId));
// For update or already installed case, leverage the existing visibility rule.
if (targetAppId != Process.INVALID_UID) {
final Object targetSetting = mSettings.getSettingLPr(targetAppId);
if (targetSetting instanceof PackageSetting) {
return !shouldFilterApplicationLocked(
(PackageSetting) targetSetting, callingUid, userId);
} else {
return !shouldFilterApplicationLocked(
(SharedUserSetting) targetSetting, callingUid, userId);
}
}
// For new installing case, check if caller declares <queries> element with the
// target package name or has proper permission.
if (setting instanceof PackageSetting) {
final AndroidPackage pkg = ((PackageSetting) setting).getPkg();
return pkg != null && mAppsFilter.canQueryPackage(pkg, targetPackageName);
} else {
final ArraySet<PackageSetting> callingSharedPkgSettings =
((SharedUserSetting) setting).packages;
for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
final AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).getPkg();
if (pkg != null && mAppsFilter.canQueryPackage(pkg, targetPackageName)) {
return true;
}
}
return false;
}
}
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
public List<ApplicationInfo> 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.getPkg();
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(),
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 boolean filterAppAccess(int uid, int callingUid) {
return PackageManagerService.this.filterAppAccess(uid, callingUid);
}
@Nullable
@Override
public int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
return PackageManagerService.this.getVisibilityAllowList(packageName, userId);
}
@Override
public boolean canQueryPackage(int callingUid, @Nullable String packageName) {
return PackageManagerService.this.canQueryPackage(callingUid, packageName);
}
@Override
public AndroidPackage getPackage(String packageName) {
return PackageManagerService.this.getPackage(packageName);
}
@Nullable
@Override
public AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
return PackageManagerService.this.getPackage(packageName);
}
@Override
public AndroidPackage getPackage(int uid) {
return PackageManagerService.this.getPackage(uid);
}
@Override
public List<AndroidPackage> getPackagesForAppId(int appId) {
final Object obj;
synchronized (mLock) {
obj = mSettings.getSettingLPr(appId);
}
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.getPackages();
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
return List.of(ps.getPkg());
} else {
return Collections.emptyList();
}
}
@Nullable
@Override
public PackageSetting getPackageSetting(String packageName) {
return PackageManagerService.this.getPackageSetting(packageName);
}
@Nullable
@Override
public PackageState getPackageState(@NonNull String packageName) {
return PackageManagerService.this.getPackageState(packageName);
}
@Override
public PackageList getPackageList(PackageListObserver observer) {
synchronized (mLock) {
final int N = mPackages.size();
final ArrayList<String> 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 = getDisabledSystemPackage(
packageName);
AndroidPackage disabledPkg = disabledPkgSetting == null
? null : disabledPkgSetting.getPkg();
return disabledPkg == null ? null : disabledPkg.getPackageName();
}
@Override
public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
return PackageManagerService.this.getKnownPackageNamesInternal(knownPackage, userId);
}
@Override
public boolean isResolveActivityComponent(ComponentInfo component) {
return mResolveActivity.packageName.equals(component.packageName)
&& mResolveActivity.name.equals(component.name);
}
@Override
public void setKeepUninstalledPackages(final List<String> 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 PackageUserStateInternal pus = ps.readUserState(userId);
if (pus.isSuspended()) {
for (int i = 0; i < pus.getSuspendParams().size(); i++) {
final PackageUserState.SuspendParams params =
pus.getSuspendParams().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);
}
}
@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 PackageUserStateInternal pus = ps.readUserState(userId);
if (pus.isSuspended()) {
String suspendingPackage = null;
for (int i = 0; i < pus.getSuspendParams().size(); i++) {
suspendingPackage = pus.getSuspendParams().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 PackageUserStateInternal pus = ps.readUserState(userId);
if (pus.isSuspended()) {
final PackageUserState.SuspendParams suspendParams =
pus.getSuspendParams().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<ResolveInfo> 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<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags, int filterCallingUid, int userId) {
return PackageManagerService.this.mResolveIntentHelper.queryIntentReceiversInternal(
intent, resolvedType, flags, userId, filterCallingUid);
}
@Override
public List<ResolveInfo> 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<ResolveInfo> 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<String> profileOwnerPackages) {
mProtectedPackages.setDeviceAndProfileOwnerPackages(
deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
if (deviceOwnerPackage != null) {
usersWithPoOrDo.add(deviceOwnerUserId);
}
final int sz = profileOwnerPackages.size();
for (int i = 0; i < sz; i++) {
if (profileOwnerPackages.valueAt(i) != null) {
usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
}
}
}
@Override
public void setDeviceOwnerProtectedPackages(
String deviceOwnerPackageName, List<String> 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);
}
}
@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) {
grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
false /* retainOnUpdate */);
}
@Override
public void grantImplicitAccess(int userId, Intent intent,
int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
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,
retainOnUpdate);
}
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<PackageInfo> 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<String> 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<PackageInfo> getOverlayPackages(int userId) {
final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
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<String> getTargetPackageNames(int userId) {
List<String> 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<String> 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<VersionedPackage> 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 mResolveIntentHelper.resolveIntentInternal(
intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
filterCallingUid);
}
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType,
int flags, int userId, int callingUid) {
return mResolveIntentHelper.resolveServiceInternal(intent, resolvedType, flags, userId,
callingUid);
}
@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<String> getAppsWithSharedUserIds() {
synchronized (mLock) {
return getAppsWithSharedUserIdsLocked();
}
}
@Override
@NonNull
public String[] getSharedUserPackagesForPackage(String packageName, int userId) {
synchronized (mLock) {
return getSharedUserPackagesForPackageLocked(packageName, userId);
}
}
@Override
public ArrayMap<String, ProcessInfo> 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<AndroidPackage> actionLocked) {
PackageManagerService.this.forEachPackage(actionLocked);
}
@Override
public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
PackageManagerService.this.forEachPackageSetting(actionLocked);
}
@Override
public void forEachPackageState(boolean locked, Consumer<PackageState> action) {
PackageManagerService.this.forEachPackageState(locked, action);
}
@Override
public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
@UserIdInt int userId) {
PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
}
@Override
public ArraySet<String> 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<String> 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<String> 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.getInstallSource()
.installerPackageName);
return installerPackageSetting != null
&& UserHandle.isSameApp(installerPackageSetting.getAppId(), 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<String> 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.getAppId(), 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.getIncrementalStatesInfo();
}
@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<Function<String, PackageSetting>> 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> Output withPackageSettingsSnapshotReturning(
@NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageSetting>, 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 <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
@NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageSetting>,
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 <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
withPackageSettingsSnapshotThrowing2(
@NonNull FunctionalUtils.ThrowingChecked2Consumer<
Function<String, PackageSetting>, 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, ExceptionType extends Exception> Output
withPackageSettingsSnapshotReturningThrowing(
@NonNull FunctionalUtils.ThrowingCheckedFunction<
Function<String, PackageSetting>, 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);
}
}
@Override
public void reconcileAppsData(int userId, int flags, boolean migrateAppsData) {
PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
migrateAppsData);
}
}
@GuardedBy("mLock")
private SparseArray<String> getAppsWithSharedUserIdsLocked() {
final SparseArray<String> 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<PackageSetting> packages = packageSetting.getSharedUser().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.getPackageName();
}
}
res = ArrayUtils.trimToSize(res, i);
return res != null ? res : EmptyArray.STRING;
}
@GuardedBy("mLock")
public ArrayMap<String, ProcessInfo> 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.getPkg().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
@VisibleForTesting(visibility = Visibility.PRIVATE)
PackageSetting getPackageSetting(String packageName) {
return mComputer.getPackageSetting(packageName);
}
PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
return mComputer.getPackageSettingInternal(packageName, callingUid);
}
@Nullable
private PackageState getPackageState(String packageName) {
return mComputer.getPackageState(packageName);
}
void forEachPackage(Consumer<AndroidPackage> actionLocked) {
synchronized (mLock) {
int numPackages = mPackages.size();
for (int i = 0; i < numPackages; i++) {
actionLocked.accept(mPackages.valueAt(i));
}
}
}
private void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {
int size = mSettings.getPackagesLocked().size();
for (int index = 0; index < size; index++) {
actionLocked.accept(mSettings.getPackagesLocked().valueAt(index));
}
}
}
private void forEachPackageState(boolean locked, Consumer<PackageState> action) {
if (locked) {
forEachPackageSetting(action::accept);
} else {
List<PackageState> packageStates = new ArrayList<>();
forEachPackageSetting(pkgSetting ->
packageStates.add(PackageStateImpl.copy(pkgSetting)));
int size = packageStates.size();
for (int index = 0; index < size; index++) {
action.accept(packageStates.get(index));
}
}
}
void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> 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();
}
}
/**
* 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 getOrCreateCompilerPackageStats(AndroidPackage pkg) {
return getOrCreateCompilerPackageStats(pkg.getPackageName());
}
public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) {
return mCompilerStats.getOrCreatePackageStats(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), 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 /*direct*/);
}
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<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
Set<String> 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.getFirstInstallTime(), 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 {
BroadcastHelper.sendDeviceCustomizationReadyBroadcast();
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void applyMimeGroupChanges(String packageName, String mimeGroup) {
if (mComponentResolver.updateMimeGroup(packageName, mimeGroup)) {
Binder.withCleanCallingIdentity(() ->
mPreferredActivityHelper.clearPackagePreferredActivities(packageName,
UserHandle.USER_ALL));
}
mPmInternal.writeSettings(false);
}
@Override
public void setMimeGroup(String packageName, String mimeGroup, List<String> 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<String> getMimeGroup(String packageName, String mimeGroup) {
enforceOwnerRights(packageName, Binder.getCallingUid());
return getMimeGroupInternal(packageName, mimeGroup);
}
private List<String> 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) {
int callingUid = Binder.getCallingUid();
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.
*/
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);
}
}
static String getDefaultTimeouts() {
final long token = Binder.clearCallingIdentity();
try {
return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE,
PROPERTY_INCFS_DEFAULT_TIMEOUTS, "");
} finally {
Binder.restoreCallingIdentity(token);
}
}
static String getKnownDigestersList() {
final long token = Binder.clearCallingIdentity();
try {
return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE,
PROPERTY_KNOWN_DIGESTERS_LIST, "");
} finally {
Binder.restoreCallingIdentity(token);
}
}
/**
* 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 =
PerPackageReadTimeouts.parseDigestersList(defaultTimeouts, knownDigestersList);
if (perPackageReadTimeouts.size() == 0) {
return EMPTY_PER_UID_READ_TIMEOUTS_ARRAY;
}
final int[] allUsers = mInjector.getUserManagerService().getUserIds();
List<PerUidReadTimeouts> 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.getAppId() < Process.FIRST_APPLICATION_UID) {
if (DEBUG_PER_UID_READ_TIMEOUTS) {
Slog.i(TAG, "PerUidReadTimeouts: package is system, appId="
+ ps.getAppId());
}
continue;
}
final AndroidPackage pkg = ps.getPkg();
if (pkg.getLongVersionCode() < perPackage.versionCodes.minVersionCode
|| pkg.getLongVersionCode() > perPackage.versionCodes.maxVersionCode) {
if (DEBUG_PER_UID_READ_TIMEOUTS) {
Slog.i(TAG, "PerUidReadTimeouts: version code is not in range = "
+ perPackage.packageName + ":" + pkg.getLongVersionCode());
}
continue;
}
if (perPackage.sha256certificate != null
&& !pkg.getSigningDetails().hasSha256Certificate(
perPackage.sha256certificate)) {
if (DEBUG_PER_UID_READ_TIMEOUTS) {
Slog.i(TAG, "PerUidReadTimeouts: invalid certificate = "
+ perPackage.packageName + ":" + pkg.getLongVersionCode());
}
continue;
}
for (int userId : allUsers) {
if (!ps.getInstalled(userId)) {
continue;
}
final int uid = UserHandle.getUid(userId, ps.getAppId());
final PerUidReadTimeouts perUid = new PerUidReadTimeouts();
perUid.uid = uid;
perUid.minTimeUs = perPackage.timeouts.minTimeUs;
perUid.minPendingTimeUs = perPackage.timeouts.minPendingTimeUs;
perUid.maxPendingTimeUs = perPackage.timeouts.maxPendingTimeUs;
result.add(perUid);
}
}
}
return result.toArray(new PerUidReadTimeouts[result.size()]);
}
@Override
public void setKeepUninstalledPackages(List<String> packageList) {
mContext.enforceCallingPermission(
Manifest.permission.KEEP_UNINSTALLED_PACKAGES,
"setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission");
Objects.requireNonNull(packageList);
setKeepUninstalledPackagesInternal(packageList);
}
private void setKeepUninstalledPackagesInternal(List<String> packageList) {
Preconditions.checkNotNull(packageList);
List<String> 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));
}
}
}
}
boolean shouldKeepUninstalledPackageLPr(String packageName) {
return mKeepUninstalledPackages != null && mKeepUninstalledPackages.contains(packageName);
}
@Override
public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
String featureId, int userId) throws RemoteException {
return mResolveIntentHelper.getLaunchIntentSenderForPackage(packageName, callingPackage,
featureId, userId);
}
@Override
public boolean canPackageQuery(String sourcePackageName, String targetPackageName, int userId) {
if (!mUserManager.exists(userId)) return false;
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "may package query");
synchronized (mLock) {
final PackageSetting sourceSetting = getPackageSetting(sourcePackageName);
final PackageSetting targetSetting = getPackageSetting(targetPackageName);
if (sourceSetting == null || targetSetting == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException("Package(s) "
+ (sourceSetting == null ? sourcePackageName + " " : "")
+ (targetSetting == null ? targetPackageName + " " : "")
+ "not found."));
}
final boolean filterSource =
shouldFilterApplicationLocked(sourceSetting, callingUid, userId);
final boolean filterTarget =
shouldFilterApplicationLocked(targetSetting, callingUid, userId);
// The caller must have visibility of the both packages
if (filterSource || filterTarget) {
throw new ParcelableException(new PackageManager.NameNotFoundException("Package(s) "
+ (filterSource ? sourcePackageName + " " : "")
+ (filterTarget ? targetPackageName + " " : "")
+ "not found."));
}
final int sourcePackageUid = UserHandle.getUid(userId, sourceSetting.getAppId());
return !shouldFilterApplicationLocked(targetSetting, sourcePackageUid, userId);
}
}
boolean getSafeMode() {
return mSafeMode;
}
ComponentName getResolveComponentName() {
return mResolveComponentName;
}
DefaultAppProvider getDefaultAppProvider() {
return mDefaultAppProvider;
}
File getCacheDir() {
return mCacheDir;
}
List<ScanPartition> getDirsToScanAsSystem() {
return mDirsToScanAsSystem;
}
PackageProperty getPackageProperty() {
return mPackageProperty;
}
WatchedArrayMap<ComponentName, ParsedInstrumentation> getInstrumentation() {
return mInstrumentation;
}
int getSdkVersion() {
return mSdkVersion;
}
void addAllPackageProperties(@NonNull AndroidPackage pkg) {
mPackageProperty.addAllProperties(pkg);
}
void addInstrumentation(ComponentName name, ParsedInstrumentation instrumentation) {
mInstrumentation.put(name, instrumentation);
}
String[] getKnownPackageNamesInternal(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_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);
}
}
/**
* Only keep package names that refer to {@link AndroidPackage#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<String> 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[]{});
}
String getActiveLauncherPackageName(int userId) {
return mDefaultAppProvider.getDefaultHome(userId);
}
boolean setActiveLauncherPackage(@NonNull String packageName, @UserIdInt int userId,
@NonNull Consumer<Boolean> callback) {
return mDefaultAppProvider.setDefaultHome(packageName, userId, mContext.getMainExecutor(),
callback);
}
void setDefaultBrowser(@Nullable String packageName, boolean async, @UserIdInt int userId) {
mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
}
ResolveInfo getInstantAppInstallerInfo() {
return mInstantAppInstallerInfo;
}
}