import static android.Manifest.permission.DELETE_PACKAGES;
import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
+import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_DEFAULT;
+import static android.content.Intent.CATEGORY_HOME;
+import static android.content.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.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
-import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
-import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_APEX;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageParser.isApkFile;
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.system.OsConstants.O_CREAT;
-import static android.system.OsConstants.O_RDWR;
+import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
-import static com.android.internal.util.ArrayUtils.appendInt;
+import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-
-import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
+import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
+import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
+import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
+import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
-import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AppsQueryHelper;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
-import android.content.pm.InstantAppResolveInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.PackageCleanItem;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageBackwardCompatibility;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
+import android.content.pm.PackageManager.ModuleInfoFlags;
+import android.content.pm.PackageManager.PermissionWhitelistFlags;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
+import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.ParseFlags;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
+import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.dex.IArtManager;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.res.Resources;
+import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
-import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
import android.os.PatternMatcher;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
+import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.permission.PermissionManager;
+import android.provider.DeviceConfig;
+import android.provider.MediaStore;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
+import android.stats.storage.StorageEnums;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
-import android.util.TimingsTraceLog;
+import android.util.ByteStringUtils;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
+import android.util.IntArray;
import android.util.Log;
import android.util.LogPrinter;
+import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.PackageUtils;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.StatsLog;
+import android.util.TimingsTraceLog;
import android.util.Xml;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.os.IParcelFileDescriptorFactory;
-import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IntPair;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
-import com.android.server.IntentResolver;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
+import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
+import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.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.permission.BasePermission;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
+import com.android.server.pm.permission.PermissionsState;
+import com.android.server.policy.PermissionPolicyInternal;
+import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import dalvik.system.CloseGuard;
-import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.io.Streams;
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
+import java.security.DigestException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Date;
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.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.GZIPInputStream;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
static final String TAG = "PackageManager";
- static final boolean DEBUG_SETTINGS = false;
+ public static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
private static final boolean DEBUG_BACKUP = false;
- private static final boolean DEBUG_INSTALL = false;
- private static final boolean DEBUG_REMOVE = false;
+ public static final boolean DEBUG_INSTALL = false;
+ public static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_BROADCASTS = false;
- private static final boolean DEBUG_SHOW_INFO = false;
private static final boolean DEBUG_PACKAGE_INFO = false;
private static final boolean DEBUG_INTENT_MATCHING = false;
- private static final boolean DEBUG_PACKAGE_SCANNING = false;
+ public static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
- private static final boolean DEBUG_FILTERS = false;
- private static final boolean DEBUG_PERMISSIONS = false;
+ public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
- private static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
public static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
- private static final boolean DEBUG_EPHEMERAL = Build.IS_DEBUGGABLE;
- private static final boolean DEBUG_TRIAGED_MISSING = false;
+ private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
/** REMOVE. According to Svet, this was only used to reset permissions during development. */
private static final boolean ENABLE_FREE_CACHE_V2 =
SystemProperties.getBoolean("fw.free_cache_v2", true);
+ private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
+
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
-
- // Cap the size of permission trees that 3rd party apps can define
- private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text
-
- // Suffix used during package installation when copying/moving
- // package apks to install directory.
- private static final String INSTALL_PACKAGE_SUFFIX = "-";
-
- static final int SCAN_NO_DEX = 1<<1;
- static final int SCAN_FORCE_DEX = 1<<2;
- static final int SCAN_UPDATE_SIGNATURE = 1<<3;
- static final int SCAN_NEW_INSTALL = 1<<4;
- static final int SCAN_UPDATE_TIME = 1<<5;
- static final int SCAN_BOOTING = 1<<6;
- static final int SCAN_TRUSTED_OVERLAY = 1<<7;
- static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<8;
- static final int SCAN_REPLACING = 1<<9;
- static final int SCAN_REQUIRE_KNOWN = 1<<10;
- static final int SCAN_MOVE = 1<<11;
- static final int SCAN_INITIAL = 1<<12;
- static final int SCAN_CHECK_ONLY = 1<<13;
- static final int SCAN_DONT_KILL_APP = 1<<14;
- static final int SCAN_IGNORE_FROZEN = 1<<15;
- static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<16;
- static final int SCAN_AS_INSTANT_APP = 1<<17;
- static final int SCAN_AS_FULL_APP = 1<<18;
- static final int SCAN_AS_VIRTUAL_PRELOAD = 1<<19;
- /** Should not be with the scan flags */
- static final int FLAGS_REMOVE_CHATTY = 1<<31;
+ private static final int SE_UID = Process.SE_UID;
+ private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_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_CHECK_ONLY = 1 << 10;
+ static final int SCAN_DONT_KILL_APP = 1 << 11;
+ static final int SCAN_IGNORE_FROZEN = 1 << 12;
+ static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13;
+ static final int SCAN_AS_INSTANT_APP = 1 << 14;
+ static final int SCAN_AS_FULL_APP = 1 << 15;
+ static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16;
+ static final int SCAN_AS_SYSTEM = 1 << 17;
+ static final int SCAN_AS_PRIVILEGED = 1 << 18;
+ static final int SCAN_AS_OEM = 1 << 19;
+ static final int SCAN_AS_VENDOR = 1 << 20;
+ static final int SCAN_AS_PRODUCT = 1 << 21;
+ static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22;
+ static final int SCAN_AS_ODM = 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_CHECK_ONLY,
+ 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 {}
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
- private final static String COMPRESSED_EXTENSION = ".gz";
+ public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
- private final static String STUB_SUFFIX = "-Stub";
+ public final static String STUB_SUFFIX = "-Stub";
private static final int[] EMPTY_INT_ARRAY = new int[0];
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
+ * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+ * rollback within that period, the install will proceed without rollback enabled.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK
+ */
+ private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+
+ /**
+ * The default duration to wait for rollback to be enabled in
+ * milliseconds.
+ */
+ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
+
+ /**
* The default response for package verification timeout.
*
* This can be either PackageManager.VERIFICATION_ALLOW or
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
- static final String PLATFORM_PACKAGE_NAME = "android";
-
- static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
-
- static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
- DEFAULT_CONTAINER_PACKAGE,
- "com.android.defcontainer.DefaultContainerService");
+ public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String KILL_APP_REASON_GIDS_CHANGED =
"permission grant or revoke changed gids";
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
- /** Permission grant: not grant the permission. */
- private static final int GRANT_DENIED = 1;
+ private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
- /** Permission grant: grant the permission as an install permission. */
- private static final int GRANT_INSTALL = 2;
+ private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
- /** Permission grant: grant the permission as a runtime one. */
- private static final int GRANT_RUNTIME = 3;
+ private static final String ODM_OVERLAY_DIR = "/odm/overlay";
- /** Permission grant: grant as runtime a permission that was granted as an install time one. */
- private static final int GRANT_UPGRADE = 4;
+ private static final String OEM_OVERLAY_DIR = "/oem/overlay";
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
sBrowserIntent.setAction(Intent.ACTION_VIEW);
sBrowserIntent.addCategory(Intent.CATEGORY_BROWSABLE);
sBrowserIntent.setData(Uri.parse("http:"));
- }
-
- /**
- * The set of all protected actions [i.e. those actions for which a high priority
- * intent filter is disallowed].
- */
- private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
- static {
- PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
- PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
- PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
- PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
+ sBrowserIntent.addFlags(Intent.FLAG_IGNORE_EPHEMERAL);
}
// Compilation reasons.
+ public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
public static final int REASON_INSTALL = 2;
public static final int REASON_LAST = REASON_SHARED;
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
-
/**
- * Version number for the package parser cache. Increment this whenever the format or
- * extent of cached data changes. See {@code PackageParser#setCacheDir}.
+ * Whether the package parser cache is enabled.
*/
- private static final String PACKAGE_PARSER_CACHE_VERSION = "1";
+ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
/**
- * Whether the package parser cache is enabled.
+ * Permissions required in order to receive instant application lifecycle broadcasts.
*/
- private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
+ private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
+ new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS };
final ServiceThread mHandlerThread;
private final ProcessLoggingHandler mProcessLoggingHandler;
- /**
- * Messages for {@link #mHandler} that need to wait for system ready before
- * being dispatched.
- */
- private ArrayList<Message> mPostSystemReadyMessages;
-
final int mSdkVersion = Build.VERSION.SDK_INT;
final Context mContext;
final boolean mIsUpgrade;
final boolean mIsPreNUpgrade;
final boolean mIsPreNMR1Upgrade;
-
- // Have we told the Activity Manager to whitelist the default container service by uid yet?
- @GuardedBy("mPackages")
- boolean mDefaultContainerWhitelisted = false;
+ final boolean mIsPreQUpgrade;
@GuardedBy("mPackages")
private boolean mDexOptDialogShown;
- /** The location for ASEC container files on internal storage. */
- final String mAsecInternalPath;
-
// 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 third-party apps stored */
- final File mAppInstallDir;
-
- /**
- * Directory to which applications installed internally have their
- * 32 bit native libraries copied.
- */
- private File mAppLib32InstallDir;
-
- // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
- // apps.
- final File mDrmAppPrivateInstallDir;
+ /** Directory where installed applications are stored */
+ private static final File sAppInstallDir =
+ new File(Environment.getDataDirectory(), "app");
+ /** Directory where installed application's 32-bit native libraries are copied. */
+ private static final File sAppLib32InstallDir =
+ new File(Environment.getDataDirectory(), "app-lib");
// ----------------------------------------------------------------
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
@GuardedBy("mPackages")
- final ArrayMap<String, PackageParser.Package> mPackages =
- new ArrayMap<String, PackageParser.Package>();
-
- final ArrayMap<String, Set<String>> mKnownCodebase =
- new ArrayMap<String, Set<String>>();
+ final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
// Keys are isolated uids and values are the uid of the application
// that created the isolated proccess.
* are package location.
*/
final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
- /**
- * Tracks high priority intent filters for protected actions. During boot, certain
- * filter actions are protected and should never be allowed to have a high priority
- * intent filter for them. However, there is one, and only one exception -- the
- * setup wizard. It must be able to define a high priority intent filter for these
- * actions to ensure there are no escapes from the wizard. We need to delay processing
- * of these during boot as we need to look at all of the system packages in order
- * to know which component is the setup wizard.
- */
- private final List<PackageParser.ActivityIntentInfo> mProtectedFilters = new ArrayList<>();
- /**
- * Whether or not processing protected filters should be deferred.
- */
- private boolean mDeferProtectedFilters = true;
/**
* Tracks existing system packages prior to receiving an OTA. Keys are package name.
PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
- // System configuration read by SystemConfig.
- final int[] mGlobalGids;
- final SparseArray<ArraySet<String>> mSystemPermissions;
@GuardedBy("mAvailableFeatures")
final ArrayMap<String, FeatureInfo> mAvailableFeatures;
- // If mac_permissions.xml was found for seinfo labeling.
- boolean mFoundPolicyFile;
-
private final InstantAppRegistry mInstantAppRegistry;
@GuardedBy("mPackages")
@GuardedBy("mPackages")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
+ @GuardedBy("mPackages")
+ final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
+
+ @GuardedBy("mPackages")
+ private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
+
+ private final ModuleInfoProvider mModuleInfoProvider;
+
+ private final ApexManager mApexManager;
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
- final List<PackageParser.Package> getStaticOverlayPackagesLocked(
+ final List<PackageParser.Package> getStaticOverlayPackages(
Collection<PackageParser.Package> allPackages, String targetPackageName) {
+ if ("android".equals(targetPackageName)) {
+ // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+ // native AssetManager.
+ return null;
+ }
+
List<PackageParser.Package> overlayPackages = null;
for (PackageParser.Package p : allPackages) {
- if (targetPackageName.equals(p.mOverlayTarget) && p.mIsStaticOverlay) {
+ if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
if (overlayPackages == null) {
- overlayPackages = new ArrayList<PackageParser.Package>();
+ overlayPackages = new ArrayList<>();
}
overlayPackages.add(p);
}
}
if (overlayPackages != null) {
- Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
- public int compare(PackageParser.Package p1, PackageParser.Package p2) {
- return p1.mOverlayPriority - p2.mOverlayPriority;
- }
- };
- Collections.sort(overlayPackages, cmp);
+ Comparator<PackageParser.Package> cmp =
+ Comparator.comparingInt(p -> p.mOverlayPriority);
+ overlayPackages.sort(cmp);
}
return overlayPackages;
}
- final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
- String targetPackageName, String targetPath) {
- if ("android".equals(targetPackageName)) {
- // Static RROs targeting to "android", ie framework-res.apk, are already applied by
- // native AssetManager.
- return null;
- }
- List<PackageParser.Package> overlayPackages =
- getStaticOverlayPackagesLocked(allPackages, targetPackageName);
+ final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+ String targetPath) {
if (overlayPackages == null || overlayPackages.isEmpty()) {
return null;
}
for (PackageParser.Package overlayPackage : overlayPackages) {
if (targetPath == null) {
if (overlayPathList == null) {
- overlayPathList = new ArrayList<String>();
+ overlayPathList = new ArrayList<>();
}
overlayPathList.add(overlayPackage.baseCodePath);
continue;
UserHandle.getSharedAppGid(
UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
if (overlayPathList == null) {
- overlayPathList = new ArrayList<String>();
+ overlayPathList = new ArrayList<>();
}
overlayPathList.add(overlayPackage.baseCodePath);
} catch (InstallerException e) {
}
String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
- synchronized (mPackages) {
- return getStaticOverlayPathsLocked(
- mPackages.values(), targetPackageName, targetPath);
+ List<PackageParser.Package> overlayPackages;
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ overlayPackages = getStaticOverlayPackages(
+ mPackages.values(), targetPackageName);
+ }
+ // It is safe to keep overlayPackages without holding mPackages because static overlay
+ // packages can't be uninstalled or disabled.
+ return getStaticOverlayPaths(overlayPackages, targetPath);
}
}
String targetPath) {
return getStaticOverlayPaths(targetPackageName, targetPath);
}
- };
+ }
class ParallelPackageParserCallback extends PackageParserCallback {
List<PackageParser.Package> mOverlayPackages = null;
void findStaticOverlayPackages() {
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
- if (p.mIsStaticOverlay) {
+ if (p.mOverlayIsStatic) {
if (mOverlayPackages == null) {
- mOverlayPackages = new ArrayList<PackageParser.Package>();
+ mOverlayPackages = new ArrayList<>();
}
mOverlayPackages.add(p);
}
synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
// We can trust mOverlayPackages without holding mPackages because package uninstall
// can't happen while running parallel parsing.
- // Moreover holding mPackages on each parsing thread causes dead-lock.
+ // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
+ // because mInstallLock is held before running parallel parsing.
+ // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
return mOverlayPackages == null ? null :
- getStaticOverlayPathsLocked(mOverlayPackages, targetPackageName, targetPath);
+ getStaticOverlayPaths(
+ getStaticOverlayPackages(mOverlayPackages, targetPackageName),
+ targetPath);
}
}
final ParallelPackageParserCallback mParallelPackageParserCallback =
new ParallelPackageParserCallback();
- public static final class SharedLibraryEntry {
- public final @Nullable String path;
- public final @Nullable String apk;
- public final @NonNull SharedLibraryInfo info;
-
- SharedLibraryEntry(String _path, String _apk, String name, int version, int type,
- String declaringPackageName, int declaringPackageVersionCode) {
- path = _path;
- apk = _apk;
- info = new SharedLibraryInfo(name, version, type, new VersionedPackage(
- declaringPackageName, declaringPackageVersionCode), null);
- }
- }
-
// Currently known shared libraries.
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
+ final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
+ final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mStaticLibsByDeclaringPackage =
new ArrayMap<>();
- // All available activities, for your resolving pleasure.
- final ActivityIntentResolver mActivities =
- new ActivityIntentResolver();
-
- // All available receivers, for your resolving pleasure.
- final ActivityIntentResolver mReceivers =
- new ActivityIntentResolver();
-
- // All available services, for your resolving pleasure.
- final ServiceIntentResolver mServices = new ServiceIntentResolver();
-
- // All available providers, for your resolving pleasure.
- final ProviderIntentResolver mProviders = new ProviderIntentResolver();
-
- // Mapping from provider base names (first directory in content URI codePath)
- // to the provider information.
- final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority =
- new ArrayMap<String, PackageParser.Provider>();
-
// Mapping from instrumentation class names to info about them.
final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
- new ArrayMap<ComponentName, PackageParser.Instrumentation>();
-
- // Mapping from permission names to info about them.
- final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
- new ArrayMap<String, PackageParser.PermissionGroup>();
+ new ArrayMap<>();
// Packages whose data we have transfered into another package, thus
// should no longer exist.
- final ArraySet<String> mTransferedPackages = new ArraySet<String>();
+ final ArraySet<String> mTransferedPackages = 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<PackageVerificationState>();
+ final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
- /** Set of packages associated with each app op permission. */
- final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>();
+ /** List of packages waiting for rollback to be enabled. */
+ final SparseArray<InstallParams> mPendingEnableRollback = new SparseArray<>();
final PackageInstallerService mInstallerService;
+ final ArtManagerService mArtManagerService;
+
private final PackageDexOptimizer mPackageDexOptimizer;
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
private final DexManager mDexManager;
+ private final ViewCompiler mViewCompiler;
+
private AtomicInteger mNextMoveId = new AtomicInteger();
private final MoveCallbacks mMoveCallbacks;
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
// Cache of users who need badging.
- SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
+ private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
/** Token for keys in mPendingVerification. */
private int mPendingVerificationToken = 0;
+ /** Token for keys in mPendingEnableRollback. */
+ private int mPendingEnableRollbackToken = 0;
+
volatile boolean mSystemReady;
volatile boolean mSafeMode;
volatile boolean mHasSystemUidErrors;
- private volatile boolean mEphemeralAppsDisabled;
+ private volatile SparseBooleanArray mWebInstantAppsDisabled = new SparseBooleanArray();
ApplicationInfo mAndroidApplication;
final ActivityInfo mResolveActivity = new ActivityInfo();
private int mIntentFilterVerificationToken = 0;
/** The service connection to the ephemeral resolver */
- final EphemeralResolverConnection mInstantAppResolverConnection;
+ final InstantAppResolverConnection mInstantAppResolverConnection;
/** Component used to show resolver settings for Instant Apps */
final ComponentName mInstantAppResolverSettingsComponent;
ActivityInfo mInstantAppInstallerActivity;
final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
+ private final Map<String, Pair<PackageInstalledInfo, IPackageInstallObserver2>>
+ mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
+
final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
- = new SparseArray<IntentFilterVerificationState>();
+ = new SparseArray<>();
+ // TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
+ private final PermissionManagerServiceInternal mPermissionManager;
+ private final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
private List<String> mKeepUninstalledPackages;
private UserManagerInternal mUserManagerInternal;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+ private StorageManagerInternal mStorageManagerInternal;
private DeviceIdleController.LocalService mDeviceIdleController;
private File mCacheDir;
- private ArraySet<String> mPrivappPermissionsViolations;
-
private Future<?> mPrepareAppDataFuture;
private static class IFVerificationParams {
pkg = _pkg;
replacing = _replacing;
userId = _userId;
- replacing = _replacing;
verifierUid = _verifierUid;
}
}
void receiveVerificationResponse(int verificationId);
}
+ @GuardedBy("mPackages")
+ private CheckPermissionDelegate mCheckPermissionDelegate;
+
+ @GuardedBy("mPackages")
+ private PackageManagerInternal.DefaultBrowserProvider mDefaultBrowserProvider;
+
+ @GuardedBy("mPackages")
+ private PackageManagerInternal.DefaultDialerProvider mDefaultDialerProvider;
+
+ @GuardedBy("mPackages")
+ private PackageManagerInternal.DefaultHomeProvider mDefaultHomeProvider;
+
private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
private Context mContext;
private ComponentName mIntentFilterVerifierComponent;
- private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<Integer>();
+ private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
public IntentVerifierProxy(Context context, ComponentName verifierComponent) {
mContext = context;
verificationIntent.setComponent(mIntentFilterVerifierComponent);
verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ final long whitelistTimeout = getVerificationTimeout();
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppWhitelistDuration(whitelistTimeout);
+
DeviceIdleController.LocalService idleController = getDeviceIdleController();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
- mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(),
+ mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
UserHandle.USER_SYSTEM, true, "intent filter verifier");
- mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM);
+ mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM,
+ null, options.toBundle());
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Sending IntentFilter verification broadcast");
}
mIntentFilterVerificationStates.remove(verificationId);
final String packageName = ivs.getPackageName();
- IntentFilterVerificationInfo ivi = null;
+ IntentFilterVerificationInfo ivi;
synchronized (mPackages) {
ivi = mSettings.getIntentFilterVerificationLPr(packageName);
+ verificationId + " packageName:" + packageName);
return;
}
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "Updating IntentFilterVerificationInfo for package " + packageName
- +" verificationId:" + verificationId);
synchronized (mPackages) {
if (verified) {
int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
boolean needUpdate = false;
- // We cannot override the STATUS_ALWAYS / STATUS_NEVER states if they have
- // already been set by the User thru the Disambiguation dialog
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG,
+ "Updating IntentFilterVerificationInfo for package " + packageName
+ + " verificationId:" + verificationId
+ + " verified=" + verified);
+ }
+
+ // In a success case, we promote from undefined or ASK to ALWAYS. This
+ // supports a flow where the app fails validation but then ships an updated
+ // APK that passes, and therefore deserves to be in ALWAYS.
+ //
+ // If validation failed, the undefined state winds up in the basic ASK behavior,
+ // but apps that previously passed and became ALWAYS are *demoted* out of
+ // that state, since they would not deserve the ALWAYS behavior in case of a
+ // clean install.
switch (userStatus) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
+ if (!verified) {
+ // Don't demote if sysconfig says 'always'
+ SystemConfig systemConfig = SystemConfig.getInstance();
+ ArraySet<String> packages = systemConfig.getLinkedApps();
+ if (!packages.contains(packageName)) {
+ // updatedStatus is already UNDEFINED
+ needUpdate = true;
+
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Formerly validated but now failing; demoting");
+ }
+ } else {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Updating bundled package " + packageName
+ + " failed autoVerify, but sysconfig supersedes");
+ }
+ // leave needUpdate == false here intentionally
+ }
+ }
+ break;
+
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ // Stay in 'undefined' on verification failure
if (verified) {
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
- } else {
- updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
}
needUpdate = true;
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Applying update; old=" + userStatus
+ + " new=" + updatedStatus);
+ }
break;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
+ // Keep in 'ask' on failure
if (verified) {
updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
needUpdate = true;
packageName, updatedStatus, userId);
scheduleWritePackageRestrictionsLocked(userId);
}
+ } else {
+ Slog.i(TAG, "autoVerify ignored when installing for all users");
}
}
}
final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
public PendingPackageBroadcasts() {
- mUidMap = new SparseArray<ArrayMap<String, ArrayList<String>>>(2);
+ mUidMap = new SparseArray<>(2);
}
public ArrayList<String> get(int userId, String packageName) {
private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) {
ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
if (map == null) {
- map = new ArrayMap<String, ArrayList<String>>();
+ map = new ArrayMap<>();
mUidMap.put(userId, map);
}
return map;
}
final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts();
- // Service Connection to remote media container service to copy
- // package uri's from external media onto secure containers
- // or internal storage.
- private IMediaContainerService mContainerService = null;
-
static final int SEND_PENDING_BROADCAST = 1;
- static final int MCS_BOUND = 3;
- static final int END_COPY = 4;
static final int INIT_COPY = 5;
- static final int MCS_UNBIND = 6;
- static final int START_CLEANING_PACKAGE = 7;
- static final int FIND_INSTALL_LOC = 8;
static final int POST_INSTALL = 9;
- static final int MCS_RECONNECT = 10;
- static final int MCS_GIVE_UP = 11;
- static final int UPDATED_MEDIA_STATUS = 12;
static final int WRITE_SETTINGS = 13;
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int INTENT_FILTER_VERIFIED = 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 DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
+ static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
- // Delay time in millisecs
- static final int BROADCAST_DELAY = 10 * 1000;
+ 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 */
static UserManagerService sUserManager;
// Stores a list of users whose package restrictions file needs to be updated
- private ArraySet<Integer> mDirtyUsers = new ArraySet<Integer>();
-
- final private DefaultContainerConnection mDefContainerConn =
- new DefaultContainerConnection();
- class DefaultContainerConnection implements ServiceConnection {
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
- final IMediaContainerService imcs = IMediaContainerService.Stub
- .asInterface(Binder.allowBlocking(service));
- mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
- }
-
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
- }
- }
+ private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
static class PostInstallData {
- public InstallArgs args;
- public PackageInstalledInfo res;
+ public final InstallArgs args;
+ public final PackageInstalledInfo res;
+ public final Runnable mPostInstallRunnable;
- PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
+ PostInstallData(InstallArgs _a, PackageInstalledInfo _r, Runnable postInstallRunnable) {
args = _a;
res = _r;
+ mPostInstallRunnable = postInstallRunnable;
}
}
- final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
+ final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<>();
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
// XML tags for backup/restore of various bits of state
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 mSystemTextClassifierPackage;
+ final @Nullable String mWellbeingPackage;
+ final @Nullable String mDocumenterPackage;
+ final @Nullable String mConfiguratorPackage;
+ final @Nullable String mAppPredictionServicePackage;
+ final @Nullable String mIncidentReportApproverPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
- final boolean mPermissionReviewRequired;
-
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
class PackageHandler extends Handler {
- private boolean mBound = false;
- final ArrayList<HandlerParams> mPendingInstalls =
- new ArrayList<HandlerParams>();
-
- private boolean connectToService() {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
- " DefaultContainerService");
- Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- if (mContext.bindServiceAsUser(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- mBound = true;
- return true;
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- return false;
- }
-
- private void disconnectService() {
- mContainerService = null;
- mBound = false;
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- mContext.unbindService(mDefContainerConn);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
PackageHandler(Looper looper) {
super(looper);
switch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
- int idx = mPendingInstalls.size();
- if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
- // If a bind was already initiated we dont really
- // need to do anything. The pending install
- // will be processed later on.
- if (!mBound) {
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- // If this is the only one pending we might
- // have to bind to the service again.
- if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- params.serviceError();
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- if (params.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
- params.traceCookie);
- }
- return;
- } else {
- // Once we bind to the service, the first
- // pending request will be processed.
- mPendingInstalls.add(idx, params);
- }
- } else {
- mPendingInstalls.add(idx, params);
- // Already bound to the service. Just make
- // sure we trigger off processing the first request.
- if (idx == 0) {
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- break;
- }
- case MCS_BOUND: {
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
- if (msg.obj != null) {
- mContainerService = (IMediaContainerService) msg.obj;
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
- System.identityHashCode(mHandler));
- }
- if (mContainerService == null) {
- if (!mBound) {
- // Something seriously wrong since we are not bound and we are not
- // waiting for connection. Bail out.
- Slog.e(TAG, "Cannot bind to media container service");
- for (HandlerParams params : mPendingInstalls) {
- // Indicate service bind error
- params.serviceError();
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- if (params.traceMethod != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
- params.traceMethod, params.traceCookie);
- }
- return;
- }
- mPendingInstalls.clear();
- } else {
- Slog.w(TAG, "Waiting to connect to media container service");
- }
- } else if (mPendingInstalls.size() > 0) {
- HandlerParams params = mPendingInstalls.get(0);
- if (params != null) {
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
- if (params.startCopy()) {
- // We are done... look for more work or to
- // go idle.
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Checking for more work or unbind...");
- // Delete pending install
- if (mPendingInstalls.size() > 0) {
- mPendingInstalls.remove(0);
- }
- if (mPendingInstalls.size() == 0) {
- if (mBound) {
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting delayed MCS_UNBIND");
- removeMessages(MCS_UNBIND);
- Message ubmsg = obtainMessage(MCS_UNBIND);
- // Unbind after a little delay, to avoid
- // continual thrashing.
- sendMessageDelayed(ubmsg, 10000);
- }
- } else {
- // There are more pending requests in queue.
- // Just post MCS_BOUND message to trigger processing
- // of next pending install.
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Posting MCS_BOUND for next work");
- mHandler.sendEmptyMessage(MCS_BOUND);
- }
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- } else {
- // Should never happen ideally.
- Slog.w(TAG, "Empty queue");
- }
- break;
- }
- case MCS_RECONNECT: {
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
- if (mPendingInstalls.size() > 0) {
- if (mBound) {
- disconnectService();
- }
- if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- for (HandlerParams params : mPendingInstalls) {
- // Indicate service bind error
- params.serviceError();
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- }
- mPendingInstalls.clear();
- }
- }
- break;
- }
- case MCS_UNBIND: {
- // If there is no actual work left, then time to unbind.
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
-
- if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
- if (mBound) {
- if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
-
- disconnectService();
- }
- } else if (mPendingInstalls.size() > 0) {
- // There are more pending requests in queue.
- // Just post MCS_BOUND message to trigger processing
- // of next pending install.
- mHandler.sendEmptyMessage(MCS_BOUND);
+ if (params != null) {
+ if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
+ params.startCopy();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
-
- break;
- }
- case MCS_GIVE_UP: {
- if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
- HandlerParams params = mPendingInstalls.remove(0);
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
break;
}
case SEND_PENDING_BROADCAST: {
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
- if (mPendingBroadcasts == null) {
- return;
- }
size = mPendingBroadcasts.size();
if (size <= 0) {
// Nothing to be done. Just return
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
}
- case START_CLEANING_PACKAGE: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- final String packageName = (String)msg.obj;
- final int userId = msg.arg1;
- final boolean andCode = msg.arg2 != 0;
- synchronized (mPackages) {
- if (userId == UserHandle.USER_ALL) {
- int[] users = sUserManager.getUserIds();
- for (int user : users) {
- mSettings.addPackageToCleanLPw(
- new PackageCleanItem(user, packageName, andCode));
- }
- } else {
- mSettings.addPackageToCleanLPw(
- new PackageCleanItem(userId, packageName, andCode));
- }
- }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- startCleaningPackages();
- } break;
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
- if (data != null) {
+ if (data != null && data.mPostInstallRunnable != null) {
+ data.mPostInstallRunnable.run();
+ } else if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
final String[] grantedPermissions = args.installGrantPermissions;
+ final List<String> whitelistedRestrictedPermissions = ((args.installFlags
+ & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
+ && parentRes.pkg != null)
+ ? parentRes.pkg.requestedPermissions
+ : args.whitelistedRestrictedPermissions;
// Handle the parent package
- handlePackagePostInstall(parentRes, grantPermissions, killApp,
- virtualPreload, grantedPermissions, didRestore,
+ handlePackagePostInstall(parentRes, grantPermissions,
+ killApp, virtualPreload, grantedPermissions,
+ whitelistedRestrictedPermissions, didRestore,
args.installerPackageName, args.observer);
// Handle the child packages
? parentRes.addedChildPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
- handlePackagePostInstall(childRes, grantPermissions, killApp,
- virtualPreload, grantedPermissions, false /*didRestore*/,
+ handlePackagePostInstall(childRes, grantPermissions,
+ killApp, virtualPreload, grantedPermissions,
+ whitelistedRestrictedPermissions, false /*didRestore*/,
args.installerPackageName, args.observer);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
args.traceCookie);
}
- } else {
- Slog.e(TAG, "Bogus post-install token " + msg.arg1);
+ } else if (DEBUG_INSTALL) {
+ // No post-install when we run restore from installExistingPackageForUser
+ Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
- case UPDATED_MEDIA_STATUS: {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
- boolean reportStatus = msg.arg1 == 1;
- boolean doGc = msg.arg2 == 1;
- if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
- if (doGc) {
- // Force a gc to clear up stale containers.
- Runtime.getRuntime().gc();
- }
- if (msg.obj != null) {
- @SuppressWarnings("unchecked")
- Set<AsecInstallArgs> args = (Set<AsecInstallArgs>) msg.obj;
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
- // Unload containers
- unloadAllContainers(args);
- }
- if (reportStatus) {
- try {
- if (DEBUG_SD_INSTALL) Log.i(TAG,
- "Invoking StorageManagerService call back");
- PackageHelper.getStorageManager().finishMediaUpdate();
- } catch (RemoteException e) {
- Log.e(TAG, "StorageManagerService not running?");
+ case DEFERRED_NO_KILL_POST_DELETE: {
+ synchronized (mInstallLock) {
+ InstallArgs args = (InstallArgs) msg.obj;
+ if (args != null) {
+ args.doPostDeleteLI(true);
}
}
} break;
+ case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
+ String packageName = (String) msg.obj;
+ if (packageName != null) {
+ notifyInstallObserver(packageName);
+ }
+ } break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
- final InstallArgs args = state.getInstallArgs();
+ final InstallParams params = state.getInstallParams();
+ final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
mPendingVerification.remove(verificationId);
- int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
-
final UserHandle user = args.getUser();
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, user);
- try {
- ret = args.copyApk(mContainerService, true);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not contact the ContainerService");
- }
} else {
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, user);
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
- processPendingInstall(args, ret);
- mHandler.sendEmptyMessage(MCS_UNBIND);
+ params.handleVerificationFinished();
}
break;
}
if (state.isVerificationComplete()) {
mPendingVerification.remove(verificationId);
- final InstallArgs args = state.getInstallArgs();
+ final InstallParams params = state.getInstallParams();
+ final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
- int ret;
if (state.isInstallAllowed()) {
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
broadcastPackageVerified(verificationId, originUri,
- response.code, state.getInstallArgs().getUser());
- try {
- ret = args.copyApk(mContainerService, true);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not contact the ContainerService");
- }
+ response.code, args.getUser());
} else {
- ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
- processPendingInstall(args, ret);
- mHandler.sendEmptyMessage(MCS_UNBIND);
+ params.handleVerificationFinished();
}
break;
(InstantAppRequest) msg.obj,
mInstantAppInstallerActivity,
mHandler);
+ break;
+ }
+ case ENABLE_ROLLBACK_STATUS: {
+ final int enableRollbackToken = msg.arg1;
+ final int enableRollbackCode = msg.arg2;
+ InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ if (params == null) {
+ Slog.w(TAG, "Invalid rollback enabled token "
+ + enableRollbackToken + " received");
+ break;
+ }
+
+ mPendingEnableRollback.remove(enableRollbackToken);
+
+ if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
+ final InstallArgs args = params.mArgs;
+ final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+ Slog.w(TAG, "Failed to enable rollback for " + originUri);
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+
+ params.handleRollbackEnabled();
+ break;
+ }
+ case ENABLE_ROLLBACK_TIMEOUT: {
+ final int enableRollbackToken = msg.arg1;
+ final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ if (params != null) {
+ final InstallArgs args = params.mArgs;
+ final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+
+ Slog.w(TAG, "Enable rollback timed out for " + originUri);
+ mPendingEnableRollback.remove(enableRollbackToken);
+
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ params.handleRollbackEnabled();
+ Intent rollbackTimeoutIntent = new Intent(
+ Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
+ rollbackTimeoutIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
+ enableRollbackToken);
+ rollbackTimeoutIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
+ android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
+ }
+ break;
}
}
}
}
+ private PermissionCallback mPermissionCallback = new PermissionCallback() {
+ @Override
+ public void onGidsChanged(int appId, int userId) {
+ mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
+ }
+ @Override
+ public void onPermissionGranted(int uid, int userId) {
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+ // Not critical; if this is lost, the application has to request again.
+ synchronized (mPackages) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ @Override
+ public void onInstallPermissionGranted() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionRevoked(int uid, int userId) {
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+ synchronized (mPackages) {
+ // Critical; after this call the application should never have the permission
+ mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+ }
+
+ final int appId = UserHandle.getAppId(uid);
+ killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+ }
+ @Override
+ public void onInstallPermissionRevoked() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+ synchronized (mPackages) {
+ for (int userId : updatedUserIds) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
+ }
+ }
+ }
+ @Override
+ public void onInstallPermissionUpdated() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionRemoved() {
+ synchronized (mPackages) {
+ mSettings.writeLPr();
+ }
+ }
+ };
+
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
- boolean killApp, boolean virtualPreload, String[] grantedPermissions,
+ boolean killApp, boolean virtualPreload,
+ String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ final boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
+ final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
+
+ if (succeeded) {
// Send the removed broadcasts
if (res.removedInfo != null) {
res.removedInfo.sendPackageRemovedBroadcasts(killApp);
}
+ // Whitelist any restricted permissions first as some may be runtime
+ // that the installer requested to be granted at install time.
+ if (whitelistedRestrictedPermissions != null
+ && !whitelistedRestrictedPermissions.isEmpty()) {
+ mPermissionManager.setWhitelistedRestrictedPermissions(
+ res.pkg, res.newUsers, whitelistedRestrictedPermissions,
+ Process.myUid(), PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
+ mPermissionCallback);
+ }
+
// Now that we successfully installed the package, grant runtime
// permissions if requested before broadcasting the install. Also
// for legacy apps in permission review mode we clear the permission
// review flag which is used to emulate runtime permissions for
// legacy apps.
if (grantPermissions) {
- grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
+ final int callingUid = Binder.getCallingUid();
+ mPermissionManager.grantRequestedRuntimePermissions(
+ res.pkg, res.newUsers, grantedPermissions, callingUid,
+ mPermissionCallback);
}
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
// app that had no children, we grant requested runtime permissions to the new
// children if the parent on the system image had them already granted.
if (res.pkg.parentPackage != null) {
- synchronized (mPackages) {
- grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
- }
+ final int callingUid = Binder.getCallingUid();
+ mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
+ res.pkg, callingUid, mPermissionCallback);
}
synchronized (mPackages) {
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
- int[] firstUsers = EMPTY_INT_ARRAY;
- int[] updateUsers = EMPTY_INT_ARRAY;
+ int[] firstUserIds = EMPTY_INT_ARRAY;
+ int[] firstInstantUserIds = EMPTY_INT_ARRAY;
+ int[] updateUserIds = EMPTY_INT_ARRAY;
+ int[] instantUserIds = EMPTY_INT_ARRAY;
final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
for (int newUser : res.newUsers) {
- if (ps.getInstantApp(newUser)) {
- continue;
- }
+ final boolean isInstantApp = ps.getInstantApp(newUser);
if (allNewUsers) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
continue;
}
boolean isNew = true;
}
}
if (isNew) {
- firstUsers = ArrayUtils.appendInt(firstUsers, newUser);
+ if (isInstantApp) {
+ firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
+ } else {
+ firstUserIds = ArrayUtils.appendInt(firstUserIds, newUser);
+ }
} else {
- updateUsers = ArrayUtils.appendInt(updateUsers, newUser);
+ if (isInstantApp) {
+ instantUserIds = ArrayUtils.appendInt(instantUserIds, newUser);
+ } else {
+ updateUserIds = ArrayUtils.appendInt(updateUserIds, newUser);
+ }
}
}
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.applicationInfo.isSystemApp();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUsers);
+ virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/, updateUsers);
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/, updateUsers);
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
+ }
+ // if the required verifier is defined, but, is not the installer of record
+ // for the package, it gets notified
+ final boolean notifyVerifier = mRequiredVerifierPackage != null
+ && !mRequiredVerifierPackage.equals(installerPackageName);
+ if (notifyVerifier) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
+ }
+ // If package installer is defined, notify package installer about new
+ // app installed
+ if (mRequiredInstallerPackage != null) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
+ mRequiredInstallerPackage, null /*finishedReceiver*/,
+ firstUserIds, instantUserIds);
}
// Send replaced for users that don't see the package for the first time
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
- updateUsers);
+ updateUserIds, instantUserIds);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/, updateUsers);
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
+ }
+ if (notifyVerifier) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
}
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
- null /*finishedReceiver*/, updateUsers);
+ null /*finishedReceiver*/, updateUserIds, instantUserIds);
} else if (launchedForRestore && !isSystemApp(res.pkg)) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
- + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
+ + " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
+ }
+ sendFirstLaunchBroadcast(packageName, installerPackage,
+ firstUserIds, firstInstantUserIds);
+ }
+
+ // Send broadcast package appeared if external for all users
+ if (isExternal(res.pkg)) {
+ if (!update) {
+ final StorageManager storage =
+ mContext.getSystemService(StorageManager.class);
+ VolumeInfo volume =
+ storage.findVolumeByUuid(
+ res.pkg.applicationInfo.storageUuid.toString());
+ int packageExternalStorageType =
+ getPackageExternalStorageType(volume, isExternal(res.pkg));
+ // If the package was installed externally, log it.
+ if (packageExternalStorageType != StorageEnums.UNKNOWN) {
+ StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+ packageExternalStorageType, res.pkg.packageName);
+ }
}
- sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
- }
-
- // Send broadcast package appeared if forward locked/external for all users
- // treat asec-hosted packages like removable media on upgrade
- if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + res.pkg
- + " is ASEC-hosted -> AVAILABLE");
+ Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
}
final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
}
+ } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
+ for (int i = 0; i < res.libraryConsumers.size(); i++) {
+ PackageParser.Package pkg = res.libraryConsumers.get(i);
+ // send broadcast that all consumers of the static shared library have changed
+ sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/,
+ new ArrayList<>(Collections.singletonList(pkg.packageName)),
+ pkg.applicationInfo.uid);
+ }
}
// Work that needs to happen on first install within each user
- if (firstUsers != null && firstUsers.length > 0) {
- synchronized (mPackages) {
- for (int userId : firstUsers) {
- // If this app is a browser and it's newly-installed for some
- // users, clear any default-browser state in those users. The
- // app's nature doesn't depend on the user, so we can just check
- // its browser nature in any user and generalize.
- if (packageIsBrowser(packageName, userId)) {
- mSettings.setDefaultBrowserPackageNameLPw(null, userId);
+ if (firstUserIds != null && firstUserIds.length > 0) {
+ for (int userId : firstUserIds) {
+ // If this app is a browser and it's newly-installed for some
+ // users, clear any default-browser state in those users. The
+ // app's nature doesn't depend on the user, so we can just check
+ // its browser nature in any user and generalize.
+ if (packageIsBrowser(packageName, userId)) {
+ // If this browser is restored from user's backup, do not clear
+ // default-browser state for this user
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting.getInstallReason(userId)
+ != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
+ setDefaultBrowserAsyncLPw(null, userId);
+ }
}
-
- // We may also need to apply pending (restored) runtime
- // permission grants within these users.
- mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
}
+
+ // We may also need to apply pending (restored) runtime permission grants
+ // within these users.
+ mPermissionManager.restoreDelayedRuntimePermissions(packageName,
+ UserHandle.of(userId));
+
+ // Persistent preferred activity might have came into effect due to this
+ // install.
+ updateDefaultHomeNotLocked(userId);
}
}
+ if (allNewUsers && !update) {
+ notifyPackageAdded(packageName, res.uid);
+ } else {
+ notifyPackageChanged(packageName, res.uid);
+ }
+
// Log current value of "unknown sources" setting
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
- // We delete after a gc for applications on sdcard.
- if (res.removedInfo != null && res.removedInfo.args != null) {
- Runtime.getRuntime().gc();
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
+ InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+ if (args != null) {
+ if (!killApp) {
+ // If we didn't kill the app, defer the deletion of code/resource files, since
+ // they may still be in use by the running application. This mitigates problems
+ // in cases where resources or code is loaded by a new Activity before
+ // ApplicationInfo changes have propagated to all application threads.
+ scheduleDeferredNoKillPostDelete(args);
+ } else {
+ synchronized (mInstallLock) {
+ args.doPostDeleteLI(true);
+ }
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
- for (int userId : firstUsers) {
+ for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an uninstall.
// This can lead to package info being null (b/36642664).
}
}
- // If someone is watching installs - notify them
+ final boolean deferInstallObserver = succeeded && update && !killApp;
+ if (deferInstallObserver) {
+ scheduleDeferredNoKillInstallObserver(res, installObserver);
+ } else {
+ notifyInstallObserver(res, installObserver);
+ }
+ }
+
+ @Override
+ public void notifyPackagesReplacedReceived(String[] packages) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
+ for (String packageName : packages) {
+ PackageSetting setting = mSettings.mPackages.get(packageName);
+ if (setting != null && filterAppAccessLPr(setting, callingUid, callingUserId)) {
+ notifyInstallObserver(packageName);
+ }
+ }
+ }
+
+ @Override
+ public List<SplitPermissionInfoParcelable> getSplitPermissions() {
+ return PermissionManager.splitPermissionInfoListToParcelableList(
+ SystemConfig.getInstance().getSplitPermissions());
+ }
+
+ private void notifyInstallObserver(String packageName) {
+ Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
+ mNoKillInstallObservers.remove(packageName);
+
+ if (pair != null) {
+ notifyInstallObserver(pair.first, pair.second);
+ }
+ }
+
+ private void notifyInstallObserver(PackageInstalledInfo info,
+ IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
- Bundle extras = extrasForInstallResult(res);
- installObserver.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
+ Bundle extras = extrasForInstallResult(info);
+ installObserver.onPackageInstalled(info.name, info.returnCode,
+ info.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
- private void grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(
- PackageParser.Package pkg) {
- if (pkg.parentPackage == null) {
- return;
- }
- if (pkg.requestedPermissions == null) {
- return;
- }
- final PackageSetting disabledSysParentPs = mSettings
- .getDisabledSystemPkgLPr(pkg.parentPackage.packageName);
- if (disabledSysParentPs == null || disabledSysParentPs.pkg == null
- || !disabledSysParentPs.isPrivileged()
- || (disabledSysParentPs.childPackageNames != null
- && !disabledSysParentPs.childPackageNames.isEmpty())) {
- return;
- }
- final int[] allUserIds = sUserManager.getUserIds();
- final int permCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permCount; i++) {
- String permission = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
- continue;
- }
- for (int userId : allUserIds) {
- if (disabledSysParentPs.getPermissionsState().hasRuntimePermission(
- permission, userId)) {
- grantRuntimePermission(pkg.packageName, permission, userId);
+ private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
+ Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
+ mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
+ }
+
+ private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
+ IPackageInstallObserver2 observer) {
+ String packageName = info.pkg.packageName;
+ 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);
+ }
+
+ /**
+ * Gets the type of the external storage a package is installed on.
+ * @param packageVolume The storage volume of the package.
+ * @param packageIsExternal true if the package is currently installed on
+ * external/removable/unprotected storage.
+ * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
+ * corresponding {@link StorageEnum} storage type value if it is.
+ */
+ private static int getPackageExternalStorageType(VolumeInfo packageVolume,
+ boolean packageIsExternal) {
+ if (packageVolume != null) {
+ DiskInfo disk = packageVolume.getDisk();
+ if (disk != null) {
+ if (disk.isSd()) {
+ return StorageEnums.SD_CARD;
+ }
+ if (disk.isUsb()) {
+ return StorageEnums.USB;
+ }
+ if (packageIsExternal) {
+ return StorageEnums.OTHER;
}
}
}
+ return StorageEnums.UNKNOWN;
}
private StorageEventListener mStorageListener = new StorageEventListener() {
unloadPrivatePackages(vol);
}
}
-
- if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.isPrimary()) {
- if (vol.state == VolumeInfo.STATE_MOUNTED) {
- updateExternalMediaStatus(true, false);
- } else if (vol.state == VolumeInfo.STATE_EJECTING) {
- updateExternalMediaStatus(false, false);
- }
- }
}
@Override
}
};
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
- String[] grantedPermissions) {
- for (int userId : userIds) {
- grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
- }
- }
-
- private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
- String[] grantedPermissions) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
-
- PermissionsState permissionsState = ps.getPermissionsState();
-
- final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
- | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-
- final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M;
-
- final boolean instantApp = isInstantApp(pkg.packageName, userId);
-
- for (String permission : pkg.requestedPermissions) {
- final BasePermission bp;
- synchronized (mPackages) {
- bp = mSettings.mPermissions.get(permission);
- }
- if (bp != null && (bp.isRuntime() || bp.isDevelopment())
- && (!instantApp || bp.isInstant())
- && (supportsRuntimePermissions || !bp.isRuntimeOnly())
- && (grantedPermissions == null
- || ArrayUtils.contains(grantedPermissions, permission))) {
- final int flags = permissionsState.getPermissionFlags(permission, userId);
- if (supportsRuntimePermissions) {
- // Installer cannot change immutable permissions.
- if ((flags & immutableFlags) == 0) {
- grantRuntimePermission(pkg.packageName, permission, userId);
- }
- } else if (mPermissionReviewRequired) {
- // In permission review mode we clear the review flag when we
- // are asked to install the app with all permissions granted.
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- updatePermissionFlags(permission, pkg.packageName,
- PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, userId);
- }
- }
- }
- }
- }
-
Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
switch (res.returnCode) {
mContext = context;
- mPermissionReviewRequired = context.getResources().getBoolean(
- R.bool.config_permissionReviewRequired);
-
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
- mSettings = new Settings(mPackages);
+ mInstaller = installer;
+
+ // Create sub-components that provide services / data. Order here is important.
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ // Expose private service for system components to use.
+ LocalServices.addService(
+ PackageManagerInternal.class, new PackageManagerInternalImpl());
+ sUserManager = new UserManagerService(context, this,
+ new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
+ mComponentResolver = new ComponentResolver(sUserManager,
+ LocalServices.getService(PackageManagerInternal.class),
+ mPackages);
+ mPermissionManager = PermissionManagerService.create(context,
+ mPackages /*externalLock*/);
+ mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
+ mSettings = new Settings(Environment.getDataDirectory(),
+ mPermissionManager.getPermissionSettings(), mPackages);
+ }
+ }
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.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);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
mSeparateProcesses = null;
}
- mInstaller = installer;
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
- mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);
+ mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock);
+ mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
+ mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
+
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
SystemConfig systemConfig = SystemConfig.getInstance();
- mGlobalGids = systemConfig.getGlobalGids();
- mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
mProtectedPackages = new ProtectedPackages(mContext);
+ mApexManager = new ApexManager(context);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
mHandler = new PackageHandler(mHandlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
-
- mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
mInstantAppRegistry = new InstantAppRegistry(this);
- File dataDir = Environment.getDataDirectory();
- mAppInstallDir = new File(dataDir, "app");
- mAppLib32InstallDir = new File(dataDir, "app-lib");
- mAsecInternalPath = new File(dataDir, "app-asec").getPath();
- mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- sUserManager = new UserManagerService(context, this,
- new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
-
- // Propagate permission configuration in to package manager.
- ArrayMap<String, SystemConfig.PermissionEntry> permConfig
- = systemConfig.getPermissions();
- for (int i=0; i<permConfig.size(); i++) {
- SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
- BasePermission bp = mSettings.mPermissions.get(perm.name);
- if (bp == null) {
- bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
- mSettings.mPermissions.put(perm.name, bp);
- }
- if (perm.gids != null) {
- bp.setGids(perm.gids, perm.perUser);
- }
+ ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
+ = systemConfig.getSharedLibraries();
+ final int builtInLibCount = libConfig.size();
+ for (int i = 0; i < builtInLibCount; i++) {
+ String name = libConfig.keyAt(i);
+ SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
+ addBuiltInSharedLibraryLocked(entry.filename, name);
}
- ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
- final int builtInLibCount = libConfig.size();
+ // 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);
- String path = libConfig.valueAt(i);
- addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
- SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
+ 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);
+ }
+ }
}
- mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
+ SELinuxMMAC.readInstallPolicy();
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
+ FallbackCategoryProvider.loadFallbacks();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
}
}
- if (mFirstBoot) {
+ if (!mOnlyCore && mFirstBoot) {
requestCopyPreoptedFiles();
}
- String customResolverActivity = Resources.getSystem().getString(
+ String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
- if (TextUtils.isEmpty(customResolverActivity)) {
- customResolverActivity = null;
- } else {
+ if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
- customResolverActivity);
+ customResolverActivityName);
}
long startTime = SystemClock.uptimeMillis();
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;
+
+ int preUpgradeSdkVersion = ver.sdkVersion;
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
}
}
- mCacheDir = preparePackageParserCache(mIsUpgrade);
+ mCacheDir = preparePackageParserCache();
// Set flag to monitor and not change apk file paths when
// scanning install directories.
scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
}
- // Collect vendor overlay packages. (Do this before scanning any apps.)
- // For security and version matching reason, only consider
- // overlay packages if they reside in the right directory.
- scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR
- | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
+ // Collect vendor/product/product_services overlay packages. (Do this before scanning
+ // any apps.)
+ // For security and version matching reason, only consider overlay packages if they
+ // reside in the right directory.
+ scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
+ 0);
+ scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT,
+ 0);
+ scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT_SERVICES,
+ 0);
+ scanDirTracedLI(new File(ODM_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_ODM,
+ 0);
+ scanDirTracedLI(new File(OEM_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_OEM,
+ 0);
mParallelPackageParserCallback.findStaticOverlayPackages();
// Find base frameworks (resource packages without code).
- scanDirTracedLI(frameworkDir, mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR
- | PackageParser.PARSE_IS_PRIVILEGED,
- scanFlags | SCAN_NO_DEX, 0);
-
- // Collected privileged system packages.
+ scanDirTracedLI(frameworkDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_NO_DEX
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRIVILEGED,
+ 0);
+ if (!mPackages.containsKey("android")) {
+ throw new IllegalStateException(
+ "Failed to load frameworks package; check log for warnings");
+ }
+
+ // Collect privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
- scanDirTracedLI(privilegedAppDir, mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR
- | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
+ scanDirTracedLI(privilegedAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRIVILEGED,
+ 0);
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
- scanDirTracedLI(systemAppDir, mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
-
- // Collect all vendor packages.
- File vendorAppDir = new File("/vendor/app");
+ scanDirTracedLI(systemAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM,
+ 0);
+
+ // Collect privileged vendor packages.
+ File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+ try {
+ privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedVendorAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary vendor packages.
+ File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
- scanDirTracedLI(vendorAppDir, mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ scanDirTracedLI(vendorAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
+ 0);
+
+ // Collect privileged odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
+ "priv-app");
+ try {
+ privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedOdmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File odmAppDir = new File(Environment.getOdmDirectory(), "app");
+ try {
+ odmAppDir = odmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(odmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
+ 0);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
- scanDirTracedLI(oemAppDir, mDefParseFlags
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ scanDirTracedLI(oemAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_OEM,
+ 0);
+
+ // Collected privileged /product packages.
+ File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
+ try {
+ privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedProductAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary /product packages.
+ File productAppDir = new File(Environment.getProductDirectory(), "app");
+ try {
+ productAppDir = productAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(productAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT,
+ 0);
+
+ // Collected privileged /product_services packages.
+ File privilegedProductServicesAppDir =
+ new File(Environment.getProductServicesDirectory(), "priv-app");
+ try {
+ privilegedProductServicesAppDir =
+ privilegedProductServicesAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedProductServicesAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT_SERVICES
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary /product_services packages.
+ File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app");
+ try {
+ productServicesAppDir = productServicesAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(productServicesAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT_SERVICES,
+ 0);
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
- logCriticalInfo(Log.WARN, "Expecting better updated system app for "
- + ps.name + "; removing system app. Last known codePath="
- + ps.codePathString + ", installStatus=" + ps.installStatus
- + ", versionCode=" + ps.versionCode + "; scanned versionCode="
- + scannedPkg.mVersionCode);
+ logCriticalInfo(Log.WARN,
+ "Expecting better updated system app for " + ps.name
+ + "; removing system app. Last known"
+ + " codePath=" + ps.codePathString
+ + ", versionCode=" + ps.versionCode
+ + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
if (disabledPs.codePath == null || !disabledPs.codePath.exists()
|| disabledPs.pkg == null) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
+ } else {
+ // We're expecting that the system app should remain disabled, but add
+ // it to expecting better to recover in case the data version cannot
+ // be scanned.
+ mExpectingBetter.put(disabledPs.name, disabledPs.codePath);
}
}
}
}
- //look for any incomplete package installations
- ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
- for (int i = 0; i < deletePkgsList.size(); i++) {
- // Actual deletion of code and data will be handled by later
- // reconciliation step
- final String packageName = deletePkgsList.get(i).name;
- logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
- synchronized (mPackages) {
- mSettings.removePackageLPw(packageName);
- }
- }
-
//delete tmp files
deleteTempPackageFiles();
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
-
- scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
- | PackageParser.PARSE_FORWARD_LOCK,
- scanFlags | SCAN_REQUIRE_KNOWN, 0);
+ scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
- for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
- PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
- mSettings.removeDisabledSystemPackageLPw(deletedAppName);
-
+ for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
+ final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
+ final PackageParser.Package pkg = mPackages.get(packageName);
final String msg;
- if (deletedPkg == null) {
+
+ // remove from the disabled system list; do this first so any future
+ // scans of this package are performed without this state
+ mSettings.removeDisabledSystemPackageLPw(packageName);
+
+ if (pkg == null) {
// should have found an update, but, we didn't; remove everything
- msg = "Updated system package " + deletedAppName
+ msg = "Updated system package " + packageName
+ " no longer exists; removing its data";
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
// found an update; revoke system privileges
- msg = "Updated system package + " + deletedAppName
- + " no longer exists; revoking system privileges";
+ msg = "Updated system package " + packageName
+ + " no longer exists; rescanning package on data";
+
+ // NOTE: We don't do anything special if a stub is removed from the
+ // system image. But, if we were [like removing the uncompressed
+ // version from the /data partition], this is where it'd be done.
+
+ // remove the package from the system and re-scan it without any
+ // special privileges
+ removePackageLI(pkg, true);
+ try {
+ final File codePath = new File(pkg.applicationInfo.getCodePath());
+ scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ + e.getMessage());
+ }
+ }
- // Don't do anything if a stub is removed from the system image. If
- // we were to remove the uncompressed version from the /data partition,
- // this is where it'd be done.
+ // one final check. if we still have a package setting [ie. it was
+ // previously scanned and known to the system], but, we don't have
+ // a package [ie. there was an error scanning it from the /data
+ // partition], completely remove the package data.
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null && mPackages.get(packageName) == null) {
+ removePackageDataLIF(ps, null, null, 0, false);
- final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
- deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
- deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
logCriticalInfo(Log.WARN, msg);
}
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
- int reparseFlags = mDefParseFlags;
+ final @ParseFlags int reparseFlags;
+ final @ScanFlags int rescanFlags;
if (FileUtils.contains(privilegedAppDir, scanFile)) {
- reparseFlags = PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR
- | PackageParser.PARSE_IS_PRIVILEGED;
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRIVILEGED;
} else if (FileUtils.contains(systemAppDir, scanFile)) {
- reparseFlags = PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR;
- } else if (FileUtils.contains(vendorAppDir, scanFile)) {
- reparseFlags = PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR;
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM;
+ } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
+ || FileUtils.contains(privilegedOdmAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED;
+ } else if (FileUtils.contains(vendorAppDir, scanFile)
+ || FileUtils.contains(odmAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR;
} else if (FileUtils.contains(oemAppDir, scanFile)) {
- reparseFlags = PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR;
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_OEM;
+ } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT
+ | SCAN_AS_PRIVILEGED;
+ } else if (FileUtils.contains(productAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT;
+ } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT_SERVICES
+ | SCAN_AS_PRIVILEGED;
+ } else if (FileUtils.contains(productServicesAppDir, scanFile)) {
+ reparseFlags =
+ mDefParseFlags |
+ PackageParser.PARSE_IS_SYSTEM_DIR;
+ rescanFlags =
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_PRODUCT_SERVICES;
} else {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
continue;
mSettings.enableSystemPackageLPw(packageName);
try {
- scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
+ scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
- decompressSystemApplications(stubSystemApps, scanFlags);
+ installSystemStubPackages(stubSystemApps, scanFlags);
final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
- cachedSystemApps;
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageName();
- if (mProtectedFilters.size() > 0) {
- if (DEBUG_FILTERS && mSetupWizardPackage == null) {
- Slog.i(TAG, "No setup wizard;"
- + " All protected intents capped to priority 0");
- }
- for (ActivityIntentInfo filter : mProtectedFilters) {
- if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Found setup wizard;"
- + " allow priority " + filter.getPriority() + ";"
- + " package: " + filter.activity.info.packageName
- + " activity: " + filter.activity.className
- + " priority: " + filter.getPriority());
- }
- // skip setup wizard; allow it to keep the high priority filter
- continue;
- }
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; cap priority to 0;"
- + " package: " + filter.activity.info.packageName
- + " activity: " + filter.activity.className
- + " origPrio: " + filter.getPriority());
- }
- filter.setPriority(0);
- }
- }
- mDeferProtectedFilters = false;
- mProtectedFilters.clear();
+ mComponentResolver.fixProtectedFilterPriorities();
+
+ mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
+
+ mWellbeingPackage = getWellbeingPackageName();
+ mDocumenterPackage = getDocumenterPackageName();
+ mConfiguratorPackage =
+ mContext.getString(R.string.config_deviceConfiguratorPackageName);
+ mAppPredictionServicePackage = getAppPredictionServicePackageName();
+ mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
- updateAllSharedLibrariesLPw(null);
+ updateAllSharedLibrariesLocked(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.
- adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+ final List<String> changedAbiCodePath =
+ adjustCpuAbisForSharedUserLPw(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();
}
// Now that we know all the packages we are keeping,
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
- int updateFlags = UPDATE_PERMISSIONS_ALL;
- if (ver.sdkVersion != mSdkVersion) {
+ final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
+ if (sdkUpdated) {
Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for internal storage");
- updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
+ mPermissionCallback);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
// all defined users.
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
- mSettings.applyDefaultPreferredAppsLPw(this, user.id);
- applyFactoryDefaultBrowserLPw(user.id);
+ mSettings.applyDefaultPreferredAppsLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
- checkDefaultBrowser();
+ // Grandfather existing (installed before Q) non-system apps to hide
+ // their icons in launcher.
+ if (!onlyCore && mIsPreQUpgrade) {
+ Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
+ int size = mSettings.mPackages.size();
+ for (int i = 0; i < size; i++) {
+ final PackageSetting ps = mSettings.mPackages.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
mExistingSystemPackages.clear();
mServicesSystemSharedLibraryPackageName = null;
mSharedSystemSharedLibraryPackageName = null;
}
+ // PermissionController hosts default permission granting and role management, so it's a
+ // critical part of the core system.
+ mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
+
+ // Initialize InstantAppRegistry's Instant App list for all users.
+ final int[] userIds = UserManagerService.getInstance().getUserIds();
+ for (PackageParser.Package pkg : mPackages.values()) {
+ if (pkg.isSystem()) {
+ continue;
+ }
+ for (int userId : userIds) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
+ continue;
+ }
+ mInstantAppRegistry.addInstantAppLPw(userId, ps.appId);
+ }
+ }
- mInstallerService = new PackageInstallerService(context, this);
+ mInstallerService = new PackageInstallerService(context, this, mApexManager);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
}
- mInstantAppResolverConnection = new EphemeralResolverConnection(
+ mInstantAppResolverConnection = new InstantAppResolverConnection(
mContext, instantAppResolverComponent.first,
instantAppResolverComponent.second);
mInstantAppResolverSettingsComponent =
// should take a fairly small time compare to the other activities (e.g. package
// scanning).
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
+ mModuleInfoProvider = new ModuleInfoProvider(mContext, this);
+
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Runtime.getRuntime().gc();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
- FallbackCategoryProvider.loadFallbacks();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
// 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(mPackages);
- // Expose private service for system components to use.
- LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
+ PackageParser.readConfigUseRoundIcon(mContext.getResources());
+
+ mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
+
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
* <p>In order to forcefully attempt an installation of a full application, go to app
* settings and enable the application.
*/
- private void decompressSystemApplications(@NonNull List<String> stubSystemApps, int scanFlags) {
- for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
- final String pkgName = stubSystemApps.get(i);
+ private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
+ @ScanFlags int scanFlags) {
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String packageName = systemStubPackageNames.get(i);
// skip if the system package is already disabled
- if (mSettings.isDisabledSystemPackageLPr(pkgName)) {
- stubSystemApps.remove(i);
+ if (mSettings.isDisabledSystemPackageLPr(packageName)) {
+ systemStubPackageNames.remove(i);
continue;
}
// skip if the package isn't installed (?!); this should never happen
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- stubSystemApps.remove(i);
+ systemStubPackageNames.remove(i);
continue;
}
// skip if the package has been disabled by the user
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
- stubSystemApps.remove(i);
+ systemStubPackageNames.remove(i);
continue;
}
}
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Uncompressing system stub; pkg: " + pkgName);
- }
-
- // uncompress the binary to its eventual destination on /data
- final File scanFile = decompressPackage(pkg);
- if (scanFile == null) {
- continue;
- }
-
// install the package to replace the stub on /system
try {
- mSettings.disableSystemPackageLPw(pkgName, true /*replaced*/);
- removePackageLI(pkg, true /*chatty*/);
- scanPackageTracedLI(scanFile, 0 /*reparseFlags*/, scanFlags, 0, null);
+ installStubPackageLI(pkg, 0, scanFlags);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
UserHandle.USER_SYSTEM, "android");
- stubSystemApps.remove(i);
- continue;
+ systemStubPackageNames.remove(i);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
}
}
// disable any stub still left; these failed to install the full application
- for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
- final String pkgName = stubSystemApps.get(i);
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String pkgName = systemStubPackageNames.get(i);
final PackageSetting ps = mSettings.mPackages.get(pkgName);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
}
}
- private int decompressFile(File srcFile, File dstFile) throws ErrnoException {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
- }
- try (
- InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
- OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
- ) {
- Streams.copy(fileIn, fileOut);
- Os.chmod(dstFile.getAbsolutePath(), 0644);
- return PackageManager.INSTALL_SUCCEEDED;
- } catch (IOException e) {
- logCriticalInfo(Log.ERROR, "Failed to decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
+ /**
+ * Extract, install and enable a stub package.
+ * <p>If the compressed file can not be extracted / installed for any reason, the stub
+ * APK will be installed and the package will be disabled. To recover from this situation,
+ * the user will need to go into system settings and re-enable the package.
+ */
+ private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+ final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+ | PackageParser.PARSE_ENFORCE_CODE;
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg;
+ try (PackageFreezer freezer =
+ freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+ synchronized (mPackages) {
+ prepareAppDataAfterInstallLIF(pkg);
+ try {
+ updateSharedLibrariesLocked(pkg, null, mPackages);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+ }
+ mPermissionManager.updatePermissions(
+ pkg.packageName, pkg, true, mPackages.values(),
+ mPermissionCallback);
+ mSettings.writeLPr();
+ }
+ } catch (PackageManagerException e) {
+ // Whoops! Something went very wrong; roll back to the stub and disable the package
+ try (PackageFreezer freezer =
+ freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ synchronized (mPackages) {
+ // NOTE: Ensure the system package is enabled; even for a compressed stub.
+ // If we don't, installing the system package fails during scan
+ enableSystemPackageLPw(stubPkg);
+ }
+ installPackageFromSystemLIF(stubPkg.codePath,
+ null /*allUserHandles*/, null /*origUserHandles*/,
+ null /*origPermissionsState*/, true /*writeSettings*/);
+ } catch (PackageManagerException pme) {
+ // Serious WTF; we have to be able to install the stub
+ Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+ } finally {
+ // Disable the package; the stub by itself is not runnable
+ synchronized (mPackages) {
+ final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
+ UserHandle.USER_SYSTEM, "android");
+ }
+ mSettings.writeLPr();
+ }
+ }
+ return false;
+ }
+ clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mDexManager.notifyPackageUpdated(pkg.packageName,
+ pkg.baseCodePath, pkg.splitCodePaths);
}
- return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return true;
}
- private File[] getCompressedFiles(String codePath) {
- final File stubCodePath = new File(codePath);
- final String stubName = stubCodePath.getName();
-
- // The layout of a compressed package on a given partition is as follows :
- //
- // Compressed artifacts:
- //
- // /partition/ModuleName/foo.gz
- // /partation/ModuleName/bar.gz
- //
- // Stub artifact:
- //
- // /partition/ModuleName-Stub/ModuleName-Stub.apk
- //
- // In other words, stub is on the same partition as the compressed artifacts
- // and in a directory that's suffixed with "-Stub".
- int idx = stubName.lastIndexOf(STUB_SUFFIX);
- if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
- return null;
+ private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+ @ParseFlags int parseFlags, @ScanFlags int scanFlags)
+ throws PackageManagerException {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
}
-
- final File stubParentDir = stubCodePath.getParentFile();
- if (stubParentDir == null) {
- Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
- return null;
+ // uncompress the binary to its eventual destination on /data
+ final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+ if (scanFile == null) {
+ throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
}
-
- final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
- final File[] files = compressedPath.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
- }
- });
-
- if (DEBUG_COMPRESSION && files != null && files.length > 0) {
- Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
+ synchronized (mPackages) {
+ mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+ }
+ removePackageLI(stubPkg, true /*chatty*/);
+ try {
+ return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+ // Remove the failed install
+ removeCodePathLI(scanFile);
+ throw e;
}
-
- return files;
- }
-
- private boolean compressedFileExists(String codePath) {
- final File[] compressedFiles = getCompressedFiles(codePath);
- return compressedFiles != null && compressedFiles.length > 0;
}
/**
* the /data partition.
* @return The directory the package was decompressed into. Otherwise, {@code null}.
*/
- private File decompressPackage(PackageParser.Package pkg) {
- final File[] compressedFiles = getCompressedFiles(pkg.codePath);
+ private File decompressPackage(String packageName, String codePath) {
+ final File[] compressedFiles = getCompressedFiles(codePath);
if (compressedFiles == null || compressedFiles.length == 0) {
if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "No files to decompress: " + pkg.baseCodePath);
+ Slog.i(TAG, "No files to decompress: " + codePath);
}
return null;
}
final File dstCodePath =
- getNextCodePath(Environment.getDataAppDirectory(null), pkg.packageName);
+ getNextCodePath(Environment.getDataAppDirectory(null), packageName);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
Os.mkdir(dstCodePath.getAbsolutePath(), 0755);
ret = decompressFile(srcFile, dstFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + pkg.packageName
+ + "; pkg: " + packageName
+ ", file: " + dstFileName);
break;
}
}
} catch (ErrnoException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + pkg.packageName
+ + "; pkg: " + packageName
+ ", err: " + e.errno);
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
null /*abiOverride*/);
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
- + "; pkg: " + pkg.packageName);
+ + "; pkg: " + packageName);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
}
if (ret != PackageManager.INSTALL_SUCCEEDED) {
- if (dstCodePath == null || !dstCodePath.exists()) {
+ if (!dstCodePath.exists()) {
return null;
}
removeCodePathLI(dstCodePath);
return dstCodePath;
}
+ @GuardedBy("mPackages")
private void updateInstantAppInstallerLocked(String modifiedPackage) {
// we're only interested in updating the installer appliction when 1) it's not
// already set or 2) the modified package is the installer
setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
}
- private static File preparePackageParserCache(boolean isUpgrade) {
+ private static @Nullable File preparePackageParserCache() {
if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
return null;
}
}
// The base directory for the package parser cache lives under /data/system/.
- final File cacheBaseDir = FileUtils.createDir(Environment.getDataSystemDirectory(),
- "package_cache");
- if (cacheBaseDir == null) {
+ final File cacheBaseDir = Environment.getPackageCacheDirectory();
+ if (!FileUtils.createDir(cacheBaseDir)) {
return null;
}
- // If this is a system upgrade scenario, delete the contents of the package cache dir.
- // This also serves to "GC" unused entries when the package cache version changes (which
- // can only happen during upgrades).
- if (isUpgrade) {
- FileUtils.deleteContents(cacheBaseDir);
+ // 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 = SystemProperties.digestOf(
+ "ro.build.fingerprint",
+ StorageManager.PROP_ISOLATED_STORAGE,
+ StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
+
+ // 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);
- // Return the versioned package cache directory. This is something like
- // "/data/system/package_cache/1"
- File cacheDir = FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
+ 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
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
if (cacheDir.lastModified() < frameworkDir.lastModified()) {
FileUtils.deleteContents(cacheBaseDir);
- cacheDir = FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
+ cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
}
}
}
@Override
- public boolean isUpgrade() {
+ public boolean isDeviceUpgrading() {
// allow instant applications
- return mIsUpgrade;
+ // 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() {
private @NonNull String getRequiredSharedLibraryLPr(String name, int version) {
synchronized (mPackages) {
- SharedLibraryEntry libraryEntry = getSharedLibraryEntryLPr(name, version);
- if (libraryEntry == null) {
+ SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version);
+ if (libraryInfo == null) {
throw new IllegalStateException("Missing required shared library:" + name);
}
- return libraryEntry.apk;
+ String packageName = libraryInfo.getPackageName();
+ if (packageName == null) {
+ throw new IllegalStateException("Expected a package for shared library " + name);
+ }
+ return packageName;
}
}
private @NonNull String getRequiredInstallerLPr() {
final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
+ 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,
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 String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver NOT found; empty package list");
}
return null;
final Intent resolverIntent = new Intent(actionName);
List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
- // temporarily look for the old action
- if (resolvers.size() == 0) {
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Ephemeral resolver not found with new action; try old one");
- }
- actionName = Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE;
- resolverIntent.setAction(actionName);
- resolvers = queryIntentServicesInternal(resolverIntent, null,
- resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
- }
final int N = resolvers.size();
if (N == 0) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver NOT found; no matching intent filters");
}
return null;
final String packageName = info.serviceInfo.packageName;
if (!possiblePackages.contains(packageName) && !Build.IS_DEBUGGABLE) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Ephemeral resolver not in allowed package list;"
+ " pkg: " + packageName + ", info:" + info);
}
continue;
}
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver found;"
+ " pkg: " + packageName + ", info:" + info);
}
return new Pair<>(new ComponentName(packageName, info.serviceInfo.name), actionName);
}
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Ephemeral resolver NOT found");
}
return null;
}
+ @GuardedBy("mPackages")
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
- final Intent intent = new Intent(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
+ String[] orderedActions = Build.IS_ENG
+ ? 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
- | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
- List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
- resolveFlags, UserHandle.USER_SYSTEM);
- // temporarily look for the old action
- if (matches.isEmpty()) {
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Ephemeral installer not found with new action; try old one");
- }
- intent.setAction(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
+ | MATCH_DIRECT_BOOT_UNAWARE
+ | Intent.FLAG_IGNORE_EPHEMERAL
+ | (!Build.IS_ENG ? MATCH_SYSTEM_ONLY : 0);
+ 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 PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
if (ps != null) {
final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)) {
+ if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
+ || Build.IS_ENG) {
continue;
}
}
final int resolveFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null, resolveFlags,
UserHandle.USER_SYSTEM);
- // temporarily look for the old action
- if (matches.isEmpty()) {
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Ephemeral resolver settings not found with new action; try old one");
- }
- intent.setAction(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS);
- matches = queryIntentActivitiesInternal(intent, null, resolveFlags,
- UserHandle.USER_SYSTEM);
- }
if (matches.isEmpty()) {
return null;
}
return matches.get(0).getComponentInfo().getComponentName();
}
+ @GuardedBy("mPackages")
private void primeDomainVerificationsLPw(int userId) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Priming domain verifications in user " + userId);
for (String packageName : packages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
- if (!pkg.isSystemApp()) {
+ if (!pkg.isSystem()) {
Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>");
continue;
}
for (ActivityIntentInfo filter : a.intents) {
if (hasValidDomains(filter)) {
if (domains == null) {
- domains = new ArraySet<String>();
+ domains = new ArraySet<>();
}
domains.addAll(filter.getHostsList());
}
scheduleWriteSettingsLocked();
}
- private void applyFactoryDefaultBrowserLPw(int userId) {
- // The default browser app's package name is stored in a string resource,
- // with a product-specific overlay used for vendor customization.
- String browserPkg = mContext.getResources().getString(
- com.android.internal.R.string.default_browser);
- if (!TextUtils.isEmpty(browserPkg)) {
- // non-empty string => required to be a known package
- PackageSetting ps = mSettings.mPackages.get(browserPkg);
- if (ps == null) {
- Slog.e(TAG, "Product default browser app does not exist: " + browserPkg);
- browserPkg = null;
- } else {
- mSettings.setDefaultBrowserPackageNameLPw(browserPkg, userId);
- }
- }
-
- // Nothing valid explicitly set? Make the factory-installed browser the explicit
- // default. If there's more than one, just leave everything alone.
- if (browserPkg == null) {
- calculateDefaultBrowserLPw(userId);
- }
- }
-
- private void calculateDefaultBrowserLPw(int userId) {
- List<String> allBrowsers = resolveAllBrowserApps(userId);
- final String browserPkg = (allBrowsers.size() == 1) ? allBrowsers.get(0) : null;
- mSettings.setDefaultBrowserPackageNameLPw(browserPkg, userId);
- }
-
- private List<String> resolveAllBrowserApps(int userId) {
- // Resolve the canonical browser intent and check that the handleAllWebDataURI boolean is set
- List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
- PackageManager.MATCH_ALL, userId);
-
- final int count = list.size();
- List<String> result = new ArrayList<String>(count);
- for (int i=0; i<count; i++) {
- ResolveInfo info = list.get(i);
- if (info.activityInfo == null
- || !info.handleAllWebDataURI
- || (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
- || result.contains(info.activityInfo.packageName)) {
- continue;
- }
- result.add(info.activityInfo.packageName);
- }
-
- return result;
- }
-
private boolean packageIsBrowser(String packageName, int userId) {
List<ResolveInfo> list = queryIntentActivitiesInternal(sBrowserIntent, null,
PackageManager.MATCH_ALL, userId);
final int N = list.size();
for (int i = 0; i < N; i++) {
ResolveInfo info = list.get(i);
- if (packageName.equals(info.activityInfo.packageName)) {
+ if (info.priority >= 0 && packageName.equals(info.activityInfo.packageName)) {
return true;
}
}
return false;
}
- private void checkDefaultBrowser() {
- final int myUserId = UserHandle.myUserId();
- final String packageName = getDefaultBrowserPackageName(myUserId);
- if (packageName != null) {
- PackageInfo info = getPackageInfo(packageName, 0, myUserId);
- if (info == null) {
- Slog.w(TAG, "Default browser no longer installed: " + packageName);
- synchronized (mPackages) {
- applyFactoryDefaultBrowserLPw(myUserId); // leaves ambiguous when > 1
- }
- }
- }
- }
-
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
}
}
- static int[] appendInts(int[] cur, int[] add) {
- if (add == null) return cur;
- if (cur == null) return add;
- final int N = add.length;
- for (int i=0; i<N; i++) {
- cur = appendInt(cur, add[i]);
- }
- return cur;
- }
-
/**
* Returns whether or not a full application can see an instant application.
* <p>
- * Currently, there are three cases in which this can occur:
+ * 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>
* {@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>
*/
private boolean canViewInstantApps(int callingUid, int userId) {
&& isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
return true;
}
+ // TODO(b/122900055) Change/Remove this and replace with new permission role.
+ if (mAppPredictionServicePackage != null
+ && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
+ return true;
+ }
}
return false;
}
if (ps == null) {
return null;
}
- PackageParser.Package p = ps.pkg;
- if (p == null) {
- return null;
- }
final int callingUid = Binder.getCallingUid();
// Filter out ephemeral app metadata:
// * The system/shell/root can see metadata for any app
return null;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- // Compute GIDs only if requested
- final int[] gids = (flags & PackageManager.GET_GIDS) == 0
- ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
- // Compute granted permissions only if package has requested permissions
- final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
- ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
- final PackageUserState state = ps.readUserState(userId);
-
if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
&& ps.isSystem()) {
flags |= MATCH_ANY_USER;
}
- PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
- ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+ final PackageUserState state = ps.readUserState(userId);
+ PackageParser.Package p = ps.pkg;
+ if (p != null) {
+ final PermissionsState permissionsState = ps.getPermissionsState();
+
+ // Compute GIDs only if requested
+ final int[] gids = (flags & PackageManager.GET_GIDS) == 0
+ ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
+ // Compute granted permissions only if package has requested permissions
+ final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+ ? Collections.emptySet() : permissionsState.getPermissions(userId);
- if (packageInfo == null) {
- return null;
- }
+ PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
- packageInfo.packageName = packageInfo.applicationInfo.packageName =
- resolveExternalPackageNameLPr(p);
+ if (packageInfo == null) {
+ return null;
+ }
- return packageInfo;
+ packageInfo.packageName = packageInfo.applicationInfo.packageName =
+ resolveExternalPackageNameLPr(p);
+
+ return packageInfo;
+ } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = ps.name;
+ pi.setLongVersionCode(ps.versionCode);
+ pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
+ pi.firstInstallTime = ps.firstInstallTime;
+ pi.lastUpdateTime = ps.lastUpdateTime;
+
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = ps.name;
+ ai.uid = UserHandle.getUid(userId, ps.appId);
+ ai.primaryCpuAbi = ps.primaryCpuAbiString;
+ ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
+ ai.setVersionCode(ps.versionCode);
+ ai.flags = ps.pkgFlags;
+ ai.privateFlags = ps.pkgPrivateFlags;
+ pi.applicationInfo = PackageParser.generateApplicationInfo(ai, flags, state, userId);
+
+ if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["
+ + ps.name + "]. Provides a minimum info.");
+ return pi;
+ } else {
+ return null;
+ }
}
@Override
public boolean isPackageAvailable(String packageName, int userId) {
if (!sUserManager.exists(userId)) return false;
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "is package available");
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode(), flags, Binder.getCallingUid(), userId);
+ versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
}
/**
* to clearing. Because it can only be provided by trusted code, it's value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
+ private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
if (matchFactoryOnly) {
+ // Instant app filtering for APEX modules is ignored
+ if ((flags & MATCH_APEX) != 0) {
+ return mApexManager.getPackageInfo(packageName,
+ ApexManager.MATCH_FACTORY_PACKAGE);
+ }
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
}
return generatePackageInfo(ps, flags, userId);
}
+ if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
+ return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
+ }
}
return null;
}
private boolean isComponentVisibleToInstantApp(
@Nullable ComponentName component, @ComponentType int type) {
if (type == TYPE_ACTIVITY) {
- final PackageParser.Activity activity = mActivities.mActivities.get(component);
- return activity != null
- ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
- : false;
+ final PackageParser.Activity activity = mComponentResolver.getActivity(component);
+ if (activity == null) {
+ return false;
+ }
+ final boolean visibleToInstantApp =
+ (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ final boolean explicitlyVisibleToInstantApp =
+ (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+ return visibleToInstantApp && explicitlyVisibleToInstantApp;
} else if (type == TYPE_RECEIVER) {
- final PackageParser.Activity activity = mReceivers.mActivities.get(component);
- return activity != null
- ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
- : false;
+ final PackageParser.Activity activity = mComponentResolver.getReceiver(component);
+ if (activity == null) {
+ return false;
+ }
+ final boolean visibleToInstantApp =
+ (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ final boolean explicitlyVisibleToInstantApp =
+ (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+ return visibleToInstantApp && !explicitlyVisibleToInstantApp;
} else if (type == TYPE_SERVICE) {
- final PackageParser.Service service = mServices.mServices.get(component);
+ final PackageParser.Service service = mComponentResolver.getService(component);
return service != null
? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
: false;
} else if (type == TYPE_PROVIDER) {
- final PackageParser.Provider provider = mProviders.mProviders.get(component);
+ final PackageParser.Provider provider = mComponentResolver.getProvider(component);
return provider != null
? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
: false;
* Access may be limited based upon whether the calling or target applications
* are instant applications.
*
- * @see #canAccessInstantApps(int)
+ * @see #canViewInstantApps(int, int)
*/
+ @GuardedBy("mPackages")
private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
return false;
}
if (callerIsInstantApp) {
- // request for a specific component; if it hasn't been explicitly exposed, filter
+ // both caller and target are both instant, but, different applications, filter
+ if (ps.getInstantApp(userId)) {
+ return true;
+ }
+ // request for a specific component; if it hasn't been explicitly exposed through
+ // property or instrumentation target, filter
if (component != null) {
+ final PackageParser.Instrumentation instrumentation =
+ mInstrumentation.get(component);
+ if (instrumentation != null
+ && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) {
+ return false;
+ }
return !isComponentVisibleToInstantApp(component, componentType);
}
// request for application; if no components have been explicitly exposed, filter
- return ps.getInstantApp(userId) || !ps.pkg.visibleToInstantApps;
+ return !ps.pkg.visibleToInstantApps;
}
if (ps.getInstantApp(userId)) {
// caller can see all components of all instant applications, don't filter
}
/**
- * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, boolean, int)
+ * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, int, int)
*/
+ @GuardedBy("mPackages")
private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid, int userId) {
return filterAppAccessLPr(ps, callingUid, null, TYPE_UNKNOWN, userId);
}
+ @GuardedBy("mPackages")
private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags) {
// Callers can access only the libs they depend on, otherwise they need to explicitly
|| appId == Process.ROOT_UID) {
return false;
}
+ // Installer gets to see all static libs.
+ if (PackageManager.PERMISSION_GRANTED
+ == checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) {
+ return false;
+ }
}
// No package means no static lib as it is always on internal storage
return false;
}
- final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(ps.pkg.staticSharedLibName,
+ final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName,
ps.pkg.staticSharedLibVersion);
- if (libEntry == null) {
+ if (libraryInfo == null) {
return false;
}
PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName);
if (uidPs != null) {
final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries,
- libEntry.info.getName());
+ libraryInfo.getName());
if (index < 0) {
continue;
}
- if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) {
+ if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) {
return false;
}
}
if (!sUserManager.exists(userId)) return -1;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid");
// reader
return -1;
}
+ /**
+ * Check if any package sharing/holding a uid has a low enough target SDK.
+ *
+ * @param uid The uid of the packages
+ * @param higherTargetSDK The target SDK that might be higher than the searched package
+ *
+ * @return {@code true} if there is a package sharing/holding the uid with
+ * {@code package.targetSDK < higherTargetSDK}
+ */
+ private boolean hasTargetSdkInUidLowerThan(int uid, int higherTargetSDK) {
+ int userId = UserHandle.getUserId(uid);
+
+ synchronized (mPackages) {
+ Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+ if (obj == null) {
+ return false;
+ }
+
+ if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+
+ if (!ps.getInstalled(userId)) {
+ return false;
+ }
+
+ return ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK;
+ } else if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+
+ final int numPkgs = sus.packages.size();
+ for (int i = 0; i < numPkgs; i++) {
+ final PackageSetting ps = sus.packages.valueAt(i);
+
+ if (!ps.getInstalled(userId)) {
+ continue;
+ }
+
+ if (ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK) {
+ return true;
+ }
+ }
+
+ return false;
+ } else {
+ return false;
+ }
+ }
+ }
+
@Override
public int[] getPackageGids(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getPackageGids");
// reader
return null;
}
- static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
- if (bp.perm != null) {
- return PackageParser.generatePermissionInfo(bp.perm, flags);
- }
- PermissionInfo pi = new PermissionInfo();
- pi.name = bp.name;
- pi.packageName = bp.sourcePackage;
- pi.nonLocalizedLabel = bp.name;
- pi.protectionLevel = bp.protectionLevel;
- return pi;
- }
-
@Override
public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
- synchronized (mPackages) {
- final BasePermission p = mSettings.mPermissions.get(name);
- if (p == null) {
- return null;
- }
- // If the caller is an app that targets pre 26 SDK drop protection flags.
- PermissionInfo permissionInfo = generatePermissionInfo(p, flags);
- if (permissionInfo != null) {
- final int protectionLevel = adjustPermissionProtectionFlagsLPr(
- permissionInfo.protectionLevel, packageName, callingUid);
- if (permissionInfo.protectionLevel != protectionLevel) {
- // If we return different protection level, don't use the cached info
- if (p.perm != null && p.perm.info == permissionInfo) {
- permissionInfo = new PermissionInfo(permissionInfo);
- }
- permissionInfo.protectionLevel = protectionLevel;
- }
- }
- return permissionInfo;
- }
- }
-
- private int adjustPermissionProtectionFlagsLPr(int protectionLevel,
- String packageName, int uid) {
- // Signature permission flags area always reported
- final int protectionLevelMasked = protectionLevel
- & (PermissionInfo.PROTECTION_NORMAL
- | PermissionInfo.PROTECTION_DANGEROUS
- | PermissionInfo.PROTECTION_SIGNATURE);
- if (protectionLevelMasked == PermissionInfo.PROTECTION_SIGNATURE) {
- return protectionLevel;
- }
-
- // System sees all flags.
- final int appId = UserHandle.getAppId(uid);
- if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID
- || appId == Process.SHELL_UID) {
- return protectionLevel;
- }
-
- // Normalize package name to handle renamed packages and static libs
- packageName = resolveInternalPackageNameLPr(packageName,
- PackageManager.VERSION_CODE_HIGHEST);
-
- // Apps that target O see flags for all protection levels.
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- return protectionLevel;
- }
- if (ps.appId != appId) {
- return protectionLevel;
- }
-
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- return protectionLevel;
- }
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
- return protectionLevelMasked;
- }
-
- return protectionLevel;
+ return mPermissionManager.getPermissionInfo(name, packageName, flags, getCallingUid());
}
@Override
- public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group,
+ public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- // reader
- synchronized (mPackages) {
- if (group != null && !mPermissionGroups.containsKey(group)) {
- // This is thrown as NameNotFoundException
- return null;
- }
-
- ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission p : mSettings.mPermissions.values()) {
- if (group == null) {
- if (p.perm == null || p.perm.info.group == null) {
- out.add(generatePermissionInfo(p, flags));
- }
- } else {
- if (p.perm != null && group.equals(p.perm.info.group)) {
- out.add(PackageParser.generatePermissionInfo(p.perm, flags));
- }
- }
- }
- return new ParceledListSlice<>(out);
- }
+ final List<PermissionInfo> permissionList =
+ mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid());
+ return (permissionList == null) ? null : new ParceledListSlice<>(permissionList);
}
@Override
- public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- // reader
- synchronized (mPackages) {
- return PackageParser.generatePermissionGroupInfo(
- mPermissionGroups.get(name), flags);
- }
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+ return mPermissionManager.getPermissionGroupInfo(groupName, flags, getCallingUid());
}
@Override
public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return ParceledListSlice.emptyList();
- }
- // reader
- synchronized (mPackages) {
- final int N = mPermissionGroups.size();
- ArrayList<PermissionGroupInfo> out
- = new ArrayList<PermissionGroupInfo>(N);
- for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
- out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
- }
- return new ParceledListSlice<>(out);
- }
+ final List<PermissionGroupInfo> permissionList =
+ mPermissionManager.getAllPermissionGroups(flags, getCallingUid());
+ return (permissionList == null)
+ ? ParceledListSlice.emptyList() : new ParceledListSlice<>(permissionList);
}
+ @GuardedBy("mPackages")
private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForApplication(flags, userId, packageName);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- false /* requireFullPermission */, false /* checkShell */, "get application info");
+
+ if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ false /* requireFullPermission */, false /* checkShell */,
+ "get application info");
+ }
// writer
synchronized (mPackages) {
return null;
}
+ @GuardedBy("mPackages")
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
@Override
public void deletePreloadsFileCache() {
- if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
- throw new SecurityException("Only system or settings may call 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);
final int[] allUsers = sUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- final SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ final LongSparseArray<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).info;
+ SharedLibraryInfo libInfo = versionedLib.valueAt(j);
// Skip packages that are not static shared libs.
if (!libInfo.isStatic()) {
break;
final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
// Resolve the package name - we use synthetic package names internally
final String internalPackageName = resolveInternalPackageNameLPr(
- declaringPackage.getPackageName(), declaringPackage.getVersionCode());
+ declaringPackage.getPackageName(),
+ declaringPackage.getLongVersionCode());
final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
// Skip unused static shared libs cached less than the min period
// to prevent pruning a lib needed by a subsequently installed package.
if (ps == null || now - ps.lastUpdateTime < maxCachePeriod) {
continue;
}
+
+ if (ps.pkg.isSystem()) {
+ continue;
+ }
+
if (packagesToDelete == null) {
packagesToDelete = new ArrayList<>();
}
packagesToDelete.add(new VersionedPackage(internalPackageName,
- declaringPackage.getVersionCode()));
+ declaringPackage.getLongVersionCode()));
}
}
}
for (int i = 0; i < packageCount; i++) {
final VersionedPackage pkgToDelete = packagesToDelete.get(i);
// Delete the package synchronously (will fail of the lib used for any user).
- if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getVersionCode(),
+ if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
== PackageManager.DELETE_SUCCEEDED) {
if (volume.getUsableSpace() >= neededSpace) {
return mUserManagerInternal;
}
+ private ActivityManagerInternal getActivityManagerInternal() {
+ if (mActivityManagerInternal == null) {
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ }
+ return mActivityManagerInternal;
+ }
+
+ private ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ if (mActivityTaskManagerInternal == null) {
+ mActivityTaskManagerInternal =
+ LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+ return mActivityTaskManagerInternal;
+ }
+
private DeviceIdleController.LocalService getDeviceIdleController() {
if (mDeviceIdleController == null) {
mDeviceIdleController =
return mDeviceIdleController;
}
+ private StorageManagerInternal getStorageManagerInternal() {
+ if (mStorageManagerInternal == null) {
+ mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
+ }
+ return mStorageManagerInternal;
+ }
+
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
private int updateFlagsForPackage(int flags, int userId, Object cookie) {
final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM;
- boolean triaged = true;
- if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
- | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) {
- // Caller is asking for component details, so they'd better be
- // asking for specific encryption matching behavior, or be triaged
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
- }
- if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
// require the permission to be held; the calling uid and given user id referring
// to the same user is not sufficient
- try {
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, true,
- "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
- + Debug.getCallers(5));
- } catch (SecurityException se) {
- // For compatibility reasons, we can't throw a security exception here if we're
- // looking for applications in our own user id. Instead, unset the MATCH_ANY_USER
- // flag and move on.
- if (userId != UserHandle.getCallingUserId()) {
- throw se;
- }
- flags &= ~PackageManager.MATCH_ANY_USER;
- }
+ mPermissionManager.enforceCrossUserPermission(
+ Binder.getCallingUid(), userId, false, false,
+ !isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId),
+ "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
+ + Debug.getCallers(5));
} else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
&& sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
// If the caller wants all packages and has a restricted profile associated with it,
// MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
flags |= PackageManager.MATCH_ANY_USER;
}
- if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
- Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
- + " with flags 0x" + Integer.toHexString(flags), new Throwable());
- }
return updateFlags(flags, userId);
}
* Update given flags when being used to request {@link ComponentInfo}.
*/
private int updateFlagsForComponent(int flags, int userId, Object cookie) {
- if (cookie instanceof Intent) {
- if ((((Intent) cookie).getFlags() & Intent.FLAG_DEBUG_TRIAGED_MISSING) != 0) {
- flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
- }
- }
-
- boolean triaged = true;
- // Caller is asking for component details, so they'd better be
- // asking for specific encryption matching behavior, or be triaged
- if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
- triaged = false;
- }
- if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
- Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
- + " with flags 0x" + Integer.toHexString(flags), new Throwable());
- }
-
return updateFlags(flags, userId);
}
flags |= PackageManager.MATCH_INSTANT;
} else {
final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
- final boolean allowMatchInstant =
- (wantInstantApps
- && Intent.ACTION_VIEW.equals(intent.getAction())
- && hasWebURI(intent))
+ final boolean allowMatchInstant = wantInstantApps
|| (wantMatchInstant && canViewInstantApps(callingUid, userId));
flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
| PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- false /* requireFullPermission */, false /* checkShell */, "get activity info");
+
+ if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ false /* requireFullPermission */, false /* checkShell */, "get activity info");
+ }
+
synchronized (mPackages) {
- PackageParser.Activity a = mActivities.mActivities.get(component);
+ PackageParser.Activity a = mComponentResolver.getActivity(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
return null;
}
- @Override
- public boolean activitySupportsIntent(ComponentName component, Intent intent,
- String resolvedType) {
- synchronized (mPackages) {
- if (component.equals(mResolveComponentName)) {
- // The resolver supports EVERYTHING!
- return true;
- }
- final int callingUid = Binder.getCallingUid();
+ private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
+ if (!getActivityTaskManagerInternal().isCallerRecents(callingUid)) {
+ return false;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (ActivityManager.getCurrentUser() != callingUserId) {
+ return false;
+ }
+ return sUserManager.isSameProfileGroup(callingUserId, targetUserId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public boolean activitySupportsIntent(ComponentName component, Intent intent,
+ String resolvedType) {
+ synchronized (mPackages) {
+ if (component.equals(mResolveComponentName)) {
+ // The resolver supports EVERYTHING!
+ return true;
+ }
+ final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- PackageParser.Activity a = mActivities.mActivities.get(component);
+ PackageParser.Activity a = mComponentResolver.getActivity(component);
if (a == null) {
return false;
}
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get receiver info");
synchronized (mPackages) {
- PackageParser.Activity a = mReceivers.mActivities.get(component);
+ PackageParser.Activity a = mComponentResolver.getReceiver(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId,
false /* throwIfPermNotDeclared*/)
|| mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES)
- == PERMISSION_GRANTED;
+ == PERMISSION_GRANTED
+ || mContext.checkCallingOrSelfPermission(
+ Manifest.permission.ACCESS_SHARED_LIBRARIES) == PERMISSION_GRANTED;
synchronized (mPackages) {
List<SharedLibraryInfo> result = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<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).info;
+ SharedLibraryInfo libInfo = versionedLib.valueAt(j);
if (!canSeeStaticLibraries && libInfo.isStatic()) {
break;
}
Binder.restoreCallingIdentity(identity);
}
- SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(),
- libInfo.getVersion(), libInfo.getType(),
- libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo,
- flags, userId));
+ SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
+ libInfo.getPackageName(), libInfo.getAllCodePaths(),
+ libInfo.getName(), libInfo.getLongVersion(),
+ libInfo.getType(), libInfo.getDeclaringPackage(),
+ getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+ (libInfo.getDependencies() == null
+ ? null
+ : new ArrayList<>(libInfo.getDependencies())));
if (result == null) {
result = new ArrayList<>();
}
}
+ @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();
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getDeclaredSharedLibraries");
+
+ Preconditions.checkNotNull(packageName, "packageName cannot be null");
+ Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
+ if (!sUserManager.exists(userId)) {
+ return null;
+ }
+
+ if (getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+
+ synchronized (mPackages) {
+ List<SharedLibraryInfo> result = null;
+
+ int libraryCount = mSharedLibraries.size();
+ for (int i = 0; i < libraryCount; i++) {
+ LongSparseArray<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;
+ }
+
+ 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, userId), libraryInfo.getDependencies() == null
+ ? null : new ArrayList<>(libraryInfo.getDependencies()));
+
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ result.add(resultLibraryInfo);
+ }
+ }
+
+ return result != null ? new ParceledListSlice<>(result) : null;
+ }
+ }
+
+ @GuardedBy("mPackages")
private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
SharedLibraryInfo libInfo, int flags, int userId) {
List<VersionedPackage> versionedPackages = null;
continue;
}
- if (!ps.getUserState().get(userId).isAvailable(flags)) {
+ if (!ps.readUserState(userId).isAvailable(flags)) {
continue;
}
if (libIdx < 0) {
continue;
}
- if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) {
+ if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
continue;
}
if (versionedPackages == null) {
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get service info");
synchronized (mPackages) {
- PackageParser.Service s = mServices.mServices.get(component);
+ PackageParser.Service s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get provider info");
synchronized (mPackages) {
- PackageParser.Provider p = mProviders.mProviders.get(component);
+ PackageParser.Provider p = mComponentResolver.getProvider(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getProviderInfo " + component + ": " + p);
if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
}
@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 (mPackages) {
Set<String> libs = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int j = 0; j < versionCount; j++) {
- SharedLibraryEntry libEntry = versionedLib.valueAt(j);
- if (!libEntry.info.isStatic()) {
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
+ if (!libraryInfo.isStatic()) {
if (libs == null) {
libs = new ArraySet<>();
}
- libs.add(libEntry.info.getName());
+ libs.add(libraryInfo.getName());
break;
}
- PackageSetting ps = mSettings.getPackageLPr(libEntry.apk);
+ 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(libEntry.info.getName());
+ libs.add(libraryInfo.getName());
break;
}
}
}
}
+ @GuardedBy("mPackages")
private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
@Override
public int checkPermission(String permName, String pkgName, int userId) {
- if (!sUserManager.exists(userId)) {
- return PackageManager.PERMISSION_DENIED;
- }
- final int callingUid = Binder.getCallingUid();
-
+ final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mPackages) {
- final PackageParser.Package p = mPackages.get(pkgName);
- if (p != null && p.mExtras != null) {
- final PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, userId)) {
- return PackageManager.PERMISSION_DENIED;
- }
- final boolean instantApp = ps.getInstantApp(userId);
- final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(permName, userId)) {
- if (instantApp) {
- BasePermission bp = mSettings.mPermissions.get(permName);
- if (bp != null && bp.isInstant()) {
- return PackageManager.PERMISSION_GRANTED;
- }
- } else {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
- if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
- .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
- return PackageManager.PERMISSION_GRANTED;
- }
+ if (mCheckPermissionDelegate == null) {
+ return checkPermissionImpl(permName, pkgName, userId);
}
+ checkPermissionDelegate = mCheckPermissionDelegate;
}
+ return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
+ PackageManagerService.this::checkPermissionImpl);
+ }
- return PackageManager.PERMISSION_DENIED;
+ private int checkPermissionImpl(String permName, String pkgName, int userId) {
+ return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId);
}
@Override
public int checkUidPermission(String permName, int uid) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
- final boolean isUidInstantApp = getInstantAppPackageName(uid) != null;
- final int userId = UserHandle.getUserId(uid);
- if (!sUserManager.exists(userId)) {
- return PackageManager.PERMISSION_DENIED;
+ final CheckPermissionDelegate checkPermissionDelegate;
+ synchronized (mPackages) {
+ if (mCheckPermissionDelegate == null) {
+ return checkUidPermissionImpl(permName, uid);
+ }
+ checkPermissionDelegate = mCheckPermissionDelegate;
}
+ return checkPermissionDelegate.checkUidPermission(permName, uid,
+ PackageManagerService.this::checkUidPermissionImpl);
+ }
+ private int checkUidPermissionImpl(String permName, int uid) {
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
- if (obj != null) {
- if (obj instanceof SharedUserSetting) {
- if (isCallerInstantApp) {
- return PackageManager.PERMISSION_DENIED;
- }
- } else if (obj instanceof PackageSetting) {
- final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
- return PackageManager.PERMISSION_DENIED;
- }
- }
- final SettingBase settingBase = (SettingBase) obj;
- final PermissionsState permissionsState = settingBase.getPermissionsState();
- if (permissionsState.hasPermission(permName, userId)) {
- if (isUidInstantApp) {
- BasePermission bp = mSettings.mPermissions.get(permName);
- if (bp != null && bp.isInstant()) {
- return PackageManager.PERMISSION_GRANTED;
- }
- } else {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
- if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
- .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
- return PackageManager.PERMISSION_GRANTED;
- }
- } else {
- ArraySet<String> perms = mSystemPermissions.get(uid);
- if (perms != null) {
- if (perms.contains(permName)) {
- return PackageManager.PERMISSION_GRANTED;
- }
- if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
- .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
+ final String[] packageNames = getPackagesForUid(uid);
+ PackageParser.Package pkg = null;
+ final int N = packageNames == null ? 0 : packageNames.length;
+ for (int i = 0; pkg == null && i < N; i++) {
+ pkg = mPackages.get(packageNames[i]);
}
+ return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
}
-
- return PackageManager.PERMISSION_DENIED;
}
@Override
@Override
public String getPermissionControllerPackageName() {
synchronized (mPackages) {
- return mRequiredInstallerPackage;
+ return mRequiredPermissionControllerPackage;
}
}
- /**
- * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
- * or INTERACT_ACROSS_USERS_FULL permissions, if the 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, int userId, boolean requireFullPermission,
- boolean checkShell, String message) {
- enforceCrossUserPermission(
- callingUid,
- userId,
- requireFullPermission,
- checkShell,
- false,
- message);
- }
-
- private void enforceCrossUserPermission(int callingUid, int userId,
- boolean requireFullPermission, boolean checkShell,
- boolean requirePermissionWhenSameUser, String message) {
- if (userId < 0) {
- throw new IllegalArgumentException("Invalid userId " + userId);
- }
- if (checkShell) {
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- if (!requirePermissionWhenSameUser && userId == UserHandle.getUserId(callingUid)) return;
- if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
- if (requireFullPermission) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- } else {
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- } catch (SecurityException se) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS, message);
- }
- }
+ String getPackageInstallerPackageName() {
+ synchronized (mPackages) {
+ return mRequiredInstallerPackage;
}
}
- void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
- if (callingUid == Process.SHELL_UID) {
- if (userHandle >= 0
- && sUserManager.hasUserRestriction(restriction, userHandle)) {
- throw new SecurityException("Shell does not have permission to access user "
- + userHandle);
- } else if (userHandle < 0) {
- Slog.e(TAG, "Unable to check shell permission for user " + userHandle + "\n\t"
- + Debug.getCallers(3));
- }
- }
+ private boolean addDynamicPermission(PermissionInfo info, final boolean async) {
+ return mPermissionManager.addDynamicPermission(
+ info, async, getCallingUid(), new PermissionCallback() {
+ @Override
+ public void onPermissionChanged() {
+ if (!async) {
+ mSettings.writeLPr();
+ } else {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ });
}
- private BasePermission findPermissionTreeLP(String permName) {
- for(BasePermission bp : mSettings.mPermissionTrees.values()) {
- if (permName.startsWith(bp.name) &&
- permName.length() > bp.name.length() &&
- permName.charAt(bp.name.length()) == '.') {
- return bp;
- }
+ @Override
+ public boolean addPermission(PermissionInfo info) {
+ synchronized (mPackages) {
+ return addDynamicPermission(info, false);
}
- return null;
}
- private BasePermission checkPermissionTreeLP(String permName) {
- if (permName != null) {
- BasePermission bp = findPermissionTreeLP(permName);
- if (bp != null) {
- if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
- return bp;
- }
- throw new SecurityException("Calling uid "
- + Binder.getCallingUid()
- + " is not allowed to add to permission tree "
- + bp.name + " owned by uid " + bp.uid);
- }
+ @Override
+ public boolean addPermissionAsync(PermissionInfo info) {
+ synchronized (mPackages) {
+ return addDynamicPermission(info, true);
}
- throw new SecurityException("No permission tree found for " + permName);
}
- static boolean compareStrings(CharSequence s1, CharSequence s2) {
- if (s1 == null) {
- return s2 == null;
- }
- if (s2 == null) {
- return false;
- }
- if (s1.getClass() != s2.getClass()) {
- return false;
- }
- return s1.equals(s2);
- }
-
- static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
- if (pi1.icon != pi2.icon) return false;
- if (pi1.logo != pi2.logo) return false;
- if (pi1.protectionLevel != pi2.protectionLevel) return false;
- if (!compareStrings(pi1.name, pi2.name)) return false;
- if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
- // We'll take care of setting this one.
- if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
- // These are not currently stored in settings.
- //if (!compareStrings(pi1.group, pi2.group)) return false;
- //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
- //if (pi1.labelRes != pi2.labelRes) return false;
- //if (pi1.descriptionRes != pi2.descriptionRes) return false;
- return true;
+ @Override
+ public void removePermission(String permName) {
+ mPermissionManager.removeDynamicPermission(permName, getCallingUid(), mPermissionCallback);
}
- int permissionInfoFootprint(PermissionInfo info) {
- int size = info.name.length();
- if (info.nonLocalizedLabel != null) size += info.nonLocalizedLabel.length();
- if (info.nonLocalizedDescription != null) size += info.nonLocalizedDescription.length();
- return size;
- }
+ @Override
+ public void grantRuntimePermission(String packageName, String permName, final int userId) {
+ boolean overridePolicy = (checkUidPermission(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED);
- int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
- int size = 0;
- for (BasePermission perm : mSettings.mPermissions.values()) {
- if (perm.uid == tree.uid) {
- size += perm.name.length() + permissionInfoFootprint(perm.perm.info);
- }
- }
- return size;
+ mPermissionManager.grantRuntimePermission(permName, packageName, overridePolicy,
+ getCallingUid(), userId, mPermissionCallback);
}
- void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
- // We calculate the max size of permissions defined by this uid and throw
- // if that plus the size of 'info' would exceed our stated maximum.
- if (tree.uid != Process.SYSTEM_UID) {
- final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
- if (curTreeSize + permissionInfoFootprint(info) > MAX_PERMISSION_TREE_FOOTPRINT) {
- throw new SecurityException("Permission tree size cap exceeded");
- }
- }
- }
+ @Override
+ public void revokeRuntimePermission(String packageName, String permName, int userId) {
+ boolean overridePolicy = (checkUidPermission(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
+ == PackageManager.PERMISSION_GRANTED);
- boolean addPermissionLocked(PermissionInfo info, boolean async) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant apps can't add permissions");
- }
- if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
- throw new SecurityException("Label must be specified in permission");
- }
- BasePermission tree = checkPermissionTreeLP(info.name);
- BasePermission bp = mSettings.mPermissions.get(info.name);
- boolean added = bp == null;
- boolean changed = true;
- int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
- if (added) {
- enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.sourcePackage,
- BasePermission.TYPE_DYNAMIC);
- } else if (bp.type != BasePermission.TYPE_DYNAMIC) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
- + info.name);
- } else {
- if (bp.protectionLevel == fixedLevel
- && bp.perm.owner.equals(tree.perm.owner)
- && bp.uid == tree.uid
- && comparePermissionInfos(bp.perm.info, info)) {
- changed = false;
- }
- }
- bp.protectionLevel = fixedLevel;
- info = new PermissionInfo(info);
- info.protectionLevel = fixedLevel;
- bp.perm = new PackageParser.Permission(tree.perm.owner, info);
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.uid = tree.uid;
- if (added) {
- mSettings.mPermissions.put(info.name, bp);
- }
- if (changed) {
- if (!async) {
- mSettings.writeLPr();
- } else {
- scheduleWriteSettingsLocked();
- }
- }
- return added;
+ mPermissionManager.revokeRuntimePermission(permName, packageName, overridePolicy,
+ userId, mPermissionCallback);
}
@Override
- public boolean addPermission(PermissionInfo info) {
+ public void resetRuntimePermissions() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+ "revokeRuntimePermission");
+
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "resetRuntimePermissions");
+ }
+
synchronized (mPackages) {
- return addPermissionLocked(info, false);
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
+ mPermissionCallback);
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int packageCount = mPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ PackageParser.Package pkg = mPackages.valueAt(i);
+ if (!(pkg.mExtras instanceof PackageSetting)) {
+ continue;
+ }
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, userId);
+ }
+ }
}
}
@Override
- public boolean addPermissionAsync(PermissionInfo info) {
- synchronized (mPackages) {
- return addPermissionLocked(info, true);
- }
+ public int getPermissionFlags(String permName, String packageName, int userId) {
+ return mPermissionManager.getPermissionFlags(
+ permName, packageName, getCallingUid(), userId);
}
@Override
- public void removePermission(String name) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- synchronized (mPackages) {
- checkPermissionTreeLP(name);
- BasePermission bp = mSettings.mPermissions.get(name);
- if (bp != null) {
- if (bp.type != BasePermission.TYPE_DYNAMIC) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
- + name);
+ public void updatePermissionFlags(String permName, String packageName, int flagMask,
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+ int callingUid = getCallingUid();
+ boolean overridePolicy = false;
+
+ if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ if (checkAdjustPolicyFlagPermission) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+ "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+ + " to change policy flags");
+ } else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) {
+ throw new IllegalArgumentException(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
+ + " to be checked for packages targeting "
+ + Build.VERSION_CODES.Q + " or later when changing policy "
+ + "flags");
+ }
+
+ overridePolicy = true;
}
- mSettings.mPermissions.remove(name);
- mSettings.writeLPr();
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
}
}
+
+ mPermissionManager.updatePermissionFlags(
+ permName, packageName, flagMask, flagValues, callingUid, userId,
+ overridePolicy, mPermissionCallback);
}
- private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(
- PackageParser.Package pkg, BasePermission bp) {
- int index = pkg.requestedPermissions.indexOf(bp.name);
- if (index == -1) {
- throw new SecurityException("Package " + pkg.packageName
- + " has not requested permission " + bp.name);
- }
- if (!bp.isRuntime() && !bp.isDevelopment()) {
- throw new SecurityException("Permission " + bp.name
- + " is not a changeable permission type");
+ /**
+ * Update the permission flags for all packages and runtime permissions of a user in order
+ * to allow device or profile owner to remove POLICY_FIXED.
+ */
+ @Override
+ public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
+ synchronized (mPackages) {
+ final boolean changed = mPermissionManager.updatePermissionFlagsForAllApps(
+ flagMask, flagValues, getCallingUid(), userId, mPackages.values(),
+ mPermissionCallback);
+ if (changed) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
}
}
@Override
- public void grantRuntimePermission(String packageName, String name, final int userId) {
- grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
- }
+ public @Nullable List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
+ @PermissionWhitelistFlags int whitelistFlags, @UserIdInt int userId) {
+ Preconditions.checkNotNull(packageName);
+ Preconditions.checkFlagsArgument(whitelistFlags,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ Preconditions.checkArgumentNonNegative(userId, null);
- private void grantRuntimePermission(String packageName, String name, final int userId,
- boolean overridePolicy) {
- if (!sUserManager.exists(userId)) {
- Log.e(TAG, "No such user:" + userId);
- return;
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ "getWhitelistedRestrictedPermissions for user " + userId);
}
- final int callingUid = Binder.getCallingUid();
-
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
- "grantRuntimePermission");
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "grantRuntimePermission");
-
- final int uid;
- final PackageSetting ps;
+ final PackageParser.Package pkg;
synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
- ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
-
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
-
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (mPermissionReviewRequired
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && bp.isRuntime()) {
- return;
+ final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ if (packageSetting == null) {
+ Slog.w(TAG, "Unknown package: " + packageName);
+ return null;
}
- uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
+ pkg = packageSetting.pkg;
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+ == PackageManager.PERMISSION_GRANTED;
+ final PackageSetting installerPackageSetting = mSettings.mPackages.get(
+ packageSetting.installerPackageName);
+ final boolean isCallerInstallerOnRecord = installerPackageSetting != null
+ && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
- final int flags = permissionsState.getPermissionFlags(name, userId);
- if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot grant system fixed permission "
- + name + " for package " + packageName);
- }
- if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- throw new SecurityException("Cannot grant policy fixed permission "
- + name + " for package " + packageName);
+ if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+ && !isCallerPrivileged) {
+ throw new SecurityException("Querying system whitelist requires "
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
- if (bp.isDevelopment()) {
- // Development permissions must be handled specially, since they are not
- // normal runtime permissions. For now they apply to all users.
- if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- scheduleWriteSettingsLocked();
+ if ((whitelistFlags & (PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) != 0) {
+ if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+ throw new SecurityException("Querying upgrade or installer whitelist"
+ + " requires being installer on record or "
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
- return;
}
- if (ps.getInstantApp(userId) && !bp.isInstant()) {
- throw new SecurityException("Cannot grant non-ephemeral permission"
- + name + " for package " + packageName);
+ if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
+ UserHandle.getCallingUserId())) {
+ return null;
}
+ }
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
- return;
- }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mPermissionManager.getWhitelistedRestrictedPermissions(
+ pkg, whitelistFlags, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
- final int result = permissionsState.grantRuntimePermission(bp, userId);
- switch (result) {
- case PermissionsState.PERMISSION_OPERATION_FAILURE: {
- return;
- }
-
- case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
- final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
- }
- });
- }
- break;
- }
-
- if (bp.isRuntime()) {
- logPermissionGranted(mContext, name, packageName);
- }
-
- mOnPermissionChangeListeners.onPermissionsChanged(uid);
+ @Override
+ public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+ @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
+ @UserIdInt int userId) {
+ // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+ Preconditions.checkNotNull(permission);
- // Not critical if that is lost - app has to request again.
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
+ return false;
}
- // Only need to do this if user is initialized. Otherwise it's a new user
- // and there are no processes running as the user yet and there's no need
- // to make an expensive call to remount processes for the changed permissions.
- if (READ_EXTERNAL_STORAGE.equals(name)
- || WRITE_EXTERNAL_STORAGE.equals(name)) {
- final long token = Binder.clearCallingIdentity();
- try {
- if (sUserManager.isInitialized(userId)) {
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
+ whitelistFlags, userId);
+ if (permissions == null) {
+ permissions = new ArrayList<>(1);
}
- }
-
- @Override
- public void revokeRuntimePermission(String packageName, String name, int userId) {
- revokeRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
- }
-
- private void revokeRuntimePermission(String packageName, String name, int userId,
- boolean overridePolicy) {
- if (!sUserManager.exists(userId)) {
- Log.e(TAG, "No such user:" + userId);
- return;
+ if (permissions.indexOf(permission) < 0) {
+ permissions.add(permission);
+ return setWhitelistedRestrictedPermissions(packageName, permissions,
+ whitelistFlags, userId);
}
+ return false;
+ }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- "revokeRuntimePermission");
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- true /* requireFullPermission */, true /* checkShell */,
- "revokeRuntimePermission");
-
- final int appId;
-
+ private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(
+ @NonNull String permission) {
synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
+ final BasePermission bp = mPermissionManager.getPermissionTEMP(permission);
if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
-
- enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
-
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (mPermissionReviewRequired
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && bp.isRuntime()) {
- return;
- }
-
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- final int flags = permissionsState.getPermissionFlags(name, userId);
- if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot revoke system fixed permission "
- + name + " for package " + packageName);
- }
- if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- throw new SecurityException("Cannot revoke policy fixed permission "
- + name + " for package " + packageName);
- }
-
- if (bp.isDevelopment()) {
- // Development permissions must be handled specially, since they are not
- // normal runtime permissions. For now they apply to all users.
- if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- scheduleWriteSettingsLocked();
- }
- return;
- }
-
- if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- return;
- }
-
- if (bp.isRuntime()) {
- logPermissionRevoked(mContext, name, packageName);
- }
-
- mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
-
- // Critical, after this call app should never have the permission.
- mSettings.writeRuntimePermissionsForUserLPr(userId, true);
-
- appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- }
-
- killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
- }
-
- /**
- * We might auto-grant permissions if any permission of the group is already granted. Hence if
- * the group of a granted permission changes we need to revoke it to avoid having permissions of
- * the new group auto-granted.
- *
- * @param newPackage The new package that was installed
- * @param oldPackage The old package that was updated
- * @param allPackageNames All package names
- */
- private void revokeRuntimePermissionsIfGroupChanged(
- PackageParser.Package newPackage,
- PackageParser.Package oldPackage,
- ArrayList<String> allPackageNames) {
- final int numOldPackagePermissions = oldPackage.permissions.size();
- final ArrayMap<String, String> oldPermissionNameToGroupName
- = new ArrayMap<>(numOldPackagePermissions);
-
- for (int i = 0; i < numOldPackagePermissions; i++) {
- final PackageParser.Permission permission = oldPackage.permissions.get(i);
-
- if (permission.group != null) {
- oldPermissionNameToGroupName.put(permission.info.name,
- permission.group.info.name);
- }
- }
-
- final int numNewPackagePermissions = newPackage.permissions.size();
- for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
- newPermissionNum++) {
- final PackageParser.Permission newPermission =
- newPackage.permissions.get(newPermissionNum);
- final int newProtection = newPermission.info.protectionLevel;
-
- if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
- final String permissionName = newPermission.info.name;
- final String newPermissionGroupName =
- newPermission.group == null ? null : newPermission.group.info.name;
- final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
- permissionName);
-
- if (newPermissionGroupName != null
- && !newPermissionGroupName.equals(oldPermissionGroupName)) {
- final List<UserInfo> users = mContext.getSystemService(UserManager.class)
- .getUsers();
-
- final int numUsers = users.size();
- for (int userNum = 0; userNum < numUsers; userNum++) {
- final int userId = users.get(userNum).id;
- final int numPackages = allPackageNames.size();
-
- for (int packageNum = 0; packageNum < numPackages; packageNum++) {
- final String packageName = allPackageNames.get(packageNum);
-
- if (checkPermission(permissionName, packageName, userId)
- == PackageManager.PERMISSION_GRANTED) {
- EventLog.writeEvent(0x534e4554, "72710897",
- newPackage.applicationInfo.uid,
- "Revoking permission", permissionName, "from package",
- packageName, "as the group changed from",
- oldPermissionGroupName, "to", newPermissionGroupName);
-
- try {
- revokeRuntimePermission(packageName, permissionName, userId,
- false);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Could not revoke " + permissionName + " from "
- + packageName, e);
- }
- }
- }
- }
- }
+ Slog.w(TAG, "No such permissions: " + permission);
+ return false;
}
- }
- }
-
-
- /**
- * Get the first event id for the permission.
- *
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
- * @param name name of the permission
- *
- * @return The first event id for the permission
- */
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
-
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
+ if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted()
+ && mContext.checkCallingOrSelfPermission(
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot modify whitelisting of an immutably "
+ + "restricted permission: " + permission);
}
+ return true;
}
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
}
@Override
- public void resetRuntimePermissions() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- "revokeRuntimePermission");
+ public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+ @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
+ @UserIdInt int userId) {
+ // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+ Preconditions.checkNotNull(permission);
- int callingUid = Binder.getCallingUid();
- if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "resetRuntimePermissions");
+ if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
+ return false;
}
- synchronized (mPackages) {
- updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int packageCount = mPackages.size();
- for (int i = 0; i < packageCount; i++) {
- PackageParser.Package pkg = mPackages.valueAt(i);
- if (!(pkg.mExtras instanceof PackageSetting)) {
- continue;
- }
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, userId);
- }
- }
+ final List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
+ whitelistFlags, userId);
+ if (permissions != null && permissions.remove(permission)) {
+ return setWhitelistedRestrictedPermissions(packageName, permissions,
+ whitelistFlags, userId);
}
+ return false;
}
- @Override
- public int getPermissionFlags(String name, String packageName, int userId) {
- if (!sUserManager.exists(userId)) {
- return 0;
- }
-
- enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, false /* checkShell */,
- "getPermissionFlags");
-
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- return 0;
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- return 0;
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- return 0;
- }
- PermissionsState permissionsState = ps.getPermissionsState();
- return permissionsState.getPermissionFlags(name, userId);
- }
- }
+ private boolean setWhitelistedRestrictedPermissions(@NonNull String packageName,
+ @Nullable List<String> permissions, @PermissionWhitelistFlags int whitelistFlag,
+ @UserIdInt int userId) {
+ Preconditions.checkNotNull(packageName);
+ Preconditions.checkFlagsArgument(whitelistFlag,
+ PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+ | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+ Preconditions.checkArgument(Integer.bitCount(whitelistFlag) == 1);
+ Preconditions.checkArgumentNonNegative(userId, null);
- @Override
- public void updatePermissionFlags(String name, String packageName, int flagMask,
- int flagValues, int userId) {
- if (!sUserManager.exists(userId)) {
- return;
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "setWhitelistedRestrictedPermissions for user " + userId);
}
- enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "updatePermissionFlags");
-
- // Only the system can change these flags and nothing else.
- if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- }
+ final PackageParser.Package pkg;
synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
+ final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ if (packageSetting == null) {
+ Slog.w(TAG, "Unknown package: " + packageName);
+ return false;
}
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
+ pkg = packageSetting.pkg;
- PermissionsState permissionsState = ps.getPermissionsState();
+ final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+ == PackageManager.PERMISSION_GRANTED;
+ final PackageSetting installerPackageSetting = mSettings.mPackages.get(
+ packageSetting.installerPackageName);
+ final boolean isCallerInstallerOnRecord = installerPackageSetting != null
+ && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
- boolean hadState = permissionsState.getRuntimePermissionState(name, userId) != null;
+ if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+ && !isCallerPrivileged) {
+ throw new SecurityException("Modifying system whitelist requires "
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+ }
- if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) {
- // Install and runtime permissions are stored in different places,
- // so figure out what permission changed and persist the change.
- if (permissionsState.getInstallPermissionState(name) != null) {
- scheduleWriteSettingsLocked();
- } else if (permissionsState.getRuntimePermissionState(name, userId) != null
- || hadState) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+ if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+ throw new SecurityException("Modifying upgrade whitelist requires"
+ + " being installer on record or "
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+ }
+ final List<String> whitelistedPermissions = getWhitelistedRestrictedPermissions(
+ packageName, whitelistFlag, userId);
+ if (permissions == null || permissions.isEmpty()) {
+ if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
+ return true;
+ }
+ } else {
+ // Only the system can add and remove while the installer can only remove.
+ final int permissionCount = permissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ if ((whitelistedPermissions == null
+ || !whitelistedPermissions.contains(permissions.get(i)))
+ && !isCallerPrivileged) {
+ throw new SecurityException("Adding to upgrade whitelist requires"
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+ }
+ }
}
}
- }
- }
-
- /**
- * Update the permission flags for all packages and runtime permissions of a user in order
- * to allow device or profile owner to remove POLICY_FIXED.
- */
- @Override
- public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
- if (!sUserManager.exists(userId)) {
- return;
- }
-
- enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlagsForAllApps");
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- true /* requireFullPermission */, true /* checkShell */,
- "updatePermissionFlagsForAllApps");
-
- // Only the system can change system fixed flags.
- if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- }
- synchronized (mPackages) {
- boolean changed = false;
- final int packageCount = mPackages.size();
- for (int pkgIndex = 0; pkgIndex < packageCount; pkgIndex++) {
- final PackageParser.Package pkg = mPackages.valueAt(pkgIndex);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- continue;
+ if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+ if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+ throw new SecurityException("Modifying installer whitelist requires"
+ + " being installer on record or "
+ + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
- PermissionsState permissionsState = ps.getPermissionsState();
- changed |= permissionsState.updatePermissionFlagsForAllPermissions(
- userId, flagMask, flagValues);
}
- if (changed) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+
+ if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
+ UserHandle.getCallingUserId())) {
+ return false;
}
}
- }
- private void enforceGrantRevokeRuntimePermissionPermissions(String message) {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
- != PackageManager.PERMISSION_GRANTED
- && mContext.checkCallingOrSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(message + " requires "
- + Manifest.permission.GRANT_RUNTIME_PERMISSIONS + " or "
- + Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mPermissionManager.setWhitelistedRestrictedPermissions(pkg,
+ new int[]{userId}, permissions, Process.myUid(), whitelistFlag,
+ mPermissionCallback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
+
+ return true;
}
@Override
|| filterAppAccessLPr(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return compareSignatures(p1.mSignatures, p2.mSignatures);
+ return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
}
}
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
// Map to base uids.
- uid1 = UserHandle.getAppId(uid1);
- uid2 = UserHandle.getAppId(uid2);
+ final int appId1 = UserHandle.getAppId(uid1);
+ final int appId2 = UserHandle.getAppId(uid2);
// reader
synchronized (mPackages) {
Signature[] s1;
Signature[] s2;
- Object obj = mSettings.getUserIdLPr(uid1);
+ Object obj = mSettings.getSettingLPr(appId1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ((SharedUserSetting)obj).signatures.mSignatures;
+ s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s1 = ps.signatures.mSignatures;
+ s1 = ps.signatures.mSigningDetails.signatures;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- obj = mSettings.getUserIdLPr(uid2);
+ obj = mSettings.getSettingLPr(appId2);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ((SharedUserSetting)obj).signatures.mSignatures;
+ s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- s2 = ps.signatures.mSignatures;
+ s2 = ps.signatures.mSigningDetails.signatures;
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
}
}
- /**
- * This method should typically only be used when granting or revoking
- * permissions, since the app may immediately restart after this call.
- * <p>
- * If you're doing surgery on app code/data, use {@link PackageFreezer} to
- * guard your work against the app being relaunched.
- */
- private void killUid(int appId, int userId, String reason) {
- final long identity = Binder.clearCallingIdentity();
- try {
- IActivityManager am = ActivityManager.getService();
- if (am != null) {
- try {
- am.killUid(appId, userId, reason);
- } catch (RemoteException e) {
- /* ignore - same process */
- }
+ @Override
+ public boolean hasSigningCertificate(
+ String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
+
+ synchronized (mPackages) {
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p == null || p.mExtras == null) {
+ return false;
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ return false;
+ }
+ switch (type) {
+ case CERT_INPUT_RAW_X509:
+ return p.mSigningDetails.hasCertificate(certificate);
+ case CERT_INPUT_SHA256:
+ return p.mSigningDetails.hasSha256Certificate(certificate);
+ default:
+ return false;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
- /**
- * Compares two sets of signatures. Returns:
- * <br />
- * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
- * <br />
- * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
- * <br />
- * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
- */
- static int compareSignatures(Signature[] s1, Signature[] s2) {
- if (s1 == null) {
- return s2 == null
- ? PackageManager.SIGNATURE_NEITHER_SIGNED
- : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
- }
-
- if (s2 == null) {
- return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
- }
-
- if (s1.length != s2.length) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- // Since both signature sets are of size 1, we can compare without HashSets.
- if (s1.length == 1) {
- return s1[0].equals(s2[0]) ?
- PackageManager.SIGNATURE_MATCH :
- PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> set1 = new ArraySet<Signature>();
- for (Signature sig : s1) {
- set1.add(sig);
- }
- ArraySet<Signature> set2 = new ArraySet<Signature>();
- for (Signature sig : s2) {
- set2.add(sig);
- }
- // Make sure s2 contains all signatures in s1.
- if (set1.equals(set2)) {
- return PackageManager.SIGNATURE_MATCH;
+ @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 (mPackages) {
+ final PackageParser.SigningDetails signingDetails;
+ final Object obj = mSettings.getSettingLPr(appId);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
+ if (isCallerInstantApp) {
+ return false;
+ }
+ signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ return false;
+ }
+ signingDetails = ps.signatures.mSigningDetails;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ switch (type) {
+ case CERT_INPUT_RAW_X509:
+ return signingDetails.hasCertificate(certificate);
+ case CERT_INPUT_SHA256:
+ return signingDetails.hasSha256Certificate(certificate);
+ default:
+ return false;
+ }
+ }
+ }
+
+ /**
+ * This method should typically only be used when granting or revoking
+ * permissions, since the app may immediately restart after this call.
+ * <p>
+ * If you're doing surgery on app code/data, use {@link PackageFreezer} to
+ * guard your work against the app being relaunched.
+ */
+ private void killUid(int appId, int userId, String reason) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ IActivityManager am = ActivityManager.getService();
+ if (am != null) {
+ try {
+ am.killUid(appId, userId, reason);
+ } catch (RemoteException e) {
+ /* ignore - same process */
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return PackageManager.SIGNATURE_NO_MATCH;
}
/**
* were updated, return true.
*/
private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
- final VersionInfo ver = getSettingsVersionForPackage(scannedPkg);
- return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
+ return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
}
- /**
- * Used for backward compatibility to make sure any packages with
- * certificate chains get upgraded to the new style. {@code existingSigs}
- * will be in the old format (since they were stored on disk from before the
- * system upgrade) and {@code scannedSigs} will be in the newer format.
- */
- private int compareSignaturesCompat(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isCompatSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> existingSet = new ArraySet<Signature>();
- for (Signature sig : existingSigs.mSignatures) {
- existingSet.add(sig);
- }
- ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
- for (Signature sig : scannedPkg.mSignatures) {
- try {
- Signature[] chainSignatures = sig.getChainSignatures();
- for (Signature chainSig : chainSignatures) {
- scannedCompatSet.add(chainSig);
- }
- } catch (CertificateEncodingException e) {
- scannedCompatSet.add(sig);
- }
- }
- /*
- * Make sure the expanded scanned set contains all signatures in the
- * existing one.
- */
- if (scannedCompatSet.equals(existingSet)) {
- // Migrate the old signatures to the new scheme.
- existingSigs.assignSignatures(scannedPkg.mSignatures);
- // The new KeySets will be re-added later in the scanning process.
- synchronized (mPackages) {
- mSettings.mKeySetManagerService.removeAppKeySetDataLPw(scannedPkg.packageName);
- }
- return PackageManager.SIGNATURE_MATCH;
- }
- return PackageManager.SIGNATURE_NO_MATCH;
+ private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
+ return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
- final VersionInfo ver = getSettingsVersionForPackage(scannedPkg);
- return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
+ return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
}
- private int compareSignaturesRecover(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isRecoverSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- String msg = null;
- try {
- if (Signature.areEffectiveMatch(existingSigs.mSignatures, scannedPkg.mSignatures)) {
- logCriticalInfo(Log.INFO, "Recovered effectively matching certificates for "
- + scannedPkg.packageName);
- return PackageManager.SIGNATURE_MATCH;
- }
- } catch (CertificateException e) {
- msg = e.getMessage();
- }
-
- logCriticalInfo(Log.INFO,
- "Failed to recover certificates for " + scannedPkg.packageName + ": " + msg);
- return PackageManager.SIGNATURE_NO_MATCH;
+ private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
+ return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
}
@Override
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mPackages) {
if (canViewInstantApps(callingUid, callingUserId)) {
- return new ArrayList<String>(mPackages.keySet());
+ return new ArrayList<>(mPackages.keySet());
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final List<String> result = new ArrayList<>();
}
}
+ /**
+ * <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.
+ */
@Override
public String[] getPackagesForUid(int uid) {
final int callingUid = Binder.getCallingUid();
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
- uid = UserHandle.getAppId(uid);
+ final int appId = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return null;
if (getInstantAppPackageName(callingUid) != null) {
return null;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
final String[] names = new String[uids.length];
synchronized (mPackages) {
for (int i = uids.length - 1; i >= 0; i--) {
- final int uid = uids[i];
- Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ final int appId = UserHandle.getAppId(uids[i]);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
names[i] = "shared:" + sus.name;
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgFlags;
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgPrivateFlags;
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
- uid = UserHandle.getAppId(uid);
+ final int appId = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLPr(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
final Iterator<PackageSetting> it = sus.packages.iterator();
}
@Override
- public String[] getAppOpPermissionPackages(String permissionName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- synchronized (mPackages) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(permissionName);
- if (pkgs == null) {
- return null;
- }
- return pkgs.toArray(new String[pkgs.size()]);
- }
+ public String[] getAppOpPermissionPackages(String permName) {
+ return mPermissionManager.getAppOpPermissionPackages(permName);
}
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
- return resolveIntentInternal(
- intent, resolvedType, flags, userId, false /*includeInstantApps*/);
+ return resolveIntentInternal(intent, resolvedType, flags, userId, false,
+ Binder.getCallingUid());
}
+ /**
+ * Normally instant apps can only be resolved when they're visible to the caller.
+ * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
+ * since we need to allow the system to start any installed application.
+ */
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
- int flags, int userId, boolean resolveForStart) {
+ int flags, int userId, boolean resolveForStart, int filterCallingUid) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
- flags = updateFlagsForResolve(flags, userId, intent, callingUid, resolveForStart);
- enforceCrossUserPermission(callingUid, userId,
+ flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
- flags, callingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
+ flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final ResolveInfo bestChoice =
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
// Find any earlier preferred or last chosen entries and nuke them
- findPreferredActivity(intent, resolvedType,
- flags, query, 0, false, true, false, userId);
+ findPreferredActivityNotLocked(
+ intent, resolvedType, flags, query, 0, false, true, false, userId);
// Add the new activity as the last chosen for this filter
addPreferredActivityInternal(filter, match, null, activity, false, userId,
"Setting last chosen");
if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
- return findPreferredActivity(intent, resolvedType, flags, query, 0,
- false, false, false, userId);
+ return findPreferredActivityNotLocked(
+ intent, resolvedType, flags, query, 0, false, false, false, userId);
}
/**
* Returns whether or not instant apps have been disabled remotely.
*/
- private boolean isEphemeralDisabled() {
- return mEphemeralAppsDisabled;
+ private boolean areWebInstantAppsDisabled(int userId) {
+ return mWebInstantAppsDisabled.get(userId);
}
- private boolean isInstantAppAllowed(
+ private boolean isInstantAppResolutionAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck) {
if (mInstantAppResolverConnection == null) {
if (!skipPackageCheck && intent.getPackage() != null) {
return false;
}
- final boolean isWebUri = hasWebURI(intent);
- if (!isWebUri || intent.getData().getHost() == null) {
- return false;
+ if (!intent.isWebIntent()) {
+ // for non web intents, we should not resolve externally if an app already exists to
+ // handle it or if the caller didn't explicitly request it.
+ if ((resolvedActivities != null && resolvedActivities.size() != 0)
+ || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
+ return false;
+ }
+ } else {
+ if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
+ return false;
+ } else if (areWebInstantAppsDisabled(userId)) {
+ return false;
+ }
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
final int status = (int) (packedStatus >> 32);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
|| status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app;"
+ " pkg: " + packageName + ", status: " + status);
}
}
}
if (ps.getInstantApp(userId)) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app installed;"
+ " pkg: " + packageName);
}
}
// If we have saved a preference for a preferred activity for
// this Intent, use that.
- ResolveInfo ri = findPreferredActivity(intent, resolvedType,
+ ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
flags, query, r0.priority, true, false, debug, userId);
if (ri != null) {
return ri;
return true;
}
+ @GuardedBy("mPackages")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
final int N = query.size();
return null;
}
+ private boolean isHomeIntent(Intent intent) {
+ return ACTION_MAIN.equals(intent.getAction())
+ && intent.hasCategory(CATEGORY_HOME)
+ && intent.hasCategory(CATEGORY_DEFAULT);
+ }
+
// TODO: handle preferred activities missing while user has amnesia
- ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
+ /** <b>must not hold {@link #mPackages}</b> */
+ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
+ if (Thread.holdsLock(mPackages)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ + " is holding mPackages", new Throwable());
+ }
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
+ // Do NOT hold the packages lock; this calls up into the settings provider which
+ // could cause a deadlock.
+ final boolean isDeviceProvisioned =
+ android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
flags = updateFlagsForResolve(
flags, userId, intent, callingUid, false /*includeInstantApps*/);
intent = updateIntentForResolve(intent);
Slog.v(TAG, " null");
}
}
+ final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
+ && !isDeviceProvisioned;
if (ai == null) {
+ // Do not remove launcher's preferred activity during SetupWizard
+ // due to it may not install yet
+ if (excludeSetupWizardHomeActivity) {
+ continue;
+ }
+
// This previously registered preferred activity
// component is no longer known. Most likely an update
// to the app was installed and in the new version this
// was created, and is not a subset of the preferred set, we need to
// clear it and re-ask the user their preference, if we're looking for
// an "always" type entry.
- if (always && !pa.mPref.sameSet(query)) {
- if (pa.mPref.isSuperset(query)) {
- // some components of the set are no longer present in
- // the query, but the preferred activity can still be reused
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Result set changed, but PreferredActivity is"
- + " still valid as only non-preferred components"
- + " were removed for " + intent + " type "
- + resolvedType);
+
+ if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
+ if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
+ if (!excludeSetupWizardHomeActivity) {
+ // some components of the set are no longer present in
+ // the query, but the preferred activity can still be reused
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Result set changed, but PreferredActivity"
+ + " is still valid as only non-preferred"
+ + " components were removed for " + intent
+ + " type " + resolvedType);
+ }
+ // remove obsolete components and re-add the up-to-date
+ // filter
+ PreferredActivity freshPa = new PreferredActivity(pa,
+ pa.mPref.mMatch,
+ pa.mPref.discardObsoleteComponents(query),
+ pa.mPref.mComponent,
+ pa.mPref.mAlways);
+ pir.removeFilter(pa);
+ pir.addFilter(freshPa);
+ changed = true;
+ } else {
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Do not remove preferred activity for launcher"
+ + " during SetupWizard");
+ }
}
- // remove obsolete components and re-add the up-to-date filter
- PreferredActivity freshPa = new PreferredActivity(pa,
- pa.mPref.mMatch,
- pa.mPref.discardObsoleteComponents(query),
- pa.mPref.mComponent,
- pa.mPref.mAlways);
- pir.removeFilter(pa);
- pir.addFilter(freshPa);
- changed = true;
} else {
Slog.i(TAG,
"Result set changed, dropping preferred activity for "
if (matches.get(i).getTargetUserId() == targetUserId) return true;
}
}
- if (hasWebURI(intent)) {
+ if (intent.hasWebURI()) {
// cross-profile app linking works only towards the parent.
final int callingUid = Binder.getCallingUid();
final UserInfo parent = getProfileParent(sourceUserId);
callingUid = mIsolatedOwners.get(callingUid);
}
final int appId = UserHandle.getAppId(callingUid);
- final Object obj = mSettings.getUserIdLPr(appId);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
boolean resolveForStart, boolean allowDynamicSplits) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
final String pkgName = intent.getPackage();
flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/);
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
// When specifying an explicit component, we prevent the activity from being
}
}
return applyPostResolutionFilter(
- list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+ list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
+ userId, intent);
}
// reader
boolean sortResult = false;
- boolean addEphemeral = false;
+ boolean addInstant = false;
List<ResolveInfo> result;
- final boolean ephemeralDisabled = isEphemeralDisabled();
synchronized (mPackages) {
if (pkgName == null) {
List<CrossProfileIntentFilter> matchingFilters =
ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
resolvedType, flags, userId);
if (xpResolveInfo != null) {
- List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
+ List<ResolveInfo> xpResult = new ArrayList<>(1);
xpResult.add(xpResolveInfo);
return applyPostResolutionFilter(
filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
- allowDynamicSplits, filterCallingUid, userId);
+ allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
}
// Check for results in the current profile.
- result = filterIfNotSystemUser(mActivities.queryIntent(
+ result = filterIfNotSystemUser(mComponentResolver.queryActivities(
intent, resolvedType, flags, userId), userId);
- addEphemeral = !ephemeralDisabled
- && isInstantAppAllowed(intent, result, userId, false /*skipPackageCheck*/);
+ addInstant = isInstantAppResolutionAllowed(intent, result, userId,
+ false /*skipPackageCheck*/);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
xpResolveInfo = queryCrossProfileIntents(
sortResult = true;
}
}
- if (hasWebURI(intent)) {
+ if (intent.hasWebURI()) {
CrossProfileDomainInfo xpDomainInfo = null;
final UserInfo parent = getProfileParent(userId);
if (parent != null) {
// in the result.
result.remove(xpResolveInfo);
}
- if (result.size() == 0 && !addEphemeral) {
+ if (result.size() == 0 && !addInstant) {
// No result in current profile, but found candidate in parent user.
// And we are not going to add emphemeral app, so we can return the
// result straight away.
result.add(xpDomainInfo.resolveInfo);
return applyPostResolutionFilter(result, instantAppPkgName,
- allowDynamicSplits, filterCallingUid, userId);
+ allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+ intent);
}
- } else if (result.size() <= 1 && !addEphemeral) {
+ } else if (result.size() <= 1 && !addInstant) {
// No result in parent user and <= 1 result in current profile, and we
// are not going to add emphemeral app, so we can return the result without
// further processing.
return applyPostResolutionFilter(result, instantAppPkgName,
- allowDynamicSplits, filterCallingUid, userId);
+ allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+ intent);
}
// We have more than one candidate (combining results from current and parent
// profile), so we need filtering and sorting.
final PackageParser.Package pkg = mPackages.get(pkgName);
result = null;
if (pkg != null) {
- result = filterIfNotSystemUser(
- mActivities.queryIntentForPackage(
- intent, resolvedType, flags, pkg.activities, userId),
- userId);
+ result = filterIfNotSystemUser(mComponentResolver.queryActivities(
+ intent, resolvedType, flags, pkg.activities, userId), userId);
}
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
- addEphemeral = !ephemeralDisabled
- && isInstantAppAllowed(
+ addInstant = isInstantAppResolutionAllowed(
intent, null /*result*/, userId, true /*skipPackageCheck*/);
if (result == null) {
result = new ArrayList<>();
}
}
}
- if (addEphemeral) {
+ if (addInstant) {
result = maybeAddInstantAppInstaller(
result, intent, resolvedType, flags, userId, resolveForStart);
}
if (sortResult) {
- Collections.sort(result, mResolvePrioritySorter);
+ Collections.sort(result, RESOLVE_PRIORITY_SORTER);
}
return applyPostResolutionFilter(
- result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+ result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
+ userId, intent);
}
private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
ResolveInfo localInstantApp = null;
boolean blockResolution = false;
if (!alreadyResolvedLocally) {
- final List<ResolveInfo> instantApps = mActivities.queryIntent(intent, resolvedType,
+ final List<ResolveInfo> instantApps = mComponentResolver.queryActivities(
+ intent,
+ resolvedType,
flags
| PackageManager.GET_RESOLVED_FILTER
| PackageManager.MATCH_INSTANT
if (ps.getInstantApp(userId)) {
final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
final int status = (int)(packedStatus >> 32);
- final int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
// there's a local instant application installed, but, the user has
// chosen to never use it; skip resolution and don't acknowledge
// an instant application is even available
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Instant app marked to never run; pkg: " + packageName);
}
blockResolution = true;
} else {
// we have a locally installed instant application; skip resolution
// but acknowledge there's an instant application available
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Found installed instant app; pkg: " + packageName);
}
localInstantApp = info;
null /*responseObj*/, intent /*origIntent*/, resolvedType,
null /*callingPackage*/, userId, null /*verificationBundle*/,
resolveForStart);
- auxiliaryResponse =
- InstantAppResolver.doInstantAppResolutionPhaseOne(
- mContext, mInstantAppResolverConnection, requestObject);
+ auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
+ mInstantAppResolverConnection, requestObject);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
} else {
// we have an instant application locally, but, we can't admit that since
// instant application available externally. when it comes time to start
// the instant application, we'll do the right thing.
final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
- auxiliaryResponse = new AuxiliaryResolveInfo(
- ai.packageName, null /*splitName*/, null /*failureActivity*/,
- ai.versionCode, null /*failureIntent*/);
+ auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */,
+ ai.packageName, ai.longVersionCode, null /* splitName */);
}
}
- if (auxiliaryResponse != null) {
- if (DEBUG_EPHEMERAL) {
- Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
- }
- final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
- final PackageSetting ps =
- mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
- if (ps != null) {
- ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
- mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
- ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
- ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
- // make sure this resolver is the default
- ephemeralInstaller.isDefault = true;
- ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
- // add a non-generic filter
- ephemeralInstaller.filter = new IntentFilter(intent.getAction());
- ephemeralInstaller.filter.addDataPath(
- intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
- ephemeralInstaller.isInstantAppAvailable = true;
- result.add(ephemeralInstaller);
- }
+ if (intent.isWebIntent() && auxiliaryResponse == null) {
+ return result;
+ }
+ final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
+ if (ps == null
+ || !ps.readUserState(userId).isEnabled(mInstantAppInstallerActivity, 0)) {
+ return result;
+ }
+ final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
+ ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
+ mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
+ ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+ | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ // add a non-generic filter
+ ephemeralInstaller.filter = new IntentFilter();
+ if (intent.getAction() != null) {
+ ephemeralInstaller.filter.addAction(intent.getAction());
+ }
+ if (intent.getData() != null && intent.getData().getPath() != null) {
+ ephemeralInstaller.filter.addDataPath(
+ intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
}
+ ephemeralInstaller.isInstantAppAvailable = true;
+ // make sure this resolver is the default
+ ephemeralInstaller.isDefault = true;
+ ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
+ if (DEBUG_INSTANT) {
+ Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+ }
+
+ result.add(ephemeralInstaller);
return result;
}
sourceUserId)) {
return null;
}
- List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
+ List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
resolvedType, flags, parentUserId);
if (resultTargetUser == null || resultTargetUser.isEmpty()) {
* @param resolveInfos The pre-filtered list of resolved activities
* @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
* is performed.
+ * @param intent
* @return A filtered list of resolved activities.
*/
private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
- String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId) {
+ String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
+ boolean resolveForStart, int userId, Intent intent) {
+ final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
final ResolveInfo info = resolveInfos.get(i);
+ // remove locally resolved instant app web results when disabled
+ if (info.isInstantAppAvailable && blockInstant) {
+ resolveInfos.remove(i);
+ continue;
+ }
// allow activities that are defined in the provided package
if (allowDynamicSplits
+ && info.activityInfo != null
&& info.activityInfo.splitName != null
&& !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
info.activityInfo.splitName)) {
- if (mInstantAppInstallerInfo == null) {
+ if (mInstantAppInstallerActivity == null) {
if (DEBUG_INSTALL) {
Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
}
resolveInfos.remove(i);
continue;
}
+ if (blockInstant && isInstantApp(info.activityInfo.packageName, userId)) {
+ resolveInfos.remove(i);
+ continue;
+ }
// requested activity is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
if (DEBUG_INSTALL) {
Slog.v(TAG, "Adding installer to the ResolveInfo list");
}
- final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+ final ResolveInfo installerInfo = new ResolveInfo(
+ mInstantAppInstallerInfo);
final ComponentName installFailureActivity = findInstallFailureActivity(
info.activityInfo.packageName, filterCallingUid, userId);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
- info.activityInfo.packageName, info.activityInfo.splitName,
installFailureActivity,
- info.activityInfo.applicationInfo.versionCode,
- null /*failureIntent*/);
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ info.activityInfo.packageName,
+ info.activityInfo.applicationInfo.longVersionCode,
+ info.activityInfo.splitName);
// add a non-generic filter
installerInfo.filter = new IntentFilter();
installerInfo.resolvePackageName = info.getComponentInfo().packageName;
installerInfo.labelRes = info.resolveLabelResId();
installerInfo.icon = info.resolveIconResId();
-
- // propagate priority/preferred order/default
- installerInfo.priority = info.priority;
- installerInfo.preferredOrder = info.preferredOrder;
- installerInfo.isDefault = info.isDefault;
+ installerInfo.isInstantAppAvailable = true;
resolveInfos.set(i, installerInfo);
continue;
}
} else if (ephemeralPkgName.equals(info.activityInfo.packageName)) {
// caller is same app; don't need to apply any other filtering
continue;
+ } else if (resolveForStart
+ && (intent.isWebIntent()
+ || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0)
+ && intent.getPackage() == null
+ && intent.getComponent() == null) {
+ // ephemeral apps can launch other ephemeral apps indirectly
+ continue;
}
// allow activities that have been explicitly exposed to ephemeral apps
final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
}
- private static boolean hasWebURI(Intent intent) {
- if (intent.getData() == null) {
- return false;
- }
- final String scheme = intent.getScheme();
- if (TextUtils.isEmpty(scheme)) {
- return false;
- }
- return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
- }
-
private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
int userId) {
candidates.size());
}
- ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> alwaysAskList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
- ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
+ final ArrayList<ResolveInfo> result = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
+ final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+ final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
+ final ArrayList<ResolveInfo> neverList = new ArrayList<>();
+ final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
synchronized (mPackages) {
final int count = candidates.size();
private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,
String resolvedType, int flags, int sourceUserId) {
int targetUserId = filter.getTargetUserId();
- List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
+ List<ResolveInfo> resultTargetUser = mComponentResolver.queryActivities(intent,
resolvedType, flags, targetUserId);
if (resultTargetUser != null && isUserEnabled(targetUserId)) {
// If all the matches in the target profile are suspended, return null.
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, intent, callingUid,
false /*includeInstantApps*/);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent activity options");
final String resultsAction = intent.getAction();
String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
if (ai != null) {
// When specifying an explicit component, we prevent the activity from being
}
}
return applyPostResolutionFilter(
- list, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+ list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+ intent);
}
// reader
String pkgName = intent.getPackage();
if (pkgName == null) {
final List<ResolveInfo> result =
- mReceivers.queryIntent(intent, resolvedType, flags, userId);
+ mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
return applyPostResolutionFilter(
- result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+ result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+ intent);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
+ final List<ResolveInfo> result = mComponentResolver.queryReceivers(
intent, resolvedType, flags, pkg.receivers, userId);
return applyPostResolutionFilter(
- result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+ result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
+ intent);
}
return Collections.emptyList();
}
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
// When specifying an explicit component, we prevent the service from being
String pkgName = intent.getPackage();
if (pkgName == null) {
return applyPostServiceResolutionFilter(
- mServices.queryIntent(intent, resolvedType, flags, userId),
+ mComponentResolver.queryServices(intent, resolvedType, flags, userId),
instantAppPkgName);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
return applyPostServiceResolutionFilter(
- mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
+ mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services,
userId),
instantAppPkgName);
}
info.serviceInfo.splitName)) {
// requested service is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
- final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+ final ResolveInfo installerInfo = new ResolveInfo(
+ mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
- info.serviceInfo.packageName, info.serviceInfo.splitName,
- null /*failureActivity*/, info.serviceInfo.applicationInfo.versionCode,
- null /*failureIntent*/);
- // make sure this resolver is the default
- installerInfo.isDefault = true;
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ null /* installFailureActivity */,
+ info.serviceInfo.packageName,
+ info.serviceInfo.applicationInfo.longVersionCode,
+ info.serviceInfo.splitName);
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// load resources from the correct package
}
}
if (comp != null) {
- final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final List<ResolveInfo> list = new ArrayList<>(1);
final ProviderInfo pi = getProviderInfo(comp, flags, userId);
if (pi != null) {
// When specifying an explicit component, we prevent the provider from being
String pkgName = intent.getPackage();
if (pkgName == null) {
return applyPostContentProviderResolutionFilter(
- mProviders.queryIntent(intent, resolvedType, flags, userId),
+ mComponentResolver.queryProviders(intent, resolvedType, flags, userId),
instantAppPkgName);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
return applyPostContentProviderResolutionFilter(
- mProviders.queryIntentForPackage(
- intent, resolvedType, flags, pkg.providers, userId),
+ mComponentResolver.queryProviders(intent, resolvedType, flags,
+ pkg.providers, userId),
instantAppPkgName);
}
return Collections.emptyList();
info.providerInfo.splitName)) {
// requested provider is defined in a split that hasn't been installed yet.
// add the installer to the resolve list
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
- final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+ final ResolveInfo installerInfo = new ResolveInfo(
+ mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
- info.providerInfo.packageName, info.providerInfo.splitName,
- null /*failureActivity*/, info.providerInfo.applicationInfo.versionCode,
- null /*failureIntent*/);
- // make sure this resolver is the default
- installerInfo.isDefault = true;
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ null /*failureActivity*/,
+ info.providerInfo.packageName,
+ info.providerInfo.applicationInfo.longVersionCode,
+ info.providerInfo.splitName);
// add a non-generic filter
installerInfo.filter = new IntentFilter();
// load resources from the correct package
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
- enforceCrossUserPermission(callingUid, userId,
+ final boolean listApex = (flags & MATCH_APEX) != 0;
+ final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
+
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */,
"get installed packages");
}
}
}
-
+ if (listApex) {
+ if (listFactory) {
+ list.addAll(mApexManager.getFactoryPackages());
+ } else {
+ list.addAll(mApexManager.getActivePackages());
+ }
+ if (listUninstalled) {
+ list.addAll(mApexManager.getInactivePackages());
+ }
+ }
return new ParceledListSlice<>(list);
}
}
String[] permissions, int flags, int userId) {
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, permissions);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"get packages holding permissions");
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
// writer
synchronized (mPackages) {
- ArrayList<PackageInfo> list = new ArrayList<PackageInfo>();
+ ArrayList<PackageInfo> list = new ArrayList<>();
boolean[] tmpBools = new boolean[permissions.length];
if (listUninstalled) {
for (PackageSetting ps : mSettings.mPackages.values()) {
}
}
- return new ParceledListSlice<PackageInfo>(list);
+ 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 ParceledListSlice.emptyList();
+ return Collections.emptyList();
}
- if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForApplication(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
- enforceCrossUserPermission(
+ mPermissionManager.enforceCrossUserPermission(
callingUid,
userId,
false /* requireFullPermission */,
}
}
- return new ParceledListSlice<>(list);
+ return list;
}
}
@Override
public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
- if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+ if (HIDE_EPHEMERAL_APIS) {
return null;
}
if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getEphemeralApplications");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getEphemeralApplications");
synchronized (mPackages) {
@Override
public boolean isInstantApp(String packageName, int userId) {
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"isInstantApp");
- if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+ if (HIDE_EPHEMERAL_APIS) {
return false;
}
@Override
public byte[] getInstantAppCookie(String packageName, int userId) {
- if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+ if (HIDE_EPHEMERAL_APIS) {
return null;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppCookie");
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
@Override
public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
- if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+ if (HIDE_EPHEMERAL_APIS) {
return true;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, true /* checkShell */,
"setInstantAppCookie");
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
@Override
public Bitmap getInstantAppIcon(String packageName, int userId) {
- if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+ if (HIDE_EPHEMERAL_APIS) {
return null;
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getInstantAppIcon");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppIcon");
}
private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
- final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<>();
// reader
synchronized (mPackages) {
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+ return resolveContentProviderInternal(name, flags, userId);
+ }
+
+ private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId, name);
- final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
- // reader
+ final int callingUid = Binder.getCallingUid();
+ final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId);
+ if (providerInfo == null) {
+ return null;
+ }
+ if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
+ return null;
+ }
synchronized (mPackages) {
- final PackageParser.Provider provider = mProvidersByAuthority.get(name);
- PackageSetting ps = provider != null
- ? mSettings.mPackages.get(provider.owner.packageName)
- : null;
- if (ps != null) {
- final boolean isInstantApp = ps.getInstantApp(userId);
- // normal application; filter out instant application provider
- if (instantAppPkgName == null && isInstantApp) {
- return null;
- }
- // instant application; filter out other instant applications
- if (instantAppPkgName != null
- && isInstantApp
- && !provider.owner.packageName.equals(instantAppPkgName)) {
- return null;
- }
- // instant application; filter out non-exposed provider
- if (instantAppPkgName != null
- && !isInstantApp
- && (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0) {
- return null;
- }
- // provider not enabled
- if (!mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)) {
- return null;
- }
- return PackageParser.generateProviderInfo(
- provider, flags, ps.readUserState(userId), userId);
+ final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+ final ComponentName component =
+ new ComponentName(providerInfo.packageName, providerInfo.name);
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ return null;
}
- return null;
+ return providerInfo;
}
}
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
- // reader
- synchronized (mPackages) {
- final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProvidersByAuthority
- .entrySet().iterator();
- final int userId = UserHandle.getCallingUserId();
- while (i.hasNext()) {
- Map.Entry<String, PackageParser.Provider> entry = i.next();
- PackageParser.Provider p = entry.getValue();
- PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
-
- if (ps != null && p.syncable
- && (!mSafeMode || (p.info.applicationInfo.flags
- &ApplicationInfo.FLAG_SYSTEM) != 0)) {
- ProviderInfo info = PackageParser.generateProviderInfo(p, 0,
- ps.readUserState(userId), userId);
- if (info != null) {
- outNames.add(entry.getKey());
- outInfo.add(info);
- }
- }
- }
- }
+ mComponentResolver.querySyncProviders(
+ outNames, outInfo, mSafeMode, UserHandle.getCallingUserId());
}
@Override
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForComponent(flags, userId, processName);
ArrayList<ProviderInfo> finalList = null;
- // reader
+ final List<ProviderInfo> matchList =
+ mComponentResolver.queryProviders(processName, metaDataKey, uid, flags, userId);
+ final int listSize = (matchList == null ? 0 : matchList.size());
synchronized (mPackages) {
- final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();
- while (i.hasNext()) {
- final PackageParser.Provider p = i.next();
- PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
- if (ps != null && p.info.authority != null
- && (processName == null
- || (p.info.processName.equals(processName)
- && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
- && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
-
- // See PM.queryContentProviders()'s javadoc for why we have the metaData
- // parameter.
- if (metaDataKey != null
- && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
- continue;
- }
- final ComponentName component =
- new ComponentName(p.info.packageName, p.info.name);
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
- continue;
- }
- if (finalList == null) {
- finalList = new ArrayList<ProviderInfo>(3);
- }
- ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
- ps.readUserState(userId), userId);
- if (info != null) {
- finalList.add(info);
- }
+ for (int i = 0; i < listSize; i++) {
+ final ProviderInfo providerInfo = matchList.get(i);
+ if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
+ continue;
+ }
+ final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+ final ComponentName component =
+ new ComponentName(providerInfo.packageName, providerInfo.name);
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ continue;
}
+ if (finalList == null) {
+ finalList = new ArrayList<>(listSize - i);
+ }
+ finalList.add(providerInfo);
}
}
if (finalList != null) {
- Collections.sort(finalList, mProviderInitOrderSorter);
- return new ParceledListSlice<ProviderInfo>(finalList);
+ finalList.sort(sProviderInitOrderSorter);
+ return new ParceledListSlice<>(finalList);
}
return ParceledListSlice.emptyList();
private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
int flags) {
- ArrayList<InstrumentationInfo> finalList = new ArrayList<InstrumentationInfo>();
+ ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
// reader
synchronized (mPackages) {
return finalList;
}
- private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
+ private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
- scanDirLI(dir, parseFlags, scanFlags, currentTime);
+ scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
- final File[] files = dir.listFiles();
+ private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
+ final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
- Log.d(TAG, "No files in app dir " + dir);
+ Log.d(TAG, "No files in app dir " + scanDir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
- ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
+ try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
- mParallelPackageParserCallback);
-
- // Submit files for parsing in parallel
- int fileCount = 0;
- for (File file : files) {
- final boolean isPackage = (isApkFile(file) || file.isDirectory())
- && !PackageInstallerService.isStageName(file.getName());
- if (!isPackage) {
- // Ignore entries which are not packages
- continue;
+ mParallelPackageParserCallback)) {
+ // Submit files for parsing in parallel
+ int fileCount = 0;
+ for (File file : files) {
+ final boolean isPackage = (isApkFile(file) || file.isDirectory())
+ && !PackageInstallerService.isStageName(file.getName());
+ if (!isPackage) {
+ // Ignore entries which are not packages
+ continue;
+ }
+ parallelPackageParser.submit(file, parseFlags);
+ fileCount++;
}
- parallelPackageParser.submit(file, parseFlags);
- fileCount++;
- }
- // Process results one by one
- for (; fileCount > 0; fileCount--) {
- ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
- Throwable throwable = parseResult.throwable;
- int errorCode = PackageManager.INSTALL_SUCCEEDED;
+ // Process results one by one
+ for (; fileCount > 0; fileCount--) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ int errorCode = PackageManager.INSTALL_SUCCEEDED;
- if (throwable == null) {
- // Static shared libraries have synthetic package names
- if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
- renameStaticSharedLibraryPackage(parseResult.pkg);
- }
- try {
- if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
- scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
+ if (throwable == null) {
+ // TODO(toddke): move lower in the scan chain
+ // Static shared libraries have synthetic package names
+ if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
+ renameStaticSharedLibraryPackage(parseResult.pkg);
+ }
+ try {
+ scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
currentTime, null);
+ } catch (PackageManagerException e) {
+ errorCode = e.error;
+ Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
- } catch (PackageManagerException e) {
+ } else if (throwable instanceof PackageParser.PackageParserException) {
+ PackageParser.PackageParserException e = (PackageParser.PackageParserException)
+ throwable;
errorCode = e.error;
- Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
+ Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + parseResult.scanFile, throwable);
}
- } else if (throwable instanceof PackageParser.PackageParserException) {
- PackageParser.PackageParserException e = (PackageParser.PackageParserException)
- throwable;
- errorCode = e.error;
- Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
- } else {
- throw new IllegalStateException("Unexpected exception occurred while parsing "
- + parseResult.scanFile, throwable);
- }
- // Delete invalid userdata apps
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
- errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
- logCriticalInfo(Log.WARN,
- "Deleting invalid package at " + parseResult.scanFile);
- removeCodePathLI(parseResult.scanFile);
+ // Delete invalid userdata apps
+ if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
+ errorCode != PackageManager.INSTALL_SUCCEEDED) {
+ logCriticalInfo(Log.WARN,
+ "Deleting invalid package at " + parseResult.scanFile);
+ removeCodePathLI(parseResult.scanFile);
+ }
}
}
- parallelPackageParser.close();
}
- private static File getSettingsProblemFile() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- File fname = new File(systemDir, "uiderrors.txt");
- return fname;
- }
-
- static void reportSettingsProblem(int priority, String msg) {
+ public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
- public static void logCriticalInfo(int priority, String msg) {
- Slog.println(priority, TAG, msg);
- EventLogTags.writePmCriticalInfo(msg);
- try {
- File fname = getSettingsProblemFile();
- FileOutputStream out = new FileOutputStream(fname, true);
- PrintWriter pw = new FastPrintWriter(out);
- SimpleDateFormat formatter = new SimpleDateFormat();
- String dateString = formatter.format(new Date(System.currentTimeMillis()));
- pw.println(dateString + ": " + msg);
- pw.close();
- FileUtils.setPermissions(
- fname.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
- -1, -1);
- } catch (java.io.IOException e) {
- }
- }
-
- private long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
- if (srcFile.isDirectory()) {
- final File baseFile = new File(pkg.baseCodePath);
- long maxModifiedTime = baseFile.lastModified();
- if (pkg.splitCodePaths != null) {
- for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
- final File splitFile = new File(pkg.splitCodePaths[i]);
- maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
- }
- }
- return maxModifiedTime;
- }
- return srcFile.lastModified();
- }
-
- private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
- final int policyFlags) throws PackageManagerException {
+ private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
+ boolean forceCollect, boolean skipVerify) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
// directory and not the APK file.
final long lastModifiedTime = mIsPreNMR1Upgrade
- ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
- if (ps != null
- && ps.codePath.equals(srcFile)
+ ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
+ final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg);
+ if (ps != null && !forceCollect
+ && ps.codePathString.equals(pkg.codePath)
&& ps.timeStamp == lastModifiedTime
- && !isCompatSignatureUpdateNeeded(pkg)
- && !isRecoverSignatureUpdateNeeded(pkg)) {
- long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- ArraySet<PublicKey> signingKs;
- synchronized (mPackages) {
- signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
- }
- if (ps.signatures.mSignatures != null
- && ps.signatures.mSignatures.length != 0
- && signingKs != null) {
- // Optimization: reuse the existing cached certificates
+ && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
+ && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
+ if (ps.signatures.mSigningDetails.signatures != null
+ && ps.signatures.mSigningDetails.signatures.length != 0
+ && ps.signatures.mSigningDetails.signatureSchemeVersion
+ != SignatureSchemeVersion.UNKNOWN) {
+ // Optimization: reuse the existing cached signing data
// if the package appears to be unchanged.
- pkg.mSignatures = ps.signatures.mSignatures;
- pkg.mSigningKeys = signingKs;
+ pkg.mSigningDetails =
+ new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
return;
}
Slog.w(TAG, "PackageSetting for " + ps.name
+ " is missing signatures. Collecting certs again to recover them.");
} else {
- Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
+ Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
+ (forceCollect ? " (forced)" : ""));
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- PackageParser.collectCertificates(pkg, policyFlags);
+ PackageParser.collectCertificates(pkg, skipVerify);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
}
/**
+ * Clear the package profile if this was an upgrade and the package
+ * version was updated.
+ */
+ private void maybeClearProfilesForUpgradesLI(
+ @Nullable PackageSetting originalPkgSetting,
+ @NonNull PackageParser.Package currentPkg) {
+ if (originalPkgSetting == null || !isDeviceUpgrading()) {
+ return;
+ }
+ if (originalPkgSetting.versionCode == currentPkg.mVersionCode) {
+ return;
+ }
+
+ clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL);
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, originalPkgSetting.name
+ + " clear profile due to version change "
+ + originalPkgSetting.versionCode + " != "
+ + currentPkg.mVersionCode);
+ }
+ }
+
+ /**
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
+ @GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
* Scans a package and returns the newly parsed package.
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
+ @GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
- if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
- parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
- }
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
renameStaticSharedLibraryPackage(pkg);
}
- return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
/**
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
- final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
- throws PackageManagerException {
+ @GuardedBy({"mInstallLock", "mPackages"})
+ private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
+ final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
+ @Nullable UserHandle user)
+ throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
// packages (parent and children) would be successfully scanned before the
}
// Scan the parent
- PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
+ PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
- scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,
+ addForInitLI(childPackage, parseFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
+ return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
return scannedPkg;
}
/**
- * Scans a package and returns the newly parsed package.
- * @throws PackageManagerException on a parse error.
+ * Returns if forced apk verification can be skipped for the whole package, including splits.
*/
- private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
- int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
- throws PackageManagerException {
- PackageSetting ps = null;
- PackageSetting updatedPkg;
- // reader
- synchronized (mPackages) {
- // Look to see if we already know about this package.
- String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
- if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
- // This package has been renamed to its original name. Let's
- // use that.
- ps = mSettings.getPackageLPr(oldName);
- }
- // If there was no original package, see one for the real package name.
- if (ps == null) {
- ps = mSettings.getPackageLPr(pkg.packageName);
- }
- // Check to see if this package could be hiding/updating a system
- // package. Must look for it either under the original or real
- // package name depending on our state.
- updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
- if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
-
- // If this is a package we don't know about on the system partition, we
- // may need to remove disabled child packages on the system partition
- // or may need to not add child packages if the parent apk is updated
- // on the data partition and no longer defines this child package.
- if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
- // If this is a parent package for an updated system app and this system
- // app got an OTA update which no longer defines some of the child packages
- // we have to prune them from the disabled system packages.
- PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (disabledPs != null) {
- final int scannedChildCount = (pkg.childPackages != null)
- ? pkg.childPackages.size() : 0;
- final int disabledChildCount = disabledPs.childPackageNames != null
- ? disabledPs.childPackageNames.size() : 0;
- for (int i = 0; i < disabledChildCount; i++) {
- String disabledChildPackageName = disabledPs.childPackageNames.get(i);
- boolean disabledPackageAvailable = false;
- for (int j = 0; j < scannedChildCount; j++) {
- PackageParser.Package childPkg = pkg.childPackages.get(j);
- if (childPkg.packageName.equals(disabledChildPackageName)) {
- disabledPackageAvailable = true;
- break;
- }
- }
- if (!disabledPackageAvailable) {
- mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
- }
- }
+ private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
+ if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
+ return false;
+ }
+ // TODO: Allow base and splits to be verified individually.
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
+ return false;
}
}
}
+ return true;
+ }
- final boolean isUpdatedPkg = updatedPkg != null;
- final boolean isUpdatedSystemPkg = isUpdatedPkg
- && (policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0;
- boolean isUpdatedPkgBetter = false;
- // First check if this is a system package that may involve an update
- if (isUpdatedSystemPkg) {
- // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
- // it needs to drop FLAG_PRIVILEGED.
- if (locationIsPrivileged(scanFile)) {
- updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
- } else {
- updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
- }
-
- if (ps != null && !ps.codePath.equals(scanFile)) {
- // The path has changed from what was last scanned... check the
- // version of the new path against what we have stored to determine
- // what to do.
- if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
- if (pkg.mVersionCode <= ps.versionCode) {
- // The system package has been updated and the code path does not match
- // Ignore entry. Skip it.
- if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + scanFile
- + " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
- if (!updatedPkg.codePath.equals(scanFile)) {
- Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
- + ps.name + " changing from " + updatedPkg.codePathString
- + " to " + scanFile);
- updatedPkg.codePath = scanFile;
- updatedPkg.codePathString = scanFile.toString();
- updatedPkg.resourcePath = scanFile;
- updatedPkg.resourcePathString = scanFile.toString();
- }
- updatedPkg.pkg = pkg;
- updatedPkg.versionCode = pkg.mVersionCode;
-
- // Update the disabled system child packages to point to the package too.
- final int childCount = updatedPkg.childPackageNames != null
- ? updatedPkg.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- String childPackageName = updatedPkg.childPackageNames.get(i);
- PackageSetting updatedChildPkg = mSettings.getDisabledSystemPkgLPr(
- childPackageName);
- if (updatedChildPkg != null) {
- updatedChildPkg.pkg = pkg;
- updatedChildPkg.versionCode = pkg.mVersionCode;
- }
- }
- } else {
- // The current app on the system partition is better than
- // what we have updated to on the data partition; switch
- // back to the system partition version.
- // At this point, its safely assumed that package installation for
- // apps in system partition will go through. If not there won't be a working
- // version of the app
- // writer
- synchronized (mPackages) {
- // Just remove the loaded entries from package lists.
- mPackages.remove(ps.name);
- }
-
- logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
- + " reverting from " + ps.codePathString
- + ": new version " + pkg.mVersionCode
- + " better than installed " + ps.versionCode);
-
- InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
- synchronized (mInstallLock) {
- args.cleanUpResourcesLI();
- }
- synchronized (mPackages) {
- mSettings.enableSystemPackageLPw(ps.name);
- }
- isUpdatedPkgBetter = true;
- }
- }
+ /**
+ * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
+ * whether the apk contains signed root hash. Note that the signer's certificate still needs to
+ * match one in a trusted source, and should be done separately.
+ */
+ private boolean canSkipForcedApkVerification(String apkPath) {
+ if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
+ return VerityUtils.hasFsverity(apkPath);
}
- String resourcePath = null;
- String baseResourcePath = null;
- if ((policyFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !isUpdatedPkgBetter) {
- if (ps != null && ps.resourcePathString != null) {
- resourcePath = ps.resourcePathString;
- baseResourcePath = ps.resourcePathString;
- } else {
- // Should not happen at all. Just log an error.
- Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
+ try {
+ final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
+ if (rootHashObserved == null) {
+ return false; // APK does not contain Merkle tree root hash.
}
- } else {
- resourcePath = pkg.codePath;
- baseResourcePath = pkg.baseCodePath;
+ synchronized (mInstallLock) {
+ // Returns whether the observed root hash matches what kernel has.
+ mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+ return true;
+ }
+ } catch (InstallerException | IOException | DigestException |
+ NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
}
+ return false;
+ }
+
+ /**
+ * Adds a new package to the internal data structures during platform initialization.
+ * <p>After adding, the package is known to the system and available for querying.
+ * <p>For packages located on the device ROM [eg. packages located in /system, /vendor,
+ * etc...], additional checks are performed. Basic verification [such as ensuring
+ * matching signatures, checking version codes, etc...] occurs if the package is
+ * identical to a previously known package. If the package fails a signature check,
+ * the version installed on /data will be removed. If the version of the new package
+ * is less than or equal than the version on /data, it will be ignored.
+ * <p>Regardless of the package location, the results are applied to the internal
+ * structures and the package is made available to the rest of the system.
+ * <p>NOTE: The return value should be removed. It's the passed in package object.
+ */
+ @GuardedBy({"mInstallLock", "mPackages"})
+ private PackageParser.Package addForInitLI(PackageParser.Package pkg,
+ @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
+ @Nullable UserHandle user)
+ throws PackageManagerException {
+ final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+ final String renamedPkgName;
+ final PackageSetting disabledPkgSetting;
+ final boolean isSystemPkgUpdated;
+ final boolean pkgAlreadyExists;
+ PackageSetting pkgSetting;
- // Set application objects path explicitly.
+ // NOTE: installPackageLI() has the same code to setup the package's
+ // application info. This probably should be done lower in the call
+ // stack [such as scanPackageOnly()]. However, we verify the application
+ // info prior to that [in scanPackageNew()] and thus have to setup
+ // the application info early.
pkg.setApplicationVolumeUuid(pkg.volumeUuid);
pkg.setApplicationInfoCodePath(pkg.codePath);
pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(resourcePath);
- pkg.setApplicationInfoBaseResourcePath(baseResourcePath);
+ pkg.setApplicationInfoResourcePath(pkg.codePath);
+ pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
- // throw an exception if we have an update to a system application, but, it's not more
- // recent than the package we've already scanned
- if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
- // Set CPU Abis to application info.
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
- final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
- } else {
- pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
- pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
+ synchronized (mPackages) {
+ renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
+ final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+ if (realPkgName != null) {
+ ensurePackageRenamed(pkg, renamedPkgName);
+ }
+ final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
+ final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+ pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
+ pkgAlreadyExists = pkgSetting != null;
+ final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+ disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
+ isSystemPkgUpdated = disabledPkgSetting != null;
+
+ if (DEBUG_INSTALL && isSystemPkgUpdated) {
+ Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
+ }
+
+ final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
+ ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+ 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
+ : null;
+ if (DEBUG_PACKAGE_SCANNING
+ && (parseFlags & PackageParser.PARSE_CHATTY) != 0
+ && sharedUserSetting != null) {
+ Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+ + " (uid=" + sharedUserSetting.userId + "):"
+ + " packages=" + sharedUserSetting.packages);
+ }
+
+ if (scanSystemPartition) {
+ // Potentially prune child packages. If the application on the /system
+ // partition has been updated via OTA, but, is still disabled by a
+ // version on /data, cycle through all of its children packages and
+ // remove children that are no longer defined.
+ if (isSystemPkgUpdated) {
+ final int scannedChildCount = (pkg.childPackages != null)
+ ? pkg.childPackages.size() : 0;
+ final int disabledChildCount = disabledPkgSetting.childPackageNames != null
+ ? disabledPkgSetting.childPackageNames.size() : 0;
+ for (int i = 0; i < disabledChildCount; i++) {
+ String disabledChildPackageName =
+ disabledPkgSetting.childPackageNames.get(i);
+ boolean disabledPackageAvailable = false;
+ for (int j = 0; j < scannedChildCount; j++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(j);
+ if (childPkg.packageName.equals(disabledChildPackageName)) {
+ disabledPackageAvailable = true;
+ break;
+ }
+ }
+ if (!disabledPackageAvailable) {
+ mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
+ }
+ }
+ // we're updating the disabled package, so, scan it as the package setting
+ final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null,
+ disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
+ null /* originalPkgSetting */, null, parseFlags, scanFlags,
+ (pkg == mPlatformPackage), user);
+ applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
+ final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+ if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
+ scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
+ }
+ }
}
-
- throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
- + scanFile + " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
}
- if (isUpdatedPkg) {
- // An updated system app will not have the PARSE_IS_SYSTEM flag set
- // initially
- policyFlags |= PackageParser.PARSE_IS_SYSTEM;
+ final boolean newPkgChangedPaths =
+ pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+ final boolean newPkgVersionGreater =
+ pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+ final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
+ && newPkgChangedPaths && newPkgVersionGreater;
+ if (isSystemPkgBetter) {
+ // The version of the application on /system is greater than the version on
+ // /data. Switch back to the application on /system.
+ // It's safe to assume the application on /system will correctly scan. If not,
+ // there won't be a working copy of the application.
+ synchronized (mPackages) {
+ // just remove the loaded entries from package lists
+ mPackages.remove(pkgSetting.name);
+ }
+
+ logCriticalInfo(Log.WARN,
+ "System package updated;"
+ + " name: " + pkgSetting.name
+ + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+ + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
- // An updated privileged app will not have the PARSE_IS_PRIVILEGED
- // flag set initially
- if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
- policyFlags |= PackageParser.PARSE_IS_PRIVILEGED;
+ final InstallArgs args = createInstallArgsForExisting(
+ pkgSetting.codePathString,
+ pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+ args.cleanUpResourcesLI();
+ synchronized (mPackages) {
+ mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
- // Verify certificates against what was last scanned
- collectCertificatesLI(ps, pkg, scanFile, policyFlags);
+ if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
+ // The version of the application on the /system partition is less than or
+ // equal to the version on the /data partition. Throw an exception and use
+ // the application already installed on the /data partition.
+ throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
+ + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
+ + " better than this " + pkg.getLongVersionCode());
+ }
+
+ // Verify certificates against what was last scanned. If there was an upgrade and this is an
+ // app in a system partition, or if this is an updated priv app, we will force re-collecting
+ // certificate.
+ final boolean forceCollect = (mIsUpgrade && scanSystemPartition)
+ || PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting);
+ // Full APK verification can be skipped during certificate collection, only if the file is
+ // in verified partition, or can be verified on access (when apk verity is enabled). In both
+ // cases, only data in Signing Block is verified instead of the whole file.
+ final boolean skipVerify = scanSystemPartition
+ || (forceCollect && canSkipForcedPackageVerification(pkg));
+ collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
+
+ // Reset profile if the application version is changed
+ maybeClearProfilesForUpgradesLI(pkgSetting, pkg);
/*
* A new system app appeared, but we already had a non-system one of the
* same name installed earlier.
*/
boolean shouldHideSystemApp = false;
- if (!isUpdatedPkg && ps != null
- && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
- /*
- * Check to make sure the signatures match first. If they don't,
- * wipe the installed application and its data.
- */
- if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
- != PackageManager.SIGNATURE_MATCH) {
- logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
- + " signatures don't match existing userdata copy; removing");
+ // A new application appeared on /system, but, we already have a copy of
+ // the application installed on /data.
+ if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
+ && !pkgSetting.isSystem()) {
+
+ if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+ && !pkgSetting.signatures.mSigningDetails.checkCapability(
+ pkg.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
+ logCriticalInfo(Log.WARN,
+ "System package signature mismatch;"
+ + " name: " + pkgSetting.name);
try (PackageFreezer freezer = freezePackage(pkg.packageName,
"scanPackageInternalLI")) {
deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
}
- ps = null;
- } else {
- /*
- * If the newly-added system app is an older version than the
- * already installed version, hide it. It will be scanned later
- * and re-added like an update.
- */
- if (pkg.mVersionCode <= ps.versionCode) {
- shouldHideSystemApp = true;
- logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
- + " but new version " + pkg.mVersionCode + " better than installed "
- + ps.versionCode + "; hiding system");
- } else {
- /*
- * The newly found system app is a newer version that the
- * one previously installed. Simply remove the
- * already-installed application and replace it with our own
- * while keeping the application data.
- */
- logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
- + " reverting from " + ps.codePathString + ": new version "
- + pkg.mVersionCode + " better than installed " + ps.versionCode);
- InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
- synchronized (mInstallLock) {
- args.cleanUpResourcesLI();
- }
+ pkgSetting = null;
+ } else if (newPkgVersionGreater) {
+ // The application on /system is newer than the application on /data.
+ // Simply remove the application on /data [keeping application data]
+ // and replace it with the version on /system.
+ logCriticalInfo(Log.WARN,
+ "System package enabled;"
+ + " name: " + pkgSetting.name
+ + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
+ + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+ InstallArgs args = createInstallArgsForExisting(
+ pkgSetting.codePathString,
+ pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+ synchronized (mInstallLock) {
+ args.cleanUpResourcesLI();
}
+ } else {
+ // The application on /system is older than the application on /data. Hide
+ // the application on /system and the version on /data will be scanned later
+ // and re-added like an update.
+ shouldHideSystemApp = true;
+ logCriticalInfo(Log.INFO,
+ "System package disabled;"
+ + " name: " + pkgSetting.name
+ + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
+ + "; new: " + pkg.codePath + " @ " + pkg.codePath);
}
}
- // The apk is forward locked (not public) if its code and resources
- // are kept in different files. (except for app in either system or
- // vendor path).
- // TODO grab this value from PackageSettings
- if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
- policyFlags |= PackageParser.PARSE_FORWARD_LOCK;
+ final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
+ | SCAN_UPDATE_SIGNATURE, currentTime, user);
+ if (scanResult.success) {
+ synchronized (mPackages) {
+ boolean appIdCreated = false;
+ try {
+ final String pkgName = scanResult.pkgSetting.name;
+ final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
+ new ReconcileRequest(
+ Collections.singletonMap(pkgName, scanResult),
+ mSharedLibraries,
+ mPackages,
+ Collections.singletonMap(
+ pkgName, getSettingsVersionForPackage(pkg)),
+ Collections.singletonMap(pkgName,
+ getSharedLibLatestVersionSetting(scanResult))),
+ mSettings.mKeySetManagerService);
+ appIdCreated = optimisticallyRegisterAppId(scanResult);
+ commitReconciledScanResultLocked(reconcileResult.get(pkgName));
+ } catch (PackageManagerException e) {
+ if (appIdCreated) {
+ cleanUpAppIdCreation(scanResult);
+ }
+ throw e;
+ }
}
}
- final int userId = ((user == null) ? 0 : user.getIdentifier());
- if (ps != null && ps.getInstantApp(userId)) {
- scanFlags |= SCAN_AS_INSTANT_APP;
- }
- if (ps != null && ps.getVirtulalPreload(userId)) {
- scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
- }
-
- // Note that we invoke the following method only if we are about to unpack an application
- PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
- | SCAN_UPDATE_SIGNATURE, currentTime, user);
-
- /*
- * If the system app should be overridden by a previously installed
- * data, hide the system app now and let the /data/app scan pick it up
- * again.
- */
if (shouldHideSystemApp) {
synchronized (mPackages) {
mSettings.disableSystemPackageLPw(pkg.packageName, true);
}
}
-
- return scannedPkg;
+ return scanResult.pkgSetting.pkg;
}
- private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+ private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
// Derive the new package synthetic package name
pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
+ pkg.staticSharedLibVersion);
}
- private static String fixProcessName(String defProcessName,
- String processName) {
+ static String fixProcessName(String defProcessName, String processName) {
if (processName == null) {
return defProcessName;
}
return processName;
}
- private void verifySignaturesLP(PackageSetting pkgSetting, PackageParser.Package pkg)
- throws PackageManagerException {
- if (pkgSetting.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures)
- == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
- + pkg.packageName + " signatures do not match the "
- + "previously installed version; ignoring!");
- }
- }
-
- // Check for shared user signatures
- if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + pkg.packageName
- + " has no signatures that match those in shared user "
- + pkgSetting.sharedUser.name + "; ignoring!");
- }
- }
- }
-
/**
* 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 final void enforceSystemOrRoot(String message) {
+ 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);
+ }
+ }
+
@Override
public void performFstrimIfNeeded() {
enforceSystemOrRoot("Only the system can request fstrim");
enforceSystemOrRoot("Only the system can request package update");
// We need to re-extract after an OTA.
- boolean causeUpgrade = isUpgrade();
+ 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
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
final int elapsedTimeSeconds =
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
- final String compilerFilter, boolean bootComplete) {
+ final int compilationReason, boolean bootComplete) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
boolean useProfileForDexopt = false;
- if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
+ if ((isFirstBoot() || isDeviceUpgrading()) && isSystemApp(pkg)) {
// 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));
// 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.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
// Disabled as this causes speed-profile compilation during first boot
// issue is that we don't have a good way to say "do this only
// once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Failed to copy system profile for stub package!");
} else {
useProfileForDexopt = true;
}
}
- String pkgCompilerFilter = compilerFilter;
+ 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.
- pkgCompilerFilter =
- PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_BACKGROUND_DEXOPT);
+ pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
+ }
+
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
+ mArtManagerService.compileLayouts(pkg);
}
// checkProfiles is false to avoid merging profiles during boot which
// 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.packageName,
- pkgCompilerFilter,
+ pkgCompilationReason,
dexoptFlags));
switch (primaryDexOptStaus) {
}
}
+ @GuardedBy("mPackages")
+ public CheckPermissionDelegate getCheckPermissionDelegateLocked() {
+ return mCheckPermissionDelegate;
+ }
+
+ @GuardedBy("mPackages")
+ public void setCheckPermissionDelegateLocked(CheckPermissionDelegate delegate) {
+ mCheckPermissionDelegate = delegate;
+ }
+
+ @GuardedBy("mPackages")
private void notifyPackageUseLocked(String packageName, int reason) {
final PackageParser.Package p = mPackages.get(packageName);
if (p == null) {
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, targetCompilerFilter,
- splitName, flags));
+ return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+ targetCompilerFilter, splitName, flags));
}
/**
return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags));
}
+ /**
+ * Ask the package manager to compile layouts in the given package.
+ */
+ @Override
+ public boolean compileLayouts(String packageName) {
+ PackageParser.Package pkg;
+ synchronized (mPackages) {
+ pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ return false;
+ }
+ }
+ return mViewCompiler.compileLayouts(pkg);
+ }
+
/*package*/ boolean performDexOpt(DexoptOptions options) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
public ArraySet<String> getOptimizablePackages() {
- ArraySet<String> pkgs = new ArraySet<String>();
+ ArraySet<String> pkgs = new ArraySet<>();
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
if (PackageDexOptimizer.canOptimizePackage(p)) {
// 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<PackageParser.Package> deps = findSharedNonSystemLibraries(p);
+ Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
- options.getCompilerFilter(), options.getSplitName(),
+ options.getCompilationReason(), options.getCompilerFilter(),
+ options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
- for (PackageParser.Package depPackage : deps) {
- // TODO: Analyze and investigate if we (should) profile libraries.
- pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
- getOrCreateCompilerPackageStats(depPackage),
- mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
+ for (SharedLibraryInfo info : deps) {
+ PackageParser.Package depPackage = null;
+ synchronized (mPackages) {
+ depPackage = mPackages.get(info.getPackageName());
+ }
+ if (depPackage != null) {
+ // TODO: Analyze and investigate if we (should) profile libraries.
+ pdo.performDexOpt(depPackage, instructionSets,
+ getOrCreateCompilerPackageStats(depPackage),
+ mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
+ libraryOptions);
+ } else {
+ // TODO(ngeoffray): Support dexopting system shared libraries.
+ }
}
}
- return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets,
+ return pdo.performDexOpt(p, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
}
/**
* Reconcile the information we have about the secondary dex files belonging to
- * {@code packagName} and the actual dex files. For all dex files that were
+ * {@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
* Execute the background dexopt job immediately.
*/
@Override
- public boolean runBackgroundDexoptJob() {
+ public boolean runBackgroundDexoptJob(@Nullable List<String> packageNames) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
- return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext);
+ enforceSystemOrRootOrShell("runBackgroundDexoptJob");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
- if (p.usesLibraries != null || p.usesOptionalLibraries != null
- || p.usesStaticLibraries != null) {
- ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+ private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
+ if (p.usesLibraryInfos != null) {
+ ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
Set<String> collectedNames = new HashSet<>();
- findSharedNonSystemLibrariesRecursive(p, retValue, collectedNames);
-
- retValue.remove(p);
-
+ for (SharedLibraryInfo info : p.usesLibraryInfos) {
+ findSharedLibrariesRecursive(info, retValue, collectedNames);
+ }
return retValue;
} else {
return Collections.emptyList();
}
}
- private void findSharedNonSystemLibrariesRecursive(PackageParser.Package p,
- ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
- if (!collectedNames.contains(p.packageName)) {
- collectedNames.add(p.packageName);
- collected.add(p);
+ 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 (p.usesLibraries != null) {
- findSharedNonSystemLibrariesRecursive(p.usesLibraries,
- null, collected, collectedNames);
- }
- if (p.usesOptionalLibraries != null) {
- findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries,
- null, collected, collectedNames);
- }
- if (p.usesStaticLibraries != null) {
- findSharedNonSystemLibrariesRecursive(p.usesStaticLibraries,
- p.usesStaticLibrariesVersions, collected, collectedNames);
+ if (info.getDependencies() != null) {
+ for (SharedLibraryInfo dep : info.getDependencies()) {
+ findSharedLibrariesRecursive(dep, collected, collectedNames);
+ }
}
}
}
- private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, int[] versions,
- ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
- final int libNameCount = libs.size();
- for (int i = 0; i < libNameCount; i++) {
- String libName = libs.get(i);
- int version = (versions != null && versions.length == libNameCount)
- ? versions[i] : PackageManager.VERSION_CODE_HIGHEST;
- PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version);
- if (libPkg != null) {
- findSharedNonSystemLibrariesRecursive(libPkg, collected, collectedNames);
+ List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) {
+ List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
+ if (!deps.isEmpty()) {
+ ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+ synchronized (mPackages) {
+ for (SharedLibraryInfo info : deps) {
+ PackageParser.Package depPackage = mPackages.get(info.getPackageName());
+ if (depPackage != null) {
+ retValue.add(depPackage);
+ }
+ }
}
+ return retValue;
+ } else {
+ return Collections.emptyList();
}
}
- private PackageParser.Package findSharedNonSystemLibrary(String name, int version) {
- synchronized (mPackages) {
- SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(name, version);
- if (libEntry != null) {
- return mPackages.get(libEntry.apk);
- }
- return null;
- }
+ @Nullable
+ private SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) {
+ return getSharedLibraryInfo(name, version, mSharedLibraries, null);
}
- private SharedLibraryEntry getSharedLibraryEntryLPr(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ @Nullable
+ private static SharedLibraryInfo getSharedLibraryInfo(String name, long version,
+ Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
+ @Nullable Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries) {
+ if (newLibraries != null) {
+ final LongSparseArray<SharedLibraryInfo> versionedLib = newLibraries.get(name);
+ SharedLibraryInfo info = null;
+ if (versionedLib != null) {
+ info = versionedLib.get(version);
+ }
+ if (info != null) {
+ return info;
+ }
+ }
+ final LongSparseArray<SharedLibraryInfo> versionedLib = existingLibraries.get(name);
if (versionedLib == null) {
return null;
}
return versionedLib.get(version);
}
- private SharedLibraryEntry getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib == null) {
return null;
}
- int previousLibVersion = -1;
+ long previousLibVersion = -1;
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- final int libVersion = versionedLib.keyAt(i);
+ final long libVersion = versionedLib.keyAt(i);
if (libVersion < pkg.staticSharedLibVersion) {
previousLibVersion = Math.max(previousLibVersion, libVersion);
}
return null;
}
+
+ @Nullable
+ private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+ PackageSetting sharedLibPackage = null;
+ synchronized (mPackages) {
+ final SharedLibraryInfo latestSharedLibraVersionLPr =
+ getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg);
+ if (latestSharedLibraVersionLPr != null) {
+ sharedLibPackage = mSettings.getPackageLPr(
+ latestSharedLibraVersionLPr.getPackageName());
+ }
+ }
+ return sharedLibPackage;
+ }
+
public void shutdown() {
mPackageUsage.writeNow(mPackages);
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
+ PackageWatchdog.getInstance(mContext).writeNow();
+
+ // This is the last chance to write out pending restriction settings
+ synchronized (mPackages) {
+ if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
+ mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ for (int userId : mDirtyUsers) {
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+ mDirtyUsers.clear();
+ }
+ }
}
@Override
synchronized (mInstallLock) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- try {
- List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly();
- String codePaths = TextUtils.join(";", allCodePaths);
- mInstaller.dumpProfiles(sharedGid, packageName, codePaths);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dump profiles", e);
- }
+ mArtManagerService.dumpProfiles(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
}
}
+ @GuardedBy("mPackages")
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
return true;
}
+ @GuardedBy("mInstallLock")
void removeCodePathLI(File codePath) {
if (codePath.isDirectory()) {
try {
for (int i = 0; i < childCount; i++) {
clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
+
+ clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
}
}
- private void destroyAppProfilesLIF(PackageParser.Package pkg, int userId) {
+ private void destroyAppProfilesLIF(PackageParser.Package pkg) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
- clearAppProfilesLeafLIF(pkg);
+ mArtManagerService.clearAppProfiles(pkg);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
- clearAppProfilesLeafLIF(pkg.childPackages.get(i));
- }
- }
-
- private void clearAppProfilesLeafLIF(PackageParser.Package pkg) {
- try {
- mInstaller.clearAppProfiles(pkg.packageName);
- } catch (InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
+ mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
}
}
}
}
- private void addSharedLibraryLPr(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
- PackageParser.Package changingLib) {
- if (file.path != null) {
- usesLibraryFiles.add(file.path);
+ @GuardedBy("mPackages")
+ private void applyDefiningSharedLibraryUpdateLocked(
+ PackageParser.Package 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 (pkg.isLibrary()) {
+ if (pkg.staticSharedLibName != null) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+ if (definedLibrary != null) {
+ action.accept(definedLibrary, libInfo);
+ }
+ } else {
+ for (String libraryName : pkg.libraryNames) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+ if (definedLibrary != null) {
+ action.accept(definedLibrary, libInfo);
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mPackages")
+ private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
+ SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+ if (libInfo.getPath() != null) {
+ usesLibraryFiles.add(libInfo.getPath());
return;
}
- PackageParser.Package p = mPackages.get(file.apk);
- if (changingLib != null && changingLib.packageName.equals(file.apk)) {
+ PackageParser.Package p = mPackages.get(libInfo.getPackageName());
+ if (changingLib != null && changingLib.packageName.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
}
if (p != null) {
usesLibraryFiles.addAll(p.getAllCodePaths());
+ // If the package provides libraries, add the dependency to them.
+ applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
+ definingLibrary.addDependency(dependency);
+ });
if (p.usesLibraryFiles != null) {
Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
}
}
}
- private void updateSharedLibrariesLPr(PackageParser.Package pkg,
- PackageParser.Package changingLib) throws PackageManagerException {
+ @GuardedBy("mPackages")
+ private void updateSharedLibrariesLocked(PackageParser.Package pkg,
+ PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+ throws PackageManagerException {
+ final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
+ collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
+ executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
+ }
+
+ private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg,
+ Map<String, PackageParser.Package> availablePackages,
+ @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
+ @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
+ throws PackageManagerException {
if (pkg == null) {
- return;
+ return null;
}
- ArraySet<String> usesLibraryFiles = null;
+ // The collection used here must maintain the order of addition (so
+ // that libraries are searched in the correct order) and must have no
+ // duplicates.
+ ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
if (pkg.usesLibraries != null) {
- usesLibraryFiles = addSharedLibrariesLPw(pkg.usesLibraries,
- null, null, pkg.packageName, changingLib, true,
- pkg.applicationInfo.targetSdkVersion, null);
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null,
+ pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null,
+ availablePackages, existingLibraries, newLibraries);
}
if (pkg.usesStaticLibraries != null) {
- usesLibraryFiles = addSharedLibrariesLPw(pkg.usesStaticLibraries,
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries,
pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests,
- pkg.packageName, changingLib, true,
- pkg.applicationInfo.targetSdkVersion, usesLibraryFiles);
+ pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos,
+ availablePackages, existingLibraries, newLibraries);
}
if (pkg.usesOptionalLibraries != null) {
- usesLibraryFiles = addSharedLibrariesLPw(pkg.usesOptionalLibraries,
- null, null, pkg.packageName, changingLib, false,
- pkg.applicationInfo.targetSdkVersion, usesLibraryFiles);
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries,
+ null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion,
+ usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
}
- if (!ArrayUtils.isEmpty(usesLibraryFiles)) {
+ return usesLibraryInfos;
+ }
+
+ private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg,
+ PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
+ // 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) {
+ pkg.usesLibraryInfos = 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);
+ }
pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
} else {
+ pkg.usesLibraryInfos = null;
pkg.usesLibraryFiles = null;
}
}
- private ArraySet<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
- @Nullable int[] requiredVersions, @Nullable String[][] requiredCertDigests,
- @NonNull String packageName, @Nullable PackageParser.Package changingLib,
- boolean required, int targetSdk, @Nullable ArraySet<String> outUsedLibraries)
+ @GuardedBy("mPackages")
+ private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(
+ @NonNull List<String> requestedLibraries,
+ @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
+ @NonNull String packageName, boolean required, int targetSdk,
+ @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries,
+ @NonNull final Map<String, PackageParser.Package> availablePackages,
+ @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
+ @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
throws PackageManagerException {
final int libCount = requestedLibraries.size();
for (int i = 0; i < libCount; i++) {
final String libName = requestedLibraries.get(i);
- final int libVersion = requiredVersions != null ? requiredVersions[i]
+ final long libVersion = requiredVersions != null ? requiredVersions[i]
: SharedLibraryInfo.VERSION_UNDEFINED;
- final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(libName, libVersion);
- if (libEntry == null) {
+ final SharedLibraryInfo libraryInfo = getSharedLibraryInfo(libName, libVersion,
+ existingLibraries, newLibraries);
+ if (libraryInfo == null) {
if (required) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable shared library "
}
} else {
if (requiredVersions != null && requiredCertDigests != null) {
- if (libEntry.info.getVersion() != requiredVersions[i]) {
+ if (libraryInfo.getLongVersion() != requiredVersions[i]) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable static shared"
+ " library " + libName + " version "
- + libEntry.info.getVersion() + "; failing!");
+ + libraryInfo.getLongVersion() + "; failing!");
}
-
- PackageParser.Package libPkg = mPackages.get(libEntry.apk);
+ PackageParser.Package libPkg =
+ availablePackages.get(libraryInfo.getPackageName());
if (libPkg == null) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable static shared"
+ " library; failing!");
}
-
final String[] expectedCertDigests = requiredCertDigests[i];
- // For apps targeting O MR1 we require explicit enumeration of all certs.
- final String[] libCertDigests = (targetSdk > Build.VERSION_CODES.O)
- ? PackageUtils.computeSignaturesSha256Digests(libPkg.mSignatures)
- : PackageUtils.computeSignaturesSha256Digests(
- new Signature[]{libPkg.mSignatures[0]});
-
- // Take a shortcut if sizes don't match. Note that if an app doesn't
- // target O we don't parse the "additional-certificate" tags similarly
- // how we only consider all certs only for apps targeting O (see above).
- // Therefore, the size check is safe to make.
- if (expectedCertDigests.length != libCertDigests.length) {
- throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
- "Package " + packageName + " requires differently signed" +
- " static sDexLoadReporter.java:45.19hared library; failing!");
- }
+ if (expectedCertDigests.length > 1) {
+ // For apps targeting O MR1 we require explicit enumeration of all certs.
+ final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
+ ? PackageUtils.computeSignaturesSha256Digests(
+ libPkg.mSigningDetails.signatures)
+ : PackageUtils.computeSignaturesSha256Digests(
+ new Signature[]{libPkg.mSigningDetails.signatures[0]});
+
+ // Take a shortcut if sizes don't match. Note that if an app doesn't
+ // target O we don't parse the "additional-certificate" tags similarly
+ // how we only consider all certs only for apps targeting O (see above).
+ // Therefore, the size check is safe to make.
+ if (expectedCertDigests.length != libCertDigests.length) {
+ throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+ "Package " + packageName + " requires differently signed" +
+ " static shared library; failing!");
+ }
- // Use a predictable order as signature order may vary
- Arrays.sort(libCertDigests);
- Arrays.sort(expectedCertDigests);
+ // Use a predictable order as signature order may vary
+ Arrays.sort(libCertDigests);
+ Arrays.sort(expectedCertDigests);
- final int certCount = libCertDigests.length;
- for (int j = 0; j < certCount; j++) {
- if (!libCertDigests[j].equalsIgnoreCase(expectedCertDigests[j])) {
- throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+ final int certCount = libCertDigests.length;
+ for (int j = 0; j < certCount; j++) {
+ if (!libCertDigests[j].equalsIgnoreCase(expectedCertDigests[j])) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+ "Package " + packageName + " requires differently signed" +
+ " static shared library; failing!");
+ }
+ }
+ } else {
+ // lib signing cert could have rotated beyond the one expected, check to see
+ // if the new one has been blessed by the old
+ if (!libPkg.mSigningDetails.hasSha256Certificate(
+ ByteStringUtils.fromHexToByteArray(expectedCertDigests[0]))) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires differently signed" +
" static shared library; failing!");
}
}
}
-
if (outUsedLibraries == null) {
- outUsedLibraries = new ArraySet<>();
+ outUsedLibraries = new ArrayList<>();
}
- addSharedLibraryLPr(outUsedLibraries, libEntry, changingLib);
+ outUsedLibraries.add(libraryInfo);
}
}
return outUsedLibraries;
}
private static boolean hasString(List<String> list, List<String> which) {
- if (list == null) {
+ if (list == null || which == null) {
return false;
}
for (int i=list.size()-1; i>=0; i--) {
return false;
}
- private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
- PackageParser.Package changingPkg) {
- ArrayList<PackageParser.Package> res = null;
- for (PackageParser.Package pkg : mPackages.values()) {
- if (changingPkg != null
- && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
- && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
- && !ArrayUtils.contains(pkg.usesStaticLibraries,
- changingPkg.staticSharedLibName)) {
- return null;
- }
- if (res == null) {
- res = new ArrayList<>();
- }
- res.add(pkg);
- try {
- updateSharedLibrariesLPr(pkg, changingPkg);
- } 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.isSystemApp() || pkg.isUpdatedSystemApp()) {
- final int flags = pkg.isUpdatedSystemApp()
- ? PackageManager.DELETE_KEEP_DATA : 0;
- deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
- flags , null, true, null);
- }
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
- }
- }
- return res;
- }
-
- /**
- * Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
- */
- private static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
-
- if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
+ @GuardedBy("mPackages")
+ private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
+ PackageParser.Package updatedPkg,
+ Map<String, PackageParser.Package> availablePackages) {
+ ArrayList<PackageParser.Package> 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
+ ArrayList<PackageParser.Package> needsUpdating = null;
+ if (updatedPkg != null) {
+ needsUpdating = new ArrayList<>(1);
+ needsUpdating.add(updatedPkg);
}
-
- return cpuAbiOverride;
+ do {
+ final PackageParser.Package changingPkg =
+ (needsUpdating == null) ? null : needsUpdating.remove(0);
+ for (int i = mPackages.size() - 1; i >= 0; --i) {
+ final PackageParser.Package pkg = mPackages.valueAt(i);
+ if (changingPkg != null
+ && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
+ && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
+ && !ArrayUtils.contains(pkg.usesStaticLibraries,
+ changingPkg.staticSharedLibName)) {
+ 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.packageName)) {
+ descendants.add(pkg.packageName);
+ needsUpdating.add(pkg);
+ }
+ }
+ try {
+ updateSharedLibrariesLocked(pkg, changingPkg, 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() || pkg.isUpdatedSystemApp()) {
+ final int flags = pkg.isUpdatedSystemApp()
+ ? PackageManager.DELETE_KEEP_DATA : 0;
+ deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+ flags , null, true, null);
+ }
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+ }
+ }
+ } while (needsUpdating != null && needsUpdating.size() > 0);
+ return resultList;
}
- private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
- final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
- throws PackageManagerException {
+ @GuardedBy({"mInstallLock", "mPackages"})
+ private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
+ final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
+ @Nullable UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
// If the package has children and this is the first dive in the function
// we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
scanFlags &= ~SCAN_CHECK_ONLY;
}
- final PackageParser.Package scannedPkg;
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ final List<ScanResult> scanResults = new ArrayList<>(1 + childCount);
try {
// Scan the parent
- scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags, currentTime, user);
+ scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
// Scan the children
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
- scanPackageLI(childPkg, policyFlags,
- scanFlags, currentTime, user);
+ scanResults.add(scanPackageNewLI(childPkg, parseFlags,
+ scanFlags, currentTime, user));
}
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageTracedLI(pkg, policyFlags, scanFlags, currentTime, user);
+ return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
}
- return scannedPkg;
+ return scanResults;
}
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
- int scanFlags, long currentTime, @Nullable UserHandle user)
- throws PackageManagerException {
- boolean success = false;
- try {
- final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
- currentTime, user);
- success = true;
- return res;
- } finally {
- if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
- // DELETE_DATA_ON_FAILURES is only used by frozen paths
- destroyAppDataLIF(pkg, UserHandle.USER_ALL,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
- }
+ /** The result of a package scan. */
+ private static class ScanResult {
+ /** The request that initiated the scan that produced this result. */
+ public final ScanRequest request;
+ /** Whether or not the package scan was successful */
+ public final boolean success;
+ /**
+ * Whether or not the original PackageSetting needs to be updated with this result on
+ * commit.
+ */
+ public final boolean existingSettingCopied;
+ /**
+ * The final package settings. This may be the same object passed in
+ * the {@link ScanRequest}, but, with modified values.
+ */
+ @Nullable public final PackageSetting pkgSetting;
+ /** ABI code paths that have changed in the package scan */
+ @Nullable public final List<String> changedAbiCodePath;
+
+ public final SharedLibraryInfo staticSharedLibraryInfo;
+
+ public final List<SharedLibraryInfo> dynamicSharedLibraryInfos;
+
+ public ScanResult(
+ ScanRequest request, boolean success,
+ @Nullable PackageSetting pkgSetting,
+ @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
+ SharedLibraryInfo staticSharedLibraryInfo,
+ List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
+ this.request = request;
+ this.success = success;
+ this.pkgSetting = pkgSetting;
+ this.changedAbiCodePath = changedAbiCodePath;
+ this.existingSettingCopied = existingSettingCopied;
+ this.staticSharedLibraryInfo = staticSharedLibraryInfo;
+ this.dynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
+ }
+ }
+
+ /** A package to be scanned */
+ private static class ScanRequest {
+ /** The parsed package */
+ @NonNull public final PackageParser.Package pkg;
+ /** The package this package replaces */
+ @Nullable public final PackageParser.Package oldPkg;
+ /** Shared user settings, if the package has a shared user */
+ @Nullable public final SharedUserSetting sharedUserSetting;
+ /**
+ * Package settings of the currently installed version.
+ * <p><em>IMPORTANT:</em> The contents of this object may be modified
+ * during scan.
+ */
+ @Nullable public final PackageSetting pkgSetting;
+ /** A copy of the settings for the currently installed version */
+ @Nullable public final PackageSetting oldPkgSetting;
+ /** Package settings for the disabled version on the /system partition */
+ @Nullable public final PackageSetting disabledPkgSetting;
+ /** Package settings for the installed version under its original package name */
+ @Nullable public final PackageSetting originalPkgSetting;
+ /** The real package name of a renamed application */
+ @Nullable public final String realPkgName;
+ public final @ParseFlags int parseFlags;
+ public final @ScanFlags int scanFlags;
+ /** The user for which the package is being scanned */
+ @Nullable public final UserHandle user;
+ /** Whether or not the platform package is being scanned */
+ public final boolean isPlatformPackage;
+ public ScanRequest(
+ @NonNull PackageParser.Package pkg,
+ @Nullable SharedUserSetting sharedUserSetting,
+ @Nullable PackageParser.Package oldPkg,
+ @Nullable PackageSetting pkgSetting,
+ @Nullable PackageSetting disabledPkgSetting,
+ @Nullable PackageSetting originalPkgSetting,
+ @Nullable String realPkgName,
+ @ParseFlags int parseFlags,
+ @ScanFlags int scanFlags,
+ boolean isPlatformPackage,
+ @Nullable UserHandle user) {
+ this.pkg = pkg;
+ this.oldPkg = oldPkg;
+ this.pkgSetting = pkgSetting;
+ this.sharedUserSetting = sharedUserSetting;
+ this.oldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
+ this.disabledPkgSetting = disabledPkgSetting;
+ this.originalPkgSetting = originalPkgSetting;
+ this.realPkgName = realPkgName;
+ this.parseFlags = parseFlags;
+ this.scanFlags = scanFlags;
+ this.isPlatformPackage = isPlatformPackage;
+ this.user = user;
}
}
/**
- * Returns {@code true} if the given file contains code. Otherwise {@code false}.
+ * Returns the actual scan flags depending upon the state of the other settings.
+ * <p>Updated system applications will not have the following flags set
+ * by default and need to be adjusted after the fact:
+ * <ul>
+ * <li>{@link #SCAN_AS_SYSTEM}</li>
+ * <li>{@link #SCAN_AS_PRIVILEGED}</li>
+ * <li>{@link #SCAN_AS_OEM}</li>
+ * <li>{@link #SCAN_AS_VENDOR}</li>
+ * <li>{@link #SCAN_AS_PRODUCT}</li>
+ * <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li>
+ * <li>{@link #SCAN_AS_INSTANT_APP}</li>
+ * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
+ * <li>{@link #SCAN_AS_ODM}</li>
+ * </ul>
*/
- private static boolean apkHasCode(String fileName) {
- StrictJarFile jarFile = null;
- try {
- jarFile = new StrictJarFile(fileName,
- false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
- return jarFile.findEntry("classes.dex") != null;
- } catch (IOException ignore) {
- } finally {
+ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
+ PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
+ PackageParser.Package pkg) {
+
+ // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
+ // the correct isSystem value now that we don't disable system packages before scan.
+ final PackageSetting systemPkgSetting =
+ (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null
+ && pkgSetting != null && pkgSetting.isSystem()
+ ? pkgSetting
+ : disabledPkgSetting;
+ if (systemPkgSetting != null) {
+ // updated system application, must at least have SCAN_AS_SYSTEM
+ scanFlags |= SCAN_AS_SYSTEM;
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ scanFlags |= SCAN_AS_PRIVILEGED;
+ }
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
+ scanFlags |= SCAN_AS_OEM;
+ }
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
+ scanFlags |= SCAN_AS_VENDOR;
+ }
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
+ scanFlags |= SCAN_AS_PRODUCT;
+ }
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
+ scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+ }
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
+ scanFlags |= SCAN_AS_ODM;
+ }
+ }
+ if (pkgSetting != null) {
+ final int userId = ((user == null) ? 0 : user.getIdentifier());
+ if (pkgSetting.getInstantApp(userId)) {
+ scanFlags |= SCAN_AS_INSTANT_APP;
+ }
+ if (pkgSetting.getVirtulalPreload(userId)) {
+ scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
+ }
+ }
+
+ // Scan as privileged apps that share a user with a priv-app.
+ final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
+ && SystemProperties.getInt("ro.vndk.version", 28) < 28;
+ if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
+ && !pkg.isPrivileged()
+ && (pkg.mSharedUserId != null)
+ && !skipVendorPrivilegeScan) {
+ SharedUserSetting sharedUserSetting = null;
try {
- if (jarFile != null) {
- jarFile.close();
+ sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
+ } catch (PackageManagerException ignore) {}
+ if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
+ // Exempt SharedUsers signed with the platform key.
+ // TODO(b/72378145) Fix this exemption. Force signature apps
+ // to whitelist their privileged permissions just like other
+ // priv-apps.
+ synchronized (mPackages) {
+ PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+ if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
+ scanFlags |= SCAN_AS_PRIVILEGED;
+ }
}
- } catch (IOException ignore) {}
+ }
}
- return false;
+
+ return scanFlags;
}
- /**
- * Enforces code policy for the package. This ensures that if an APK has
- * declared hasCode="true" in its manifest that the APK actually contains
- * code.
- *
- * @throws PackageManagerException If bytecode could not be found when it should exist
- */
- private static void assertCodePolicy(PackageParser.Package pkg)
- throws PackageManagerException {
- final boolean shouldHaveCode =
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
- if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Package " + pkg.baseCodePath + " code is missing");
+ // TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting
+ // the results / removing app data needs to be moved up a level to the callers of this
+ // method. Also, we need to solve the problem of potentially creating a new shared user
+ // setting. That can probably be done later and patch things up after the fact.
+ @GuardedBy({"mInstallLock", "mPackages"})
+ private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
+ final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
+ @Nullable UserHandle user) throws PackageManagerException {
+
+ final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
+ final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+ if (realPkgName != null) {
+ ensurePackageRenamed(pkg, renamedPkgName);
}
+ final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
+ final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+ final PackageSetting disabledPkgSetting =
+ mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- final boolean splitShouldHaveCode =
- (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
- if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Package " + pkg.splitCodePaths[i] + " code is missing");
+ if (mTransferedPackages.contains(pkg.packageName)) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " was transferred to another, but its .apk remains");
+ }
+
+ scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
+ synchronized (mPackages) {
+ applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
+ assertPackageIsValid(pkg, parseFlags, scanFlags);
+
+ SharedUserSetting sharedUserSetting = null;
+ if (pkg.mSharedUserId != null) {
+ // SIDE EFFECTS; may potentially allocate a new shared user
+ sharedUserSetting = mSettings.getSharedUserLPw(
+ pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+ + " (uid=" + sharedUserSetting.userId + "):"
+ + " packages=" + sharedUserSetting.packages);
}
}
+ final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+ pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
+ originalPkgSetting, realPkgName, parseFlags, scanFlags,
+ (pkg == mPlatformPackage), user);
+ return scanPackageOnlyLI(request, mFactoryTest, currentTime);
}
}
- private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
- final int policyFlags, final int scanFlags, long currentTime, @Nullable UserHandle user)
- throws PackageManagerException {
- if (DEBUG_PACKAGE_SCANNING) {
- if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
- Log.d(TAG, "Scanning package " + pkg.packageName);
- }
- applyPolicy(pkg, policyFlags);
+ /**
+ * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering
+ * the app ID required for reconcile.
+ * @return {@code true} if a new app ID was registered and will need to be cleaned up on
+ * failure.
+ */
+ private boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
+ throws PackageManagerException {
+ if (!result.existingSettingCopied) {
+ // THROWS: when we can't allocate a user id. add call to check if there's
+ // enough space to ensure we won't throw; otherwise, don't modify state
+ return mSettings.registerAppIdLPw(result.pkgSetting);
+ }
+ return false;
+ }
- assertPackageIsValid(pkg, policyFlags, scanFlags);
+ /**
+ * Reverts any app ID creation that were made by
+ * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the
+ * referenced method returned true.
+ */
+ private void cleanUpAppIdCreation(@NonNull ScanResult result) {
+ // iff we've acquired an app ID for a new package setting, remove it so that it can be
+ // acquired by another request.
+ if (result.pkgSetting.appId > 0) {
+ mSettings.removeAppIdLPw(result.pkgSetting.appId);
+ }
+ }
- // Initialize package source and resource directories
- final File scanFile = new File(pkg.codePath);
- final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
- final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
+ /**
+ * Commits the package scan and modifies system state.
+ * <p><em>WARNING:</em> The method may throw an excpetion in the middle
+ * of committing the package, leaving the system in an inconsistent state.
+ * This needs to be fixed so, once we get to this point, no errors are
+ * possible and the system is not left in an inconsistent state.
+ */
+ @GuardedBy({"mPackages", "mInstallLock"})
+ private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
+ final ScanResult result = reconciledPkg.scanResult;
+ final ScanRequest request = result.request;
+ final PackageParser.Package pkg = request.pkg;
+ final PackageParser.Package oldPkg = request.oldPkg;
+ final @ParseFlags int parseFlags = request.parseFlags;
+ final @ScanFlags int scanFlags = request.scanFlags;
+ final PackageSetting oldPkgSetting = request.oldPkgSetting;
+ final PackageSetting originalPkgSetting = request.originalPkgSetting;
+ final UserHandle user = request.user;
+ final String realPkgName = request.realPkgName;
+ final List<String> changedAbiCodePath = result.changedAbiCodePath;
+ final PackageSetting pkgSetting;
+ if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
+ && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+ // shared user changed, remove from old shared user
+ request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+ }
+ if (result.existingSettingCopied) {
+ pkgSetting = request.pkgSetting;
+ pkgSetting.updateFrom(result.pkgSetting);
+ pkg.mExtras = pkgSetting;
+ } else {
+ pkgSetting = result.pkgSetting;
+ if (originalPkgSetting != null) {
+ mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
+ }
+ if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
+ mTransferedPackages.add(originalPkgSetting.name);
+ }
+ }
+ if (pkgSetting.sharedUser != null) {
+ pkgSetting.sharedUser.addPackage(pkgSetting);
+ }
+ // TODO(toddke): Consider a method specifically for modifying the Package object
+ // post scan; or, moving this stuff out of the Package object since it has nothing
+ // to do with the package on disk.
+ // We need to have this here because addUserToSettingLPw() is sometimes responsible
+ // for creating the application ID. If we did this earlier, we would be saving the
+ // correct ID.
+ pkg.applicationInfo.uid = pkgSetting.appId;
- SharedUserSetting suid = null;
- PackageSetting pkgSetting = null;
+ mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
- // Getting the package setting may have a side-effect, so if we
- // are only checking if scan would succeed, stash a copy of the
- // old setting to restore at the end.
- PackageSetting nonMutatedPs = null;
+ if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
+ mTransferedPackages.add(pkg.packageName);
+ }
- // We keep references to the derived CPU Abis from settings in oder to reuse
- // them in the case where we're not upgrading or booting for the first time.
- String primaryCpuAbiFromSettings = null;
- String secondaryCpuAbiFromSettings = null;
+ if (reconciledPkg.collectedSharedLibraryInfos != null) {
+ executeSharedLibrariesUpdateLPr(pkg, null, reconciledPkg.collectedSharedLibraryInfos);
+ }
- final PackageParser.Package oldPkg;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (reconciledPkg.removeAppKeySetData) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ if (reconciledPkg.sharedUserSignaturesChanged) {
+ pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
+ pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;
+ }
+ pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
- // writer
- synchronized (mPackages) {
- if (pkg.mSharedUserId != null) {
- // SIDE EFFECTS; may potentially allocate a new shared user
- suid = mSettings.getSharedUserLPw(
- pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
- if (DEBUG_PACKAGE_SCANNING) {
- if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
- Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
- + "): packages=" + suid.packages);
- }
- }
-
- // Check if we are renaming from an original package name.
- PackageSetting origPackage = null;
- String realName = null;
- if (pkg.mOriginalPackages != null) {
- // This package may need to be renamed to a previously
- // installed name. Let's check on that...
- final String renamed = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
- if (pkg.mOriginalPackages.contains(renamed)) {
- // This package had originally been installed as the
- // original name, and we have already taken care of
- // transitioning to the new one. Just update the new
- // one to continue using the old name.
- realName = pkg.mRealPackage;
- if (!pkg.packageName.equals(renamed)) {
- // Callers into this function may have already taken
- // care of renaming the package; only do it here if
- // it is not already done.
- pkg.setPackageName(renamed);
- }
- } else {
- for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
- if ((origPackage = mSettings.getPackageLPr(
- pkg.mOriginalPackages.get(i))) != null) {
- // We do have the package already installed under its
- // original name... should we use it?
- if (!verifyPackageUpdateLPr(origPackage, pkg)) {
- // New package is not compatible with original.
- origPackage = null;
- continue;
- } else if (origPackage.sharedUser != null) {
- // Make sure uid is compatible between packages.
- if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
- Slog.w(TAG, "Unable to migrate data from " + origPackage.name
- + " to " + pkg.packageName + ": old uid "
- + origPackage.sharedUser.name
- + " differs from " + pkg.mSharedUserId);
- origPackage = null;
- continue;
- }
- // TODO: Add case when shared user id is added [b/28144775]
- } else {
- if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
- + pkg.packageName + " to old name " + origPackage.name);
- }
- break;
- }
+ if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
+ // This package wants to adopt ownership of permissions from
+ // another package.
+ for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
+ final String origName = pkg.mAdoptPermissions.get(i);
+ final PackageSetting orig = mSettings.getPackageLPr(origName);
+ if (orig != null) {
+ if (verifyPackageUpdateLPr(orig, pkg)) {
+ Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ + pkg.packageName);
+ mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
}
}
}
+ }
- if (mTransferedPackages.contains(pkg.packageName)) {
- Slog.w(TAG, "Package " + pkg.packageName
- + " was transferred to another, but its .apk remains");
- }
-
- // See comments in nonMutatedPs declaration
- if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
- if (foundPs != null) {
- nonMutatedPs = new PackageSetting(foundPs);
+ 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) {
}
}
+ }
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {
- PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
- if (foundPs != null) {
- primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
- secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
+ if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
+ if (oldPkgSetting != null) {
+ synchronized (mPackages) {
+ mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
}
}
-
- pkgSetting = mSettings.getPackageLPr(pkg.packageName);
- if (pkgSetting != null && pkgSetting.sharedUser != suid) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + pkg.packageName + " shared user changed from "
- + (pkgSetting.sharedUser != null
- ? pkgSetting.sharedUser.name : "<nothing>")
- + " to "
- + (suid != null ? suid.name : "<nothing>")
- + "; replacing with new");
- pkgSetting = null;
+ } else {
+ final int userId = user == null ? 0 : user.getIdentifier();
+ // Modify state for the given package setting
+ commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
+ (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
+ if (pkgSetting.getInstantApp(userId)) {
+ mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
- final PackageSetting oldPkgSetting =
- pkgSetting == null ? null : new PackageSetting(pkgSetting);
- final PackageSetting disabledPkgSetting =
- mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+ }
+ }
- if (oldPkgSetting == null) {
- oldPkg = null;
- } else {
- oldPkg = oldPkgSetting.pkg;
- }
+ /**
+ * Returns the "real" name of the package.
+ * <p>This may differ from the package's actual name if the application has already
+ * been installed under one of this package's original names.
+ */
+ private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
+ @Nullable String renamedPkgName) {
+ if (isPackageRenamed(pkg, renamedPkgName)) {
+ return pkg.mRealPackage;
+ }
+ return null;
+ }
- String[] usesStaticLibraries = null;
- if (pkg.usesStaticLibraries != null) {
- usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
- pkg.usesStaticLibraries.toArray(usesStaticLibraries);
- }
+ /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
+ private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+ @Nullable String renamedPkgName) {
+ return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
+ }
- if (pkgSetting == null) {
- final String parentPackageName = (pkg.parentPackage != null)
- ? pkg.parentPackage.packageName : null;
- final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
- final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
- // REMOVE SharedUserSetting from method; update in a separate call
- pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
- disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
- pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
- pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
- true /*allowInstall*/, instantApp, virtualPreload,
- parentPackageName, pkg.getChildPackageNames(),
- UserManagerService.getInstance(), usesStaticLibraries,
- pkg.usesStaticLibrariesVersions);
- // SIDE EFFECTS; updates system state; move elsewhere
- if (origPackage != null) {
- mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
- }
- mSettings.addUserToSettingLPw(pkgSetting);
- } else {
- // REMOVE SharedUserSetting from method; update in a separate call.
- //
- // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
- // secondaryCpuAbi are not known at this point so we always update them
- // to null here, only to reset them at a later point.
- Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
- pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
- pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(),
- UserManagerService.getInstance(), usesStaticLibraries,
- pkg.usesStaticLibrariesVersions);
- }
- // SIDE EFFECTS; persists system state to files on disk; move elsewhere
- mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
-
- // SIDE EFFECTS; modifies system state; move elsewhere
- if (pkgSetting.origPackage != null) {
- // If we are first transitioning from an original package,
- // fix up the new package's name now. We need to do this after
- // looking up the package under its new name, so getPackageLP
- // can take care of fiddling things correctly.
- pkg.setPackageName(origPackage.name);
-
- // File a report about this.
- String msg = "New package " + pkgSetting.realName
- + " renamed to replace old package " + pkgSetting.name;
- reportSettingsProblem(Log.WARN, msg);
-
- // Make a note of it.
- if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
- mTransferedPackages.add(origPackage.name);
+ /**
+ * Returns the original package setting.
+ * <p>A package can migrate its name during an update. In this scenario, a package
+ * designates a set of names that it considers as one of its original names.
+ * <p>An original package must be signed identically and it must have the same
+ * shared user [if any].
+ */
+ @GuardedBy("mPackages")
+ private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
+ @Nullable String renamedPkgName) {
+ if (!isPackageRenamed(pkg, renamedPkgName)) {
+ return null;
+ }
+ for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
+ final PackageSetting originalPs =
+ mSettings.getPackageLPr(pkg.mOriginalPackages.get(i));
+ if (originalPs != null) {
+ // the package is already installed under its original name...
+ // but, should we use it?
+ if (!verifyPackageUpdateLPr(originalPs, pkg)) {
+ // the new package is incompatible with the original
+ continue;
+ } else if (originalPs.sharedUser != null) {
+ if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) {
+ // the shared user id is incompatible with the original
+ Slog.w(TAG, "Unable to migrate data from " + originalPs.name
+ + " to " + pkg.packageName + ": old uid "
+ + originalPs.sharedUser.name
+ + " differs from " + pkg.mSharedUserId);
+ continue;
+ }
+ // TODO: Add case when shared user id is added [b/28144775]
+ } else {
+ if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ + pkg.packageName + " to old name " + originalPs.name);
}
-
- // No longer need to retain this.
- pkgSetting.origPackage = null;
- }
-
- // SIDE EFFECTS; modifies system state; move elsewhere
- if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realName != null) {
- // Make a note of it.
- mTransferedPackages.add(pkg.packageName);
- }
-
- if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ return originalPs;
}
+ }
+ return null;
+ }
- if ((scanFlags & SCAN_BOOTING) == 0
- && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- // Check all shared libraries and map to their actual file path.
- // We only do this here for apps not on a system dir, because those
- // are the only ones that can fail an install due to this. We
- // will take care of the system apps by updating all of their
- // library paths after the scan is done. Also during the initial
- // scan don't update any libs as we do this wholesale after all
- // apps are scanned to avoid dependency based scanning.
- updateSharedLibrariesLPr(pkg, null);
- }
+ /**
+ * Renames the package if it was installed under a different name.
+ * <p>When we've already installed the package under an original name, update
+ * the new package so we can continue to have the old name.
+ */
+ private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg,
+ @NonNull String renamedPackageName) {
+ if (pkg.mOriginalPackages == null
+ || !pkg.mOriginalPackages.contains(renamedPackageName)
+ || pkg.packageName.equals(renamedPackageName)) {
+ return;
+ }
+ pkg.setPackageName(renamedPackageName);
+ }
- if (mFoundPolicyFile) {
- SELinuxMMAC.assignSeInfoValue(pkg);
- }
- pkg.applicationInfo.uid = pkgSetting.appId;
- pkg.mExtras = pkgSetting;
+ /**
+ * Just scans the package without any side effects.
+ * <p>Not entirely true at the moment. There is still one side effect -- this
+ * method potentially modifies a live {@link PackageSetting} object representing
+ * the package being scanned. This will be resolved in the future.
+ *
+ * @param request Information about the package to be scanned
+ * @param isUnderFactoryTest Whether or not the device is under factory test
+ * @param currentTime The current time, in millis
+ * @return The results of the scan
+ */
+ @GuardedBy("mInstallLock")
+ private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ boolean isUnderFactoryTest, long currentTime)
+ throws PackageManagerException {
+ final PackageParser.Package pkg = request.pkg;
+ PackageSetting pkgSetting = request.pkgSetting;
+ final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
+ final PackageSetting originalPkgSetting = request.originalPkgSetting;
+ final @ParseFlags int parseFlags = request.parseFlags;
+ final @ScanFlags int scanFlags = request.scanFlags;
+ final String realPkgName = request.realPkgName;
+ final SharedUserSetting sharedUserSetting = request.sharedUserSetting;
+ final UserHandle user = request.user;
+ final boolean isPlatformPackage = request.isPlatformPackage;
+
+ List<String> changedAbiCodePath = null;
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.d(TAG, "Scanning package " + pkg.packageName);
+ }
- // Static shared libs have same package with different versions where
- // we internally use a synthetic package name to allow multiple versions
- // of the same package, therefore we need to compare signatures against
- // the package setting for the latest library version.
- PackageSetting signatureCheckPs = pkgSetting;
- if (pkg.applicationInfo.isStaticSharedLibrary()) {
- SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
- if (libraryEntry != null) {
- signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
- }
- }
+ // Initialize package source and resource directories
+ final File scanFile = new File(pkg.codePath);
+ final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
+ final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
- // We just determined the app is signed correctly, so bring
- // over the latest parsed certs.
- pkgSetting.signatures.mSignatures = pkg.mSignatures;
- } else {
- if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "Package " + pkg.packageName + " upgrade keys do not match the "
- + "previously installed version");
- } else {
- pkgSetting.signatures.mSignatures = pkg.mSignatures;
- String msg = "System package " + pkg.packageName
- + " signature changed; retaining data.";
- reportSettingsProblem(Log.WARN, msg);
- }
- }
+ // We keep references to the derived CPU Abis from settings in oder to reuse
+ // them in the case where we're not upgrading or booting for the first time.
+ String primaryCpuAbiFromSettings = null;
+ String secondaryCpuAbiFromSettings = null;
+ boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
+ if (!needToDeriveAbi) {
+ if (pkgSetting != null) {
+ primaryCpuAbiFromSettings = pkgSetting.primaryCpuAbiString;
+ secondaryCpuAbiFromSettings = pkgSetting.secondaryCpuAbiString;
} else {
- try {
- // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
- verifySignaturesLP(signatureCheckPs, pkg);
- // We just determined the app is signed correctly, so bring
- // over the latest parsed certs.
- pkgSetting.signatures.mSignatures = pkg.mSignatures;
- } catch (PackageManagerException e) {
- if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- throw e;
- }
- // The signature has changed, but this package is in the system
- // image... let's recover!
- pkgSetting.signatures.mSignatures = pkg.mSignatures;
- // However... if this package is part of a shared user, but it
- // doesn't match the signature of the shared user, let's fail.
- // What this means is that you can't change the signatures
- // associated with an overall shared user, which doesn't seem all
- // that unreasonable.
- if (signatureCheckPs.sharedUser != null) {
- if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures,
- pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
- throw new PackageManagerException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Signature mismatch for shared user: "
- + pkgSetting.sharedUser);
- }
- }
- // File a report about this.
- String msg = "System package " + pkg.packageName
- + " signature changed; retaining data.";
- reportSettingsProblem(Log.WARN, msg);
- }
+ // Re-scanning a system package after uninstalling updates; need to derive ABI
+ needToDeriveAbi = true;
}
+ }
- if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
- // This package wants to adopt ownership of permissions from
- // another package.
- for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
- final String origName = pkg.mAdoptPermissions.get(i);
- final PackageSetting orig = mSettings.getPackageLPr(origName);
- if (orig != null) {
- if (verifyPackageUpdateLPr(orig, pkg)) {
- Slog.i(TAG, "Adopting permissions from " + origName + " to "
- + pkg.packageName);
- // SIDE EFFECTS; updates permissions system state; move elsewhere
- mSettings.transferPermissionsLPw(origName, pkg.packageName);
- }
- }
- }
- }
+ if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + pkg.packageName + " shared user changed from "
+ + (pkgSetting.sharedUser != null
+ ? pkgSetting.sharedUser.name : "<nothing>")
+ + " to "
+ + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
+ + "; replacing with new");
+ pkgSetting = null;
}
+ String[] usesStaticLibraries = null;
+ if (pkg.usesStaticLibraries != null) {
+ usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
+ pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+ }
+ final boolean createNewPackage = (pkgSetting == null);
+ if (createNewPackage) {
+ final String parentPackageName = (pkg.parentPackage != null)
+ ? pkg.parentPackage.packageName : null;
+ final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+ final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
+ // REMOVE SharedUserSetting from method; update in a separate call
+ pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
+ disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
+ destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
+ pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
+ pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+ user, true /*allowInstall*/, instantApp, virtualPreload,
+ parentPackageName, pkg.getChildPackageNames(),
+ UserManagerService.getInstance(), usesStaticLibraries,
+ pkg.usesStaticLibrariesVersions);
+ } else {
+ // make a deep copy to avoid modifying any existing system state.
+ pkgSetting = new PackageSetting(pkgSetting);
+ pkgSetting.pkg = pkg;
+
+ // REMOVE SharedUserSetting from method; update in a separate call.
+ //
+ // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
+ // secondaryCpuAbi are not known at this point so we always update them
+ // to null here, only to reset them at a later point.
+ Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
+ destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
+ pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
+ pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+ pkg.getChildPackageNames(), UserManagerService.getInstance(),
+ usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+ }
+ if (createNewPackage && originalPkgSetting != null) {
+ // This is the initial transition from the original package, so,
+ // fix up the new package's name now. We must do this after looking
+ // up the package under its new name, so getPackageLP takes care of
+ // fiddling things correctly.
+ pkg.setPackageName(originalPkgSetting.name);
+
+ // File a report about this.
+ String msg = "New package " + pkgSetting.realName
+ + " renamed to replace old package " + pkgSetting.name;
+ reportSettingsProblem(Log.WARN, msg);
+ }
+
+ final int userId = (user == null ? UserHandle.USER_SYSTEM : user.getIdentifier());
+ // for existing packages, change the install state; but, only if it's explicitly specified
+ if (!createNewPackage) {
+ final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+ final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
+ setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ }
+ // TODO(patb): see if we can do away with disabled check here.
+ if (disabledPkgSetting != null
+ || (0 != (scanFlags & SCAN_NEW_INSTALL)
+ && pkgSetting != null && pkgSetting.isSystem())) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+
+ // Apps which share a sharedUserId must be placed in the same selinux domain. If this
+ // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
+ // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be
+ // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the
+ // least restrictive selinux domain.
+ // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion
+ // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
+ // ensures that all packages continue to run in the same selinux domain.
+ final int targetSdkVersion =
+ ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
+ sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion;
+ // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
+ // They currently can be if the sharedUser apps are signed with the platform key.
+ final boolean isPrivileged = (sharedUserSetting != null) ?
+ sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
+
+ pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ pkg.applicationInfo.targetSandboxVersion, targetSdkVersion);
+ pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
+ userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
+
+ pkg.mExtras = pkgSetting;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName);
- if (pkg != mPlatformPackage) {
+ if (!isPlatformPackage) {
// Get all of our default paths setup
pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
}
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+ if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs,
- mAppLib32InstallDir);
+ derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+ setNativeLibraryPaths(pkg, sAppLib32InstallDir);
}
} else {
// This is not a first boot or an upgrade, don't bother deriving the
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
- setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+ setNativeLibraryPaths(pkg, sAppLib32InstallDir);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
- pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
- pkg.applicationInfo.secondaryCpuAbi);
+ pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
+ pkg.applicationInfo.secondaryCpuAbi);
}
}
} else {
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+ setNativeLibraryPaths(pkg, sAppLib32InstallDir);
}
// This is a special case for the "system" package, where the ABI is
// dictated by the zygote configuration (and init.rc). We should keep track
// of this ABI so that we can deal with "normal" applications that run under
// the same UID correctly.
- if (mPlatformPackage == pkg) {
+ if (isPlatformPackage) {
pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
}
// would've already compiled the app without taking the package setting into
// account.
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
- if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
+ if (cpuAbiOverride == null && pkg.packageName != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
" for package " + pkg.packageName);
}
pkg.cpuAbiOverride = cpuAbiOverride;
if (DEBUG_ABI_SELECTION) {
- Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.applicationInfo.packageName
+ Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
+ " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
+ pkg.applicationInfo.nativeLibraryRootRequiresIsa);
}
" secondary=" + pkg.applicationInfo.secondaryCpuAbi);
}
- // SIDE EFFECTS; removes DEX files from disk; move elsewhere
if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+ changedAbiCodePath =
+ adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
}
- if (mFactoryTest && pkg.requestedPermissions.contains(
+ if (isUnderFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
}
// Take care of first install / last update times.
- final long scanFileTime = getLastModifiedTime(pkg, scanFile);
+ final long scanFileTime = getLastModifiedTime(pkg);
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
} else if (pkgSetting.firstInstallTime == 0) {
// We need *something*. Take time time stamp of the file.
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
- } else if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ } else if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
if (scanFileTime != pkgSetting.timeStamp) {
// A package on the system image has changed; consider this
// to be an update.
}
pkgSetting.setTimeStamp(scanFileTime);
- if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- if (nonMutatedPs != null) {
- synchronized (mPackages) {
- mSettings.mPackages.put(nonMutatedPs.name, nonMutatedPs);
- }
- }
- } else {
- final int userId = user == null ? 0 : user.getIdentifier();
- // Modify state for the given package setting
- commitPackageSettings(pkg, pkgSetting, user, scanFlags,
- (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
- if (pkgSetting.getInstantApp(userId)) {
- mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
+ pkgSetting.pkg = pkg;
+ pkgSetting.pkgFlags = pkg.applicationInfo.flags;
+ if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
+ pkgSetting.versionCode = pkg.getLongVersionCode();
+ }
+ // Update volume if needed
+ final String volumeUuid = pkg.applicationInfo.volumeUuid;
+ if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
+ Slog.i(PackageManagerService.TAG,
+ "Update" + (pkgSetting.isSystem() ? " system" : "")
+ + " package " + pkg.packageName
+ + " volume from " + pkgSetting.volumeUuid
+ + " to " + volumeUuid);
+ pkgSetting.volumeUuid = volumeUuid;
+ }
+
+ SharedLibraryInfo staticSharedLibraryInfo = null;
+ if (!TextUtils.isEmpty(pkg.staticSharedLibName)) {
+ staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg);
+ }
+ List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
+ if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
+ dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size());
+ for (String name : pkg.libraryNames) {
+ dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name));
}
}
- if (oldPkg != null) {
- // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
- // revokation from this method might need to kill apps which need the
- // mPackages lock on a different thread. This would dead lock.
- //
- // Hence create a copy of all package names and pass it into
- // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
- // revoked. If a new package is added before the async code runs the permission
- // won't be granted yet, hence new packages are no problem.
- final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+ return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
+ !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo,
+ dynamicSharedLibraryInfos);
+ }
- AsyncTask.execute(new Runnable() {
- public void run() {
- revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames);
+ /**
+ * Returns {@code true} if the given file contains code. Otherwise {@code false}.
+ */
+ private static boolean apkHasCode(String fileName) {
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(fileName,
+ false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
+ return jarFile.findEntry("classes.dex") != null;
+ } catch (IOException ignore) {
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
}
- });
+ } catch (IOException ignore) {}
}
+ return false;
+ }
- return pkg;
+ /**
+ * Enforces code policy for the package. This ensures that if an APK has
+ * declared hasCode="true" in its manifest that the APK actually contains
+ * code.
+ *
+ * @throws PackageManagerException If bytecode could not be found when it should exist
+ */
+ private static void assertCodePolicy(PackageParser.Package pkg)
+ throws PackageManagerException {
+ final boolean shouldHaveCode =
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Package " + pkg.baseCodePath + " code is missing");
+ }
+
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ final boolean splitShouldHaveCode =
+ (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Package " + pkg.splitCodePaths[i] + " code is missing");
+ }
+ }
+ }
}
/**
* Implementation detail: This method must NOT have any side effect. It would
* ideally be static, but, it requires locks to read system state.
*/
- private void applyPolicy(PackageParser.Package pkg, int policyFlags) {
- if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+ private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags,
+ final @ScanFlags int scanFlags, PackageParser.Package platformPkg) {
+ if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
if (pkg.applicationInfo.isDirectBootAware()) {
// we're direct boot aware; set for all components
pkg.isStub = true;
}
} else {
- // Only allow system apps to be flagged as core apps.
+ // non system apps can't be flagged as core
pkg.coreApp = false;
// clear flags not applicable to regular apps
+ pkg.applicationInfo.flags &=
+ ~ApplicationInfo.FLAG_PERSISTENT;
pkg.applicationInfo.privateFlags &=
~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
pkg.applicationInfo.privateFlags &=
~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+ // cap permission priorities
+ if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
+ for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
+ pkg.permissionGroups.get(i).info.priority = 0;
+ }
+ }
+ }
+ if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
+ // clear protected broadcasts
+ pkg.protectedBroadcasts = null;
+ // ignore export request for single user receivers
+ if (pkg.receivers != null) {
+ for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
+ final PackageParser.Activity receiver = pkg.receivers.get(i);
+ if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+ receiver.info.exported = false;
+ }
+ }
+ }
+ // ignore export request for single user services
+ if (pkg.services != null) {
+ for (int i = pkg.services.size() - 1; i >= 0; --i) {
+ final PackageParser.Service service = pkg.services.get(i);
+ if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
+ service.info.exported = false;
+ }
+ }
+ }
+ // ignore export request for single user providers
+ if (pkg.providers != null) {
+ for (int i = pkg.providers.size() - 1; i >= 0; --i) {
+ final PackageParser.Provider provider = pkg.providers.get(i);
+ if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
+ provider.info.exported = false;
+ }
+ }
+ }
}
- pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
- if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
+ if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
+ if ((scanFlags & SCAN_AS_OEM) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
+ }
+
+ if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
+ }
+
+ if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+ }
+
+ if ((scanFlags & SCAN_AS_PRODUCT_SERVICES) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
+ }
+
+ if ((scanFlags & SCAN_AS_ODM) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
+ }
+
+ // Check if the package is signed with the same key as the platform package.
+ if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
+ (platformPkg != null && compareSignatures(
+ platformPkg.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) {
+ pkg.applicationInfo.privateFlags |=
+ ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
+ }
+
if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
+
+ PackageBackwardCompatibility.modifySharedLibraries(pkg);
+ }
+
+ private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
+ throws PackageManagerException {
+ if (object == null) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, message);
+ }
+ return object;
}
/**
*
* @throws PackageManagerException If the package fails any of the validation checks
*/
- private void assertPackageIsValid(PackageParser.Package pkg, int policyFlags, int scanFlags)
- throws PackageManagerException {
- if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
+ private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags,
+ final @ScanFlags int scanFlags)
+ throws PackageManagerException {
+ if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
assertCodePolicy(pkg);
}
"Code and resource paths haven't been set correctly");
}
+ // Check that there is an APEX package with the same name only during install/first boot
+ // after OTA.
+ final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
+ final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
+ if ((isUserInstall || isFirstBootOrUpgrade)
+ && mApexManager.isApexPackage(pkg.packageName)) {
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ pkg.packageName + " is an APEX package and can't be installed as an APK.");
+ }
+
// Make sure we're not adding any bogus keyset info
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
synchronized (mPackages) {
}
// A package name must be unique; don't allow duplicates
- if (mPackages.containsKey(pkg.packageName)) {
+ if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Application package " + pkg.packageName
+ " already installed. Skipping duplicate.");
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// but we still want the base name to be unique.
- if (mPackages.containsKey(pkg.manifestPackageName)) {
+ if ((scanFlags & SCAN_NEW_INSTALL) == 0
+ && mPackages.containsKey(pkg.manifestPackageName)) {
throw new PackageManagerException(
"Duplicate static shared lib provider package");
}
}
// The version codes must be ordered as lib versions
- int minVersionCode = Integer.MIN_VALUE;
- int maxVersionCode = Integer.MAX_VALUE;
+ long minVersionCode = Long.MIN_VALUE;
+ long maxVersionCode = Long.MAX_VALUE;
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib != null) {
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- SharedLibraryInfo libInfo = versionedLib.valueAt(i).info;
- final int libVersionCode = libInfo.getDeclaringPackage()
- .getVersionCode();
- if (libInfo.getVersion() < pkg.staticSharedLibVersion) {
+ SharedLibraryInfo libInfo = versionedLib.valueAt(i);
+ final long libVersionCode = libInfo.getDeclaringPackage()
+ .getLongVersionCode();
+ if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) {
minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
- } else if (libInfo.getVersion() > pkg.staticSharedLibVersion) {
+ } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) {
maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
} else {
minVersionCode = maxVersionCode = libVersionCode;
}
}
}
- if (pkg.mVersionCode < minVersionCode || pkg.mVersionCode > maxVersionCode) {
+ if (pkg.getLongVersionCode() < minVersionCode
+ || pkg.getLongVersionCode() > maxVersionCode) {
throw new PackageManagerException("Static shared"
+ " lib version codes must be ordered as lib versions");
}
// Only privileged apps and updated privileged apps can add child packages.
if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
- if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) {
+ if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
throw new PackageManagerException("Only privileged apps can add child "
+ "packages. Ignoring package " + pkg.packageName);
}
// package isn't already installed, since we don't want to break
// things that are installed.
if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
- final int N = pkg.providers.size();
- int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- if (p.info.authority != null) {
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProvidersByAuthority.containsKey(names[j])) {
- PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
- final String otherPackageName =
- ((other != null && other.getComponentName() != null) ?
- other.getComponentName().getPackageName() : "?");
- throw new PackageManagerException(
- INSTALL_FAILED_CONFLICTING_PROVIDER,
- "Can't install because provider name " + names[j]
- + " (in package " + pkg.applicationInfo.packageName
- + ") is already used by " + otherPackageName);
+ mComponentResolver.assertProvidersNotDefined(pkg);
+ }
+
+ // Verify that packages sharing a user with a privileged app are marked as privileged.
+ if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) {
+ SharedUserSetting sharedUserSetting = null;
+ try {
+ sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
+ } catch (PackageManagerException ignore) {}
+ if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
+ // Exempt SharedUsers signed with the platform key.
+ PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+ if ((platformPkgSetting.signatures.mSigningDetails
+ != PackageParser.SigningDetails.UNKNOWN)
+ && (compareSignatures(
+ platformPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException("Apps that share a user with a " +
+ "privileged app must themselves be marked as privileged. " +
+ pkg.packageName + " shares privileged user " +
+ pkg.mSharedUserId + ".");
+ }
+ }
+ }
+
+ // Apply policies specific for runtime resource overlays (RROs).
+ if (pkg.mOverlayTarget != null) {
+ // System overlays have some restrictions on their use of the 'static' state.
+ if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
+ // We are scanning a system overlay. This can be the first scan of the
+ // system/vendor/oem partition, or an update to the system overlay.
+ if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ // This must be an update to a system overlay.
+ final PackageSetting previousPkg = assertNotNull(
+ mSettings.getPackageLPr(pkg.packageName),
+ "previous package state not present");
+
+ // previousPkg.pkg may be null: the package will be not be scanned if the
+ // package manager knows there is a newer version on /data.
+ // TODO[b/79435695]: Find a better way to keep track of the "static"
+ // property for RROs instead of having to parse packages on /system
+ PackageParser.Package ppkg = previousPkg.pkg;
+ if (ppkg == null) {
+ try {
+ final PackageParser pp = new PackageParser();
+ ppkg = pp.parsePackage(previousPkg.codePath,
+ parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR);
+ } catch (PackageParserException e) {
+ Slog.w(TAG, "failed to parse " + previousPkg.codePath, e);
+ }
+ }
+
+ // Static overlays cannot be updated.
+ if (ppkg != null && ppkg.mOverlayIsStatic) {
+ throw new PackageManagerException("Overlay " + pkg.packageName +
+ " is static and cannot be upgraded.");
+ // Non-static overlays cannot be converted to static overlays.
+ } else if (pkg.mOverlayIsStatic) {
+ throw new PackageManagerException("Overlay " + pkg.packageName +
+ " cannot be upgraded into a static overlay.");
+ }
+ }
+ } else {
+ // The overlay is a non-system overlay. Non-system overlays cannot be static.
+ if (pkg.mOverlayIsStatic) {
+ throw new PackageManagerException("Overlay " + pkg.packageName +
+ " is static but not pre-installed.");
+ }
+
+ // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
+ // signed with the platform certificate. Check this in increasing order of
+ // computational cost.
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ final PackageSetting platformPkgSetting =
+ mSettings.getPackageLPr("android");
+ if ((platformPkgSetting.signatures.mSigningDetails
+ != PackageParser.SigningDetails.UNKNOWN)
+ && (compareSignatures(
+ platformPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException("Overlay " + pkg.packageName
+ + " must target Q or later, "
+ + "or be signed with the platform certificate");
+ }
+ }
+
+ // A non-preloaded overlay package, without <overlay android:targetName>, will
+ // only be used if it is signed with the same certificate as its target. If the
+ // target is already installed, check this here to augment the last line of
+ // defence which is OMS.
+ if (pkg.mOverlayTargetName == null) {
+ final PackageSetting targetPkgSetting =
+ mSettings.getPackageLPr(pkg.mOverlayTarget);
+ if (targetPkgSetting != null) {
+ if ((targetPkgSetting.signatures.mSigningDetails
+ != PackageParser.SigningDetails.UNKNOWN)
+ && (compareSignatures(
+ targetPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException("Overlay " + pkg.packageName
+ + " and target " + pkg.mOverlayTarget + " signed with"
+ + " different certificates, and the overlay lacks"
+ + " <overlay android:targetName>");
}
}
}
}
}
- private boolean addSharedLibraryLPw(String path, String apk, String name, int version,
- int type, String declaringPackageName, int declaringVersionCode) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
- if (versionedLib == null) {
- versionedLib = new SparseArray<>();
- mSharedLibraries.put(name, versionedLib);
- if (type == SharedLibraryInfo.TYPE_STATIC) {
- mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
- }
- } else if (versionedLib.indexOfKey(version) >= 0) {
+ @GuardedBy("mPackages")
+ private boolean addBuiltInSharedLibraryLocked(String path, String name) {
+ if (nonStaticSharedLibExistsLocked(name)) {
return false;
}
- SharedLibraryEntry libEntry = new SharedLibraryEntry(path, apk, name,
- version, type, declaringPackageName, declaringVersionCode);
- versionedLib.put(version, libEntry);
+
+ SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, null, null, name,
+ (long) SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN,
+ new VersionedPackage(PLATFORM_PACKAGE_NAME, (long) 0),
+ null, null);
+
+ commitSharedLibraryInfoLocked(libraryInfo);
return true;
}
- private boolean removeSharedLibraryLPw(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ @GuardedBy("mPackages")
+ private boolean nonStaticSharedLibExistsLocked(String name) {
+ return sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED, mSharedLibraries);
+ }
+
+ private static boolean sharedLibExists(final String name, final long version,
+ Map<String, LongSparseArray<SharedLibraryInfo>> librarySource) {
+ LongSparseArray<SharedLibraryInfo> versionedLib = librarySource.get(name);
+ if (versionedLib != null && versionedLib.indexOfKey(version) >= 0) {
+ return true;
+ }
+ return false;
+ }
+
+ @GuardedBy("mPackages")
+ private void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) {
+ final String name = libraryInfo.getName();
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
+ if (versionedLib == null) {
+ versionedLib = new LongSparseArray<>();
+ mSharedLibraries.put(name, versionedLib);
+ }
+ final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
+ if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+ mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
+ }
+ versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
+ }
+
+ private boolean removeSharedLibraryLPw(String name, long version) {
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
return false;
}
if (libIdx < 0) {
return false;
}
- SharedLibraryEntry libEntry = versionedLib.valueAt(libIdx);
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
versionedLib.remove(version);
if (versionedLib.size() <= 0) {
mSharedLibraries.remove(name);
- if (libEntry.info.getType() == SharedLibraryInfo.TYPE_STATIC) {
- mStaticLibsByDeclaringPackage.remove(libEntry.info.getDeclaringPackage()
+ if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+ mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
.getPackageName());
}
}
* Adds a scanned package to the system. When this method is finished, the package will
* be available for query, resolution, etc...
*/
- private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
- UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
+ private void commitPackageSettings(PackageParser.Package pkg,
+ @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
+ final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
final String pkgName = pkg.packageName;
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
+ pkg.mVersionCodeMajor = 0;
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
ArrayList<PackageParser.Package> clientLibPkgs = null;
// writer
synchronized (mPackages) {
- boolean hasStaticSharedLibs = false;
-
- // Any app can add new static shared libraries
- if (pkg.staticSharedLibName != null) {
- // Static shared libs don't allow renaming as they have synthetic package
- // names to allow install of multiple versions, so use name from manifest.
- if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
- pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
- pkg.manifestPackageName, pkg.mVersionCode)) {
- hasStaticSharedLibs = true;
- } else {
- Slog.w(TAG, "Package " + pkg.packageName + " library "
- + pkg.staticSharedLibName + " already exists; skipping");
- }
- // Static shared libs cannot be updated once installed since they
- // use synthetic package name which includes the version code, so
- // not need to update other packages's shared lib dependencies.
- }
-
- if (!hasStaticSharedLibs
- && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- // Only system apps can add new dynamic shared libraries.
- if (pkg.libraryNames != null) {
- for (int i = 0; i < pkg.libraryNames.size(); i++) {
- String name = pkg.libraryNames.get(i);
- boolean allowed = false;
- if (pkg.isUpdatedSystemApp()) {
- // New library entries can only be added through the
- // system image. This is important to get rid of a lot
- // of nasty edge cases: for example if we allowed a non-
- // system update of the app to add a library, then uninstalling
- // the update would make the library go away, and assumptions
- // we made such as through app install filtering would now
- // have allowed apps on the device which aren't compatible
- // with it. Better to just have the restriction here, be
- // conservative, and create many fewer cases that can negatively
- // impact the user experience.
- final PackageSetting sysPs = mSettings
- .getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
- for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) {
- if (name.equals(sysPs.pkg.libraryNames.get(j))) {
- allowed = true;
- break;
- }
- }
- }
- } else {
- allowed = true;
- }
- if (allowed) {
- if (!addSharedLibraryLPw(null, pkg.packageName, name,
- SharedLibraryInfo.VERSION_UNDEFINED,
- SharedLibraryInfo.TYPE_DYNAMIC,
- pkg.packageName, pkg.mVersionCode)) {
- Slog.w(TAG, "Package " + pkg.packageName + " library "
- + name + " already exists; skipping");
- }
- } else {
- Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
- + name + " that is not declared on system image; skipping");
- }
- }
-
- if ((scanFlags & SCAN_BOOTING) == 0) {
- // If we are not booting, we need to update any applications
- // that are clients of our shared library. If we are booting,
- // this will all be done once the scan is complete.
- clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
- }
+ if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
+ for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
+ commitSharedLibraryInfoLocked(info);
+ }
+ final Map<String, PackageParser.Package> combinedPackages =
+ reconciledPkg.getCombinedPackages();
+ try {
+ // Shared libraries for the package need to be updated.
+ updateSharedLibrariesLocked(pkg, null, combinedPackages);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
+ }
+ // Update all applications that use this library. Skip when booting
+ // since this will be done after all packages are scaned.
+ if ((scanFlags & SCAN_BOOTING) == 0) {
+ clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
}
}
}
+ if (reconciledPkg.installResult != null) {
+ reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
+ }
if ((scanFlags & SCAN_BOOTING) != 0) {
// No apps can run during boot scan, so they don't need to be frozen
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
- // Make sure we don't accidentally delete its data.
- final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
- while (iter.hasNext()) {
- PackageCleanItem item = iter.next();
- if (pkgName.equals(item.packageName)) {
- iter.remove();
- }
- }
// Add the package's KeySets to the global KeySetManagerService
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.addScannedPackageLPw(pkg);
- int N = pkg.providers.size();
- StringBuilder r = null;
- int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- p.info.processName = fixProcessName(pkg.applicationInfo.processName,
- p.info.processName);
- mProviders.addProvider(p);
- p.syncable = p.info.isSyncable;
- if (p.info.authority != null) {
- String names[] = p.info.authority.split(";");
- p.info.authority = null;
- for (int j = 0; j < names.length; j++) {
- if (j == 1 && p.syncable) {
- // We only want the first authority for a provider to possibly be
- // syncable, so if we already added this provider using a different
- // authority clear the syncable flag. We copy the provider before
- // changing it because the mProviders object contains a reference
- // to a provider that we don't want to change.
- // Only do this for the second authority since the resulting provider
- // object can be the same for all future authorities for this provider.
- p = new PackageParser.Provider(p);
- p.syncable = false;
- }
- if (!mProvidersByAuthority.containsKey(names[j])) {
- mProvidersByAuthority.put(names[j], p);
- if (p.info.authority == null) {
- p.info.authority = names[j];
- } else {
- p.info.authority = p.info.authority + ";" + names[j];
- }
- if (DEBUG_PACKAGE_SCANNING) {
- if (chatty)
- Log.d(TAG, "Registered content provider: " + names[j]
- + ", className = " + p.info.name + ", isSyncable = "
- + p.info.isSyncable);
- }
- } else {
- PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
- Slog.w(TAG, "Skipping provider name " + names[j] +
- " (in package " + pkg.applicationInfo.packageName +
- "): name already used by "
- + ((other != null && other.getComponentName() != null)
- ? other.getComponentName().getPackageName() : "?"));
- }
- }
- }
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
- }
-
- N = pkg.services.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Service s = pkg.services.get(i);
- s.info.processName = fixProcessName(pkg.applicationInfo.processName,
- s.info.processName);
- mServices.addService(s);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(s.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
- }
-
- N = pkg.receivers.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
- a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName);
- mReceivers.addActivity(a, "receiver");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
- }
-
- N = pkg.activities.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName);
- mActivities.addActivity(a, "activity");
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r);
- }
-
- N = pkg.permissionGroups.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
- PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
- final String curPackageName = cur == null ? null : cur.info.packageName;
- // Dont allow ephemeral apps to define new permission groups.
- if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
- Slog.w(TAG, "Permission group " + pg.info.name + " from package "
- + pg.info.packageName
- + " ignored: instant apps cannot define new permission groups.");
- continue;
- }
- final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
- if (cur == null || isPackageUpdate) {
- mPermissionGroups.put(pg.info.name, pg);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- if (isPackageUpdate) {
- r.append("UPD:");
- }
- r.append(pg.info.name);
- }
- } else {
- Slog.w(TAG, "Permission group " + pg.info.name + " from package "
- + pg.info.packageName + " ignored: original from "
- + cur.info.packageName);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append("DUP:");
- r.append(pg.info.name);
- }
- }
- }
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r);
- }
-
- N = pkg.permissions.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
-
- // Dont allow ephemeral apps to define new permissions.
- if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName
- + " ignored: instant apps cannot define new permissions.");
- continue;
- }
-
- // Assume by default that we did not install this permission into the system.
- p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
-
- // Now that permission groups have a special meaning, we ignore permission
- // groups for legacy apps to prevent unexpected behavior. In particular,
- // permissions for one app being granted to someone just because they happen
- // to be in a group defined by another app (before this had no implications).
- if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
- p.group = mPermissionGroups.get(p.info.group);
- // Warn for a permission in an unknown group.
- if (DEBUG_PERMISSIONS && p.info.group != null && p.group == null) {
- Slog.i(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " in an unknown group " + p.info.group);
- }
- }
-
- ArrayMap<String, BasePermission> permissionMap =
- p.tree ? mSettings.mPermissionTrees
- : mSettings.mPermissions;
- BasePermission bp = permissionMap.get(p.info.name);
-
- // Allow system apps to redefine non-system permissions
- if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
- final boolean currentOwnerIsSystem = (bp.perm != null
- && isSystemApp(bp.perm.owner));
- if (isSystemApp(p.owner)) {
- if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
- // It's a built-in permission and no owner, take ownership now
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- } else if (!currentOwnerIsSystem) {
- String msg = "New decl " + p.owner + " of permission "
- + p.info.name + " is system; overriding " + bp.sourcePackage;
- reportSettingsProblem(Log.WARN, msg);
- bp = null;
- }
- }
- }
-
- if (bp == null) {
- bp = new BasePermission(p.info.name, p.info.packageName,
- BasePermission.TYPE_NORMAL);
- permissionMap.put(p.info.name, bp);
- }
+ mComponentResolver.addAllComponents(pkg, chatty);
- if (bp.perm == null) {
- if (bp.sourcePackage == null
- || bp.sourcePackage.equals(p.info.packageName)) {
- BasePermission tree = findPermissionTreeLP(p.info.name);
- if (tree == null
- || tree.sourcePackage.equals(p.info.packageName)) {
- bp.packageSetting = pkgSetting;
- bp.perm = p;
- bp.uid = pkg.applicationInfo.uid;
- bp.sourcePackage = p.info.packageName;
- p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: base tree "
- + tree.name + " is from package "
- + tree.sourcePackage);
- }
- } else {
- Slog.w(TAG, "Permission " + p.info.name + " from package "
- + p.info.packageName + " ignored: original from "
- + bp.sourcePackage);
- }
- } else if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append("DUP:");
- r.append(p.info.name);
- }
- if (bp.perm == p) {
- bp.protectionLevel = p.info.protectionLevel;
- }
+ // Don't allow ephemeral applications to define new permissions groups.
+ if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
+ Slog.w(TAG, "Permission groups from package " + pkg.packageName
+ + " ignored: instant apps cannot define new permission groups.");
+ } else {
+ mPermissionManager.addAllPermissionGroups(pkg, chatty);
}
- if (r != null) {
- if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r);
+ // Don't allow ephemeral applications to define new permissions.
+ if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
+ Slog.w(TAG, "Permissions from package " + pkg.packageName
+ + " ignored: instant apps cannot define new permissions.");
+ } else {
+ mPermissionManager.addAllPermissions(pkg, chatty);
}
- N = pkg.instrumentation.size();
- r = null;
- for (i=0; i<N; i++) {
+ int collectionSize = pkg.instrumentation.size();
+ StringBuilder r = null;
+ int i;
+ for (i = 0; i < collectionSize; i++) {
PackageParser.Instrumentation a = pkg.instrumentation.get(i);
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
+ a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
+ a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
}
if (pkg.protectedBroadcasts != null) {
- N = pkg.protectedBroadcasts.size();
+ collectionSize = pkg.protectedBroadcasts.size();
synchronized (mProtectedBroadcasts) {
- for (i = 0; i < N; i++) {
+ for (i = 0; i < collectionSize; i++) {
mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}
}
}
+
+ if (oldPkg != null) {
+ // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
+ // revoke callbacks from this method might need to kill apps which need the
+ // mPackages lock on a different thread. This would dead lock.
+ //
+ // Hence create a copy of all package names and pass it into
+ // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
+ // revoked. If a new package is added before the async code runs the permission
+ // won't be granted yet, hence new packages are no problem.
+ final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+
+ AsyncTask.execute(() ->
+ mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
+ allPackageNames, mPermissionCallback));
+ }
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
*
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
- private static void derivePackageAbi(PackageParser.Package pkg, File scanFile,
- String cpuAbiOverride, boolean extractLibs,
- File appLib32InstallDir)
- throws PackageManagerException {
+ private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
+ boolean extractLibs)
+ throws PackageManagerException {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
- setNativeLibraryPaths(pkg, appLib32InstallDir);
+ setNativeLibraryPaths(pkg, sAppLib32InstallDir);
- // We would never need to extract libs for forward-locked and external packages,
- // since the container service will do it for us. We shouldn't attempt to
- // extract libs from system app when it was not updated.
- if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() ||
- (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) {
+ // We shouldn't attempt to extract libs from system app when it was not updated.
+ if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
extractLibs = false;
}
// Now that we've calculated the ABIs and determined if it's an internal app,
// we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg, appLib32InstallDir);
+ setNativeLibraryPaths(pkg, sAppLib32InstallDir);
}
/**
* NOTE: We currently only match for the primary CPU abi string. Matching the secondary
* adds unnecessary complexity.
*/
- private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
- PackageParser.Package scannedPackage) {
+ private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+ List<String> changedAbiCodePath = null;
String requiredInstructionSet = null;
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
requiredInstructionSet = VMRuntime.getInstructionSet(
+ (scannedPackage != null ? scannedPackage : "null")
+ ")");
}
- try {
- mInstaller.rmdex(ps.codePathString,
- getDexCodeInstructionSet(getPreferredInstructionSet()));
- } catch (InstallerException ignored) {
+ if (changedAbiCodePath == null) {
+ changedAbiCodePath = new ArrayList<>();
}
+ changedAbiCodePath.add(ps.codePathString);
}
}
}
}
+ return changedAbiCodePath;
}
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
private void setUpInstantAppInstallerActivityLP(ActivityInfo installerActivity) {
if (installerActivity == null) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Clear ephemeral installer activity");
}
mInstantAppInstallerActivity = null;
return;
}
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral installer activity: "
+ installerActivity.getComponentName());
}
mInstantAppInstallerActivity.exported = true;
mInstantAppInstallerActivity.enabled = true;
mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity;
- mInstantAppInstallerInfo.priority = 0;
+ mInstantAppInstallerInfo.priority = 1;
mInstantAppInstallerInfo.preferredOrder = 1;
mInstantAppInstallerInfo.isDefault = true;
mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
codeRoot = Environment.getOemDirectory();
} else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
codeRoot = Environment.getVendorDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+ codeRoot = Environment.getProductDirectory();
+ } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) {
+ codeRoot = Environment.getProductServicesDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
} else {
// Unrecognized code path; take its top real segment as the apk root:
// e.g. /something/app/blah.apk => /something
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
- final boolean asecApp = info.isForwardLocked() || info.isExternalAsec();
info.nativeLibraryRootDir = null;
info.nativeLibraryRootRequiresIsa = false;
info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
secondaryLibDir, apkName).getAbsolutePath();
}
- } else if (asecApp) {
- info.nativeLibraryRootDir = new File(codeFile.getParentFile(), LIB_DIR_NAME)
- .getAbsolutePath();
} else {
final String apkName = deriveCodePathName(codePath);
info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
// Remove the parent package setting
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps != null) {
- removePackageLI(ps, chatty);
+ removePackageLI(ps.name, chatty);
+ } else if (DEBUG_REMOVE && chatty) {
+ Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
}
// Remove the child package setting
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
PackageParser.Package childPkg = pkg.childPackages.get(i);
ps = (PackageSetting) childPkg.mExtras;
if (ps != null) {
- removePackageLI(ps, chatty);
+ removePackageLI(ps.name, chatty);
}
}
}
- void removePackageLI(PackageSetting ps, boolean chatty) {
+ void removePackageLI(String packageName, boolean chatty) {
if (DEBUG_INSTALL) {
if (chatty)
- Log.d(TAG, "Removing package " + ps.name);
+ Log.d(TAG, "Removing package " + packageName);
}
// writer
synchronized (mPackages) {
- mPackages.remove(ps.name);
- final PackageParser.Package pkg = ps.pkg;
- if (pkg != null) {
- cleanPackageDataStructuresLILPw(pkg, chatty);
+ final PackageParser.Package removedPackage = mPackages.remove(packageName);
+ if (removedPackage != null) {
+ cleanPackageDataStructuresLILPw(removedPackage, chatty);
}
}
}
}
void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
- int N = pkg.providers.size();
+ mComponentResolver.removeAllComponents(pkg, chatty);
+
+ mPermissionManager.removeAllPermissions(pkg, chatty);
+
+ final int instrumentationSize = pkg.instrumentation.size();
StringBuilder r = null;
int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- mProviders.removeProvider(p);
- if (p.info.authority == null) {
-
- /* There was another ContentProvider with this authority when
- * this app was installed so this authority is null,
- * Ignore it as we don't have to unregister the provider.
- */
- continue;
- }
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProvidersByAuthority.get(names[j]) == p) {
- mProvidersByAuthority.remove(names[j]);
- if (DEBUG_REMOVE) {
- if (chatty)
- Log.d(TAG, "Unregistered content provider: " + names[j]
- + ", className = " + p.info.name + ", isSyncable = "
- + p.info.isSyncable);
- }
- }
- }
- if (DEBUG_REMOVE && chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
- }
-
- N = pkg.services.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Service s = pkg.services.get(i);
- mServices.removeService(s);
- if (chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(s.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
- }
-
- N = pkg.receivers.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.receivers.get(i);
- mReceivers.removeActivity(a, "receiver");
- if (DEBUG_REMOVE && chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
- }
-
- N = pkg.activities.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Activity a = pkg.activities.get(i);
- mActivities.removeActivity(a, "activity");
- if (DEBUG_REMOVE && chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(a.info.name);
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
- }
-
- N = pkg.permissions.size();
- r = null;
- for (i=0; i<N; i++) {
- PackageParser.Permission p = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(p.info.name);
- if (bp == null) {
- bp = mSettings.mPermissionTrees.get(p.info.name);
- }
- if (bp != null && bp.perm == p) {
- bp.perm = null;
- if (DEBUG_REMOVE && chatty) {
- if (r == null) {
- r = new StringBuilder(256);
- } else {
- r.append(' ');
- }
- r.append(p.info.name);
- }
- }
- if ((p.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(p.info.name);
- if (appOpPkgs != null) {
- appOpPkgs.remove(pkg.packageName);
- }
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
- }
-
- N = pkg.requestedPermissions.size();
- r = null;
- for (i=0; i<N; i++) {
- String perm = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(perm);
- if (bp != null && (bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm);
- if (appOpPkgs != null) {
- appOpPkgs.remove(pkg.packageName);
- if (appOpPkgs.isEmpty()) {
- mAppOpPermissionPackages.remove(perm);
- }
- }
- }
- }
- if (r != null) {
- if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
- }
-
- N = pkg.instrumentation.size();
- r = null;
- for (i=0; i<N; i++) {
+ for (i = 0; i < instrumentationSize; i++) {
PackageParser.Instrumentation a = pkg.instrumentation.get(i);
mInstrumentation.remove(a.getComponentName());
if (DEBUG_REMOVE && chatty) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// Only system apps can hold shared libraries.
if (pkg.libraryNames != null) {
- for (i = 0; i < pkg.libraryNames.size(); i++) {
+ final int libraryNamesSize = pkg.libraryNames.size();
+ for (i = 0; i < libraryNamesSize; i++) {
String name = pkg.libraryNames.get(i);
if (removeSharedLibraryLPw(name, 0)) {
if (DEBUG_REMOVE && chatty) {
}
}
- private static boolean hasPermission(PackageParser.Package pkgInfo, String perm) {
- for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
- if (pkgInfo.permissions.get(i).info.name.equals(perm)) {
- return true;
+ @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) {
+ mHandler.post(() -> {
+ try {
+ final IActivityManager am = ActivityManager.getService();
+ if (am == null) return;
+ final int[] resolvedUserIds;
+ if (userIds == null) {
+ resolvedUserIds = am.getRunningUserIds();
+ } else {
+ resolvedUserIds = userIds;
+ }
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ resolvedUserIds, false);
+ if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
+ doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+ instantUserIds, true);
+ }
+ } catch (RemoteException ex) {
}
- }
- return false;
+ });
}
- static final int UPDATE_PERMISSIONS_ALL = 1<<0;
- static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1;
- static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2;
-
- private void updatePermissionsLPw(PackageParser.Package pkg, int flags) {
- // Update the parent permissions
- updatePermissionsLPw(pkg.packageName, pkg, flags);
- // Update the child permissions
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- updatePermissionsLPw(childPkg.packageName, childPkg, flags);
+ @Override
+ public void notifyPackageAdded(String packageName, int uid) {
+ final PackageListObserver[] observers;
+ synchronized (mPackages) {
+ 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);
}
}
- private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo,
- int flags) {
- final String volumeUuid = (pkgInfo != null) ? getVolumeUuidForPackage(pkgInfo) : null;
- updatePermissionsLPw(changingPkg, pkgInfo, volumeUuid, flags);
- }
-
- private void updatePermissionsLPw(String changingPkg,
- PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
- // Make sure there are no dangling permission trees.
- Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
- while (it.hasNext()) {
- final BasePermission bp = it.next();
- if (bp.packageSetting == null) {
- // We may not yet have parsed the package, so just see if
- // we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
- }
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
- it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission tree: " + bp.name
- + " from package " + bp.sourcePackage);
- flags |= UPDATE_PERMISSIONS_ALL;
- it.remove();
- }
- }
- }
-
- // Make sure all dynamic permissions have been assigned to a package,
- // and make sure there are no dangling permissions.
- it = mSettings.mPermissions.values().iterator();
- while (it.hasNext()) {
- final BasePermission bp = it.next();
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
- + bp.name + " pkg=" + bp.sourcePackage
- + " info=" + bp.pendingInfo);
- if (bp.packageSetting == null && bp.pendingInfo != null) {
- final BasePermission tree = findPermissionTreeLP(bp.name);
- if (tree != null && tree.perm != null) {
- bp.packageSetting = tree.packageSetting;
- bp.perm = new PackageParser.Permission(tree.perm.owner,
- new PermissionInfo(bp.pendingInfo));
- bp.perm.info.packageName = tree.perm.info.packageName;
- bp.perm.info.name = bp.name;
- bp.uid = tree.uid;
- }
- }
- }
- if (bp.packageSetting == null) {
- // We may not yet have parsed the package, so just see if
- // we still know about its settings.
- bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
- }
- if (bp.packageSetting == null) {
- Slog.w(TAG, "Removing dangling permission: " + bp.name
- + " from package " + bp.sourcePackage);
- it.remove();
- } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
- if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
- Slog.i(TAG, "Removing old permission: " + bp.name
- + " from package " + bp.sourcePackage);
- flags |= UPDATE_PERMISSIONS_ALL;
- it.remove();
- }
- }
- }
-
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
- // Now update the permissions for all packages, in particular
- // replace the granted permissions of the system packages.
- if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
- for (PackageParser.Package pkg : mPackages.values()) {
- if (pkg != pkgInfo) {
- // Only replace for packages on requested volume
- final String volumeUuid = getVolumeUuidForPackage(pkg);
- final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
- && Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissionsLPw(pkg, replace, changingPkg);
- }
+ @Override
+ public void notifyPackageChanged(String packageName, int uid) {
+ final PackageListObserver[] observers;
+ synchronized (mPackages) {
+ if (mPackageListObservers.size() == 0) {
+ return;
}
+ final PackageListObserver[] observerArray =
+ new PackageListObserver[mPackageListObservers.size()];
+ observers = mPackageListObservers.toArray(observerArray);
}
-
- if (pkgInfo != null) {
- // Only replace for packages on requested volume
- final String volumeUuid = getVolumeUuidForPackage(pkgInfo);
- final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
- && Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissionsLPw(pkgInfo, replace, changingPkg);
+ for (int i = observers.length - 1; i >= 0; --i) {
+ observers[i].onPackageChanged(packageName, uid);
}
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
- String packageOfInterest) {
- // IMPORTANT: There are two types of permissions: install and runtime.
- // Install time permissions are granted when the app is installed to
- // all device users and users added in the future. Runtime permissions
- // are granted at runtime explicitly to specific users. Normal and signature
- // protected permissions are install time permissions. Dangerous permissions
- // are install permissions if the app's target SDK is Lollipop MR1 or older,
- // otherwise they are runtime permissions. This function does not manage
- // runtime permissions except for the case an app targeting Lollipop MR1
- // being upgraded to target a newer SDK, in which case dangerous permissions
- // are transformed from install time to runtime ones.
-
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
+ 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 (mPackages) {
+ 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);
}
+ }
- PermissionsState permissionsState = ps.getPermissionsState();
- PermissionsState origPermissions = permissionsState;
+ /**
+ * Sends a broadcast for the given action.
+ * <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with
+ * the {@link android.Manifest.permission#ACCESS_INSTANT_APPS} permission. This allows
+ * the system and applications allowed to see instant applications to receive package
+ * lifecycle events for instant applications.
+ */
+ private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
+ int flags, String targetPkg, IIntentReceiver finishedReceiver,
+ int[] userIds, boolean isInstantApp)
+ throws RemoteException {
+ for (int id : userIds) {
+ final Intent intent = new Intent(action,
+ pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
+ final String[] requiredPermissions =
+ isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null;
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ if (targetPkg != null) {
+ intent.setPackage(targetPkg);
+ }
+ // Modify the UID when posting to other users
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid > 0 && UserHandle.getUserId(uid) != id) {
+ uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ }
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
+ if (DEBUG_BROADCASTS) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "Sending to user " + id + ": "
+ + intent.toShortString(false, true, false, false)
+ + " " + intent.getExtras(), here);
+ }
+ am.broadcastIntent(null, intent, null, finishedReceiver,
+ 0, null, null, requiredPermissions, android.app.AppOpsManager.OP_NONE,
+ null, finishedReceiver != null, false, id);
+ }
+ }
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+ /**
+ * Check if the external storage media is available. This is true if there
+ * is a mounted external storage medium or if the external storage is
+ * emulated.
+ */
+ private boolean isExternalMediaAvailable() {
+ return mMediaMounted || Environment.isExternalStorageEmulated();
+ }
- boolean runtimePermissionsRevoked = false;
- int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY;
+ /**
+ * Ensure that the install reason matches what we know about the package installer (e.g. whether
+ * it is acting on behalf on an enterprise or the user).
+ *
+ * Note that the ordering of the conditionals in this method is important. The checks we perform
+ * are as follows, in this order:
+ *
+ * 1) If the install is being performed by a system app, we can trust the app to have set the
+ * install reason correctly. Thus, we pass through the install reason unchanged, no matter
+ * what it is.
+ * 2) If the install is being performed by a device or profile owner app, the install reason
+ * should be enterprise policy. However, we cannot be sure that the device or profile owner
+ * set the install reason correctly. If the app targets an older SDK version where install
+ * reasons did not exist yet, or if the app author simply forgot, the install reason may be
+ * unset or wrong. Thus, we force the install reason to be enterprise policy.
+ * 3) In all other cases, the install is being performed by a regular app that is neither part
+ * of the system nor a device or profile owner. We have no reason to believe that this app is
+ * acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+ * set to enterprise policy and if so, change it to unknown instead.
+ */
+ private int fixUpInstallReason(String installerPackageName, int installerUid,
+ int installReason) {
+ if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+ == PERMISSION_GRANTED) {
+ // If the install is being performed by a system app, we trust that app to have set the
+ // install reason correctly.
+ return installReason;
+ }
+ final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(
+ UserHandle.getUserId(installerUid));
+ if (ownerPackage != null && ownerPackage.equals(installerPackageName)) {
+ // If the install is being performed by a device or profile owner, the install
+ // reason should be enterprise policy.
+ return PackageManager.INSTALL_REASON_POLICY;
+ }
- boolean changedInstallPermission = false;
- if (replace) {
- ps.installPermissionsFixed = false;
- if (!ps.isSharedUser()) {
- origPermissions = new PermissionsState(permissionsState);
- permissionsState.reset();
- } else {
- // We need to know only about runtime permission changes since the
- // calling code always writes the install permissions state but
- // the runtime ones are written only if changed. The only cases of
- // changed runtime permissions here are promotion of an install to
- // runtime and revocation of a runtime from a shared user.
- changedRuntimePermissionUserIds = revokeUnusedSharedUserPermissionsLPw(
- ps.sharedUser, UserManagerService.getInstance().getUserIds());
- if (!ArrayUtils.isEmpty(changedRuntimePermissionUserIds)) {
- runtimePermissionsRevoked = true;
- }
- }
+ if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+ // If the install is being performed by a regular app (i.e. neither system app nor
+ // device or profile owner), we have no reason to believe that the app is acting on
+ // behalf of an enterprise. If the app set the install reason to enterprise policy,
+ // change it to unknown instead.
+ return PackageManager.INSTALL_REASON_UNKNOWN;
}
- permissionsState.setGlobalGids(mGlobalGids);
-
- final int N = pkg.requestedPermissions.size();
- for (int i=0; i<N; i++) {
- final String name = pkg.requestedPermissions.get(i);
- final BasePermission bp = mSettings.mPermissions.get(name);
- final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M;
+ // If the install is being performed by a regular app and the install reason was set to any
+ // value but enterprise policy, leave the install reason unchanged.
+ return installReason;
+ }
- if (DEBUG_INSTALL) {
- Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
+ void installStage(ActiveInstallSession activeInstallSession) {
+ if (DEBUG_INSTANT) {
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
+ }
+ final Message msg = mHandler.obtainMessage(INIT_COPY);
+ final InstallParams params = new InstallParams(activeInstallSession);
+ params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
+ msg.obj = params;
- if (bp == null || bp.packageSetting == null) {
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Unknown permission " + name
- + " in package " + pkg.packageName);
- }
- }
- continue;
- }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mHandler.sendMessage(msg);
+ }
- // Limit ephemeral apps to ephemeral allowed permissions.
- if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
- if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
- + pkg.packageName);
- }
- continue;
- }
+ void installStage(List<ActiveInstallSession> children)
+ throws PackageManagerException {
+ final Message msg = mHandler.obtainMessage(INIT_COPY);
+ final MultiPackageInstallParams params =
+ new MultiPackageInstallParams(UserHandle.ALL, children);
+ params.setTraceMethod("installStageMultiPackage")
+ .setTraceCookie(System.identityHashCode(params));
+ msg.obj = params;
- if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
- if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
- + pkg.packageName);
- }
- continue;
- }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mHandler.sendMessage(msg);
+ }
- final String perm = bp.name;
- boolean allowedSig = false;
- int grant = GRANT_DENIED;
+ private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
+ int userId) {
+ final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
+ final boolean isInstantApp = pkgSetting.getInstantApp(userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
+ sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
+ false /*startReceiver*/, pkgSetting.appId, userIds, instantUserIds);
- // Keep track of app op permissions.
- if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
- if (pkgs == null) {
- pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(bp.name, pkgs);
- }
- pkgs.add(pkg.packageName);
- }
+ // Send a session commit broadcast
+ final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
+ info.installReason = pkgSetting.getInstallReason(userId);
+ info.appPackageName = packageName;
+ sendSessionCommitBroadcast(info, userId);
+ }
- final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
- switch (level) {
- case PermissionInfo.PROTECTION_NORMAL: {
- // For all apps normal permissions are install time ones.
- grant = GRANT_INSTALL;
- } break;
+ @Override
+ public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds) {
+ if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
+ return;
+ }
+ Bundle extras = new Bundle(1);
+ // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast
+ final int uid = UserHandle.getUid(
+ (ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId);
+ extras.putInt(Intent.EXTRA_UID, uid);
- case PermissionInfo.PROTECTION_DANGEROUS: {
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
- // For legacy apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL;
- } else if (origPermissions.hasInstallPermission(bp.name)) {
- // For legacy apps that became modern, install becomes runtime.
- grant = GRANT_UPGRADE;
- } else if (mPromoteSystemApps
- && isSystemApp(ps)
- && mExistingSystemPackages.contains(ps.name)) {
- // For legacy system apps, install becomes runtime.
- // We cannot check hasInstallPermission() for system apps since those
- // permissions were granted implicitly and not persisted pre-M.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ packageName, extras, 0, null, null, userIds, instantUserIds);
+ if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
+ mHandler.post(() -> {
+ for (int userId : userIds) {
+ sendBootCompletedBroadcastToSystemApp(
+ packageName, includeStopped, userId);
+ }
}
- } break;
+ );
+ }
+ }
- case PermissionInfo.PROTECTION_SIGNATURE: {
- // For all apps signature permissions are install time ones.
- allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
- if (allowedSig) {
- grant = GRANT_INSTALL;
- }
- } break;
+ /**
+ * The just-installed/enabled app is bundled on the system, so presumed to be able to run
+ * automatically without needing an explicit launch.
+ * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
+ */
+ private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
+ int userId) {
+ // If user is not running, the app didn't miss any broadcast
+ if (!mUserManagerInternal.isUserRunning(userId)) {
+ return;
+ }
+ final IActivityManager am = ActivityManager.getService();
+ try {
+ // Deliver LOCKED_BOOT_COMPLETED first
+ Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
+ .setPackage(packageName);
+ if (includeStopped) {
+ lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
+ final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
+ am.broadcastIntent(null, lockedBcIntent, null, null, 0, null, null, requiredPermissions,
+ android.app.AppOpsManager.OP_NONE, null, false, false, userId);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
- }
-
- if (grant != GRANT_DENIED) {
- if (!isSystemApp(ps) && ps.installPermissionsFixed) {
- // If this is an existing, non-system package, then
- // we can't add any new permissions to it.
- if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
- // Except... if this is a permission that was added
- // to the platform (note: need to only do this when
- // updating the platform).
- if (!isNewPlatformPermissionForPackage(perm, pkg)) {
- grant = GRANT_DENIED;
- }
- }
+ // Deliver BOOT_COMPLETED only if user is unlocked
+ if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) {
+ Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
+ if (includeStopped) {
+ bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
+ am.broadcastIntent(null, bcIntent, null, null, 0, null, null, requiredPermissions,
+ android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
- switch (grant) {
- case GRANT_INSTALL: {
- // Revoke this as runtime permission to handle the case of
- // a runtime permission being downgraded to an install one.
- // Also in permission review mode we keep dangerous permissions
- // for legacy apps
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- if (origPermissions.getRuntimePermissionState(
- bp.name, userId) != null) {
- // Revoke the runtime permission and clear the flags.
- origPermissions.revokeRuntimePermission(bp, userId);
- origPermissions.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- // If we revoked a permission permission, we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- }
- // Grant an install permission.
- if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- changedInstallPermission = true;
- }
- } break;
-
- case GRANT_RUNTIME: {
- // Grant previously granted runtime permissions.
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- PermissionState permissionState = origPermissions
- .getRuntimePermissionState(bp.name, userId);
- int flags = permissionState != null
- ? permissionState.getFlags() : 0;
- if (origPermissions.hasRuntimePermission(bp.name, userId)) {
- // Don't propagate the permission in a permission review mode if
- // the former was revoked, i.e. marked to not propagate on upgrade.
- // Note that in a permission review mode install permissions are
- // represented as constantly granted runtime ones since we need to
- // keep a per user state associated with the permission. Also the
- // revoke on upgrade flag is no longer applicable and is reset.
- final boolean revokeOnUpgrade = (flags & PackageManager
- .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
- if (revokeOnUpgrade) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- // Since we changed the flags, we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- if (!mPermissionReviewRequired || !revokeOnUpgrade) {
- if (permissionsState.grantRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // If we cannot put the permission as it was,
- // we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, 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();
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "setApplicationHiddenSetting for user " + userId);
- // If the app supports runtime permissions no need for a review.
- if (mPermissionReviewRequired
- && appSupportsRuntimePermissions
- && (flags & PackageManager
- .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- // Since we changed the flags, we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- } else if (mPermissionReviewRequired
- && !appSupportsRuntimePermissions) {
- // For legacy apps that need a permission review, every new
- // runtime permission is granted but it is pending a review.
- // We also need to review only platform defined runtime
- // permissions as these are the only ones the platform knows
- // how to disable the API to simulate revocation as legacy
- // apps don't expect to run with revoked permissions.
- if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
- if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
- // We changed the flags, hence have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- }
- if (permissionsState.grantRuntimePermission(bp, userId)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We changed the permission, hence have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- }
- // Propagate the permission flags.
- permissionsState.updatePermissionFlags(bp, userId, flags, flags);
- }
- } break;
-
- case GRANT_UPGRADE: {
- // Grant runtime permissions for a previously held install permission.
- PermissionState permissionState = origPermissions
- .getInstallPermissionState(bp.name);
- final int flags = permissionState != null ? permissionState.getFlags() : 0;
-
- if (origPermissions.revokeInstallPermission(bp)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We will be transferring the permission flags, so clear them.
- origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- changedInstallPermission = true;
- }
+ if (hidden && isPackageDeviceAdmin(packageName, userId)) {
+ Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin");
+ return false;
+ }
- // If the permission is not to be promoted to runtime we ignore it and
- // also its other flags as they are not applicable to install permissions.
- if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
- for (int userId : currentUserIds) {
- if (permissionsState.grantRuntimePermission(bp, userId) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // Transfer the permission flags.
- permissionsState.updatePermissionFlags(bp, userId,
- flags, flags);
- // If we granted the permission, we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
- }
- }
- }
- } break;
-
- default: {
- if (packageOfInterest == null
- || packageOfInterest.equals(pkg.packageName)) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
- + " because it was previously installed without");
- }
- }
- } break;
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ boolean sendAdded = false;
+ boolean sendRemoved = false;
+ // writer
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ return false;
}
- } else {
- if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // Also drop the permission flags.
- permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- changedInstallPermission = true;
- Slog.i(TAG, "Un-granting permission " + perm
- + " from package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
- + ")");
- } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
- // Don't print warning for app op permissions, since it is fine for them
- // not to be granted, there is a UI for the user to decide.
- if (DEBUG_PERMISSIONS
- && (packageOfInterest == null
- || packageOfInterest.equals(pkg.packageName))) {
- Slog.i(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
- + " (protectionLevel=" + bp.protectionLevel
- + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
- + ")");
- }
- }
- }
- }
-
- if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
- !isSystemApp(ps) || isUpdatedSystemApp(ps)){
- // This is the first that we have heard about this package, so the
- // permissions we have now selected are fixed until explicitly
- // changed.
- ps.installPermissionsFixed = true;
- }
-
- // Persist the runtime permissions state for users with changes. If permissions
- // were revoked because no app in the shared user declares them we have to
- // write synchronously to avoid losing runtime permissions state.
- for (int userId : changedRuntimePermissionUserIds) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked);
- }
- }
-
- private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
- boolean allowed = false;
- final int NP = PackageParser.NEW_PERMISSIONS.length;
- for (int ip=0; ip<NP; ip++) {
- final PackageParser.NewPermissionInfo npi
- = PackageParser.NEW_PERMISSIONS[ip];
- if (npi.name.equals(perm)
- && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
- allowed = true;
- Log.i(TAG, "Auto-granting " + perm + " to old pkg "
- + pkg.packageName);
- break;
- }
- }
- return allowed;
- }
-
- private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
- BasePermission bp, PermissionsState origPermissions) {
- boolean privilegedPermission = (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
- boolean privappPermissionsDisable =
- RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
- boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
- boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
- if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
- && !platformPackage && platformPermission) {
- final ArraySet<String> allowedPermissions = SystemConfig.getInstance()
- .getPrivAppPermissions(pkg.packageName);
- final boolean whitelisted =
- allowedPermissions != null && allowedPermissions.contains(perm);
- if (!whitelisted) {
- Slog.w(TAG, "Privileged permission " + perm + " for package "
- + pkg.packageName + " - not in privapp-permissions whitelist");
- // Only report violations for apps on system image
- if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
- // it's only a reportable violation if the permission isn't explicitly denied
- final ArraySet<String> deniedPermissions = SystemConfig.getInstance()
- .getPrivAppDenyPermissions(pkg.packageName);
- final boolean permissionViolation =
- deniedPermissions == null || !deniedPermissions.contains(perm);
- if (permissionViolation) {
- if (mPrivappPermissionsViolations == null) {
- mPrivappPermissionsViolations = new ArraySet<>();
- }
- mPrivappPermissionsViolations.add(pkg.packageName + ": " + perm);
- } else {
- return false;
- }
+ if (filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ return false;
}
- if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
+ // Do not allow "android" is being disabled
+ if ("android".equals(packageName)) {
+ Slog.w(TAG, "Cannot hide package: android");
return false;
}
- }
- }
- boolean allowed = (compareSignatures(
- bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
- == PackageManager.SIGNATURE_MATCH)
- || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
- == PackageManager.SIGNATURE_MATCH);
- if (!allowed && privilegedPermission) {
- if (isSystemApp(pkg)) {
- // For updated system applications, a system permission
- // is granted only if it had been defined by the original application.
- if (pkg.isUpdatedSystemApp()) {
- final PackageSetting sysPs = mSettings
- .getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPs != null && sysPs.getPermissionsState().hasInstallPermission(perm)) {
- // If the original was granted this permission, we take
- // that grant decision as read and propagate it to the
- // update.
- if (sysPs.isPrivileged()) {
- allowed = true;
- }
+ // 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.
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.staticSharedLibName != null) {
+ Slog.w(TAG, "Cannot hide package: " + packageName
+ + " providing static shared library: "
+ + pkg.staticSharedLibName);
+ return false;
+ }
+ // Only allow protected packages to hide themselves.
+ if (hidden && !UserHandle.isSameApp(callingUid, pkgSetting.appId)
+ && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ Slog.w(TAG, "Not hiding protected package: " + packageName);
+ return false;
+ }
+
+ if (pkgSetting.getHidden(userId) != hidden) {
+ pkgSetting.setHidden(hidden, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+ if (hidden) {
+ sendRemoved = true;
} else {
- // The system apk may have been updated with an older
- // version of the one on the data partition, but which
- // granted a new system permission that it didn't have
- // before. In this case we do want to allow the app to
- // now get the new permission if the ancestral apk is
- // privileged to get it.
- if (sysPs != null && sysPs.pkg != null && sysPs.isPrivileged()) {
- for (int j = 0; j < sysPs.pkg.requestedPermissions.size(); j++) {
- if (perm.equals(sysPs.pkg.requestedPermissions.get(j))) {
- allowed = true;
- break;
- }
- }
- }
- // Also if a privileged parent package on the system image or any of
- // its children requested a privileged permission, the updated child
- // packages can also get the permission.
- if (pkg.parentPackage != null) {
- final PackageSetting disabledSysParentPs = mSettings
- .getDisabledSystemPkgLPr(pkg.parentPackage.packageName);
- if (disabledSysParentPs != null && disabledSysParentPs.pkg != null
- && disabledSysParentPs.isPrivileged()) {
- if (isPackageRequestingPermission(disabledSysParentPs.pkg, perm)) {
- allowed = true;
- } else if (disabledSysParentPs.pkg.childPackages != null) {
- final int count = disabledSysParentPs.pkg.childPackages.size();
- for (int i = 0; i < count; i++) {
- PackageParser.Package disabledSysChildPkg =
- disabledSysParentPs.pkg.childPackages.get(i);
- if (isPackageRequestingPermission(disabledSysChildPkg,
- perm)) {
- allowed = true;
- break;
- }
- }
- }
- }
- }
+ sendAdded = true;
}
- } else {
- allowed = isPrivilegedApp(pkg);
- }
- }
- }
- if (!allowed) {
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PRE23) != 0
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- // If this was a previously normal/dangerous permission that got moved
- // to a system permission as part of the runtime permission redesign, then
- // we still want to blindly grant it to old apps.
- allowed = true;
- }
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0
- && pkg.packageName.equals(mRequiredInstallerPackage)) {
- // If this permission is to be granted to the system installer and
- // this app is an installer, then it gets the permission.
- allowed = true;
- }
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0
- && pkg.packageName.equals(mRequiredVerifierPackage)) {
- // If this permission is to be granted to the system verifier and
- // this app is a verifier, then it gets the permission.
- allowed = true;
- }
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
- && isSystemApp(pkg)) {
- // Any pre-installed system app is allowed to get this permission.
- allowed = true;
- }
- if (!allowed && (bp.protectionLevel
- & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
- // For development permissions, a development permission
- // is granted only if it was already granted.
- allowed = origPermissions.hasInstallPermission(perm);
- }
- if (!allowed && (bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0
- && pkg.packageName.equals(mSetupWizardPackage)) {
- // If this permission is to be granted to the system setup wizard and
- // this app is a setup wizard, then it gets the permission.
- allowed = true;
- }
- }
- return allowed;
- }
-
- private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) {
- final int permCount = pkg.requestedPermissions.size();
- for (int j = 0; j < permCount; j++) {
- String requestedPermission = pkg.requestedPermissions.get(j);
- if (permission.equals(requestedPermission)) {
+ }
+ }
+ if (sendAdded) {
+ sendPackageAddedForUser(packageName, pkgSetting, userId);
+ return true;
+ }
+ if (sendRemoved) {
+ killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+ "hiding pkg");
+ sendApplicationHiddenForUser(packageName, pkgSetting, userId);
return true;
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
return false;
}
- final class ActivityIntentResolver
- extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, int userId) {
- if (!sUserManager.exists(userId)) return null;
- mFlags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0);
- return super.queryIntent(intent, resolvedType, defaultOnly, userId);
- }
-
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
- int userId) {
- if (!sUserManager.exists(userId)) return null;
- mFlags = flags;
- return super.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId);
- }
-
- public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {
- if (!sUserManager.exists(userId)) return null;
- if (packageActivities == null) {
- return null;
+ @Override
+ public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
+ enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled");
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || !pkgSetting.isSystem()) {
+ return;
}
- mFlags = flags;
- final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final int N = packageActivities.size();
- ArrayList<PackageParser.ActivityIntentInfo[]> listCut =
- new ArrayList<PackageParser.ActivityIntentInfo[]>(N);
-
- ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
- for (int i = 0; i < N; ++i) {
- intentFilters = packageActivities.get(i).intents;
- if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ActivityIntentInfo[] array =
- new PackageParser.ActivityIntentInfo[intentFilters.size()];
- intentFilters.toArray(array);
- listCut.add(array);
- }
+ PackageParser.Package pkg = pkgSetting.pkg;
+ if (pkg != null && pkg.applicationInfo != null) {
+ pkg.applicationInfo.hiddenUntilInstalled = hidden;
}
- return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
- }
-
- /**
- * Finds a privileged activity that matches the specified activity names.
- */
- private PackageParser.Activity findMatchingActivity(
- List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
- for (PackageParser.Activity sysActivity : activityList) {
- if (sysActivity.info.name.equals(activityInfo.name)) {
- return sysActivity;
- }
- if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
- return sysActivity;
- }
- if (sysActivity.info.targetActivity != null) {
- if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
- return sysActivity;
- }
- if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
- return sysActivity;
- }
- }
+ final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
+ if (disabledPs == null) {
+ return;
}
- return null;
- }
-
- public class IterGenerator<E> {
- public Iterator<E> generate(ActivityIntentInfo info) {
- return null;
+ pkg = disabledPs.pkg;
+ if (pkg != null && pkg.applicationInfo != null) {
+ pkg.applicationInfo.hiddenUntilInstalled = hidden;
}
}
+ }
- public class ActionIterGenerator extends IterGenerator<String> {
- @Override
- public Iterator<String> generate(ActivityIntentInfo info) {
- return info.actionsIterator();
+ @Override
+ public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
+ enforceSystemOrPhoneCaller("setSystemAppInstallState");
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ // The target app should always be in system
+ if (pkgSetting == null || !pkgSetting.isSystem()) {
+ return false;
}
- }
-
- public class CategoriesIterGenerator extends IterGenerator<String> {
- @Override
- public Iterator<String> generate(ActivityIntentInfo info) {
- return info.categoriesIterator();
+ // Check if the install state is the same
+ if (pkgSetting.getInstalled(userId) == installed) {
+ return false;
}
}
- public class SchemesIterGenerator extends IterGenerator<String> {
- @Override
- public Iterator<String> generate(ActivityIntentInfo info) {
- return info.schemesIterator();
+ 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;
}
- }
- public class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
- @Override
- public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
- return info.authoritiesIterator();
- }
+ // 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);
}
+ }
- /**
- * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
- * MODIFIED. Do not pass in a list that should not be changed.
- */
- private <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
- IterGenerator<T> generator, Iterator<T> searchIterator) {
- // loop through the set of actions; every one must be found in the intent filter
- while (searchIterator.hasNext()) {
- // we must have at least one filter in the list to consider a match
- if (intentList.size() == 0) {
- break;
- }
-
- final T searchAction = searchIterator.next();
-
- // loop through the set of intent filters
- final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
- while (intentIter.hasNext()) {
- final ActivityIntentInfo intentInfo = intentIter.next();
- boolean selectionFound = false;
+ private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
+ int userId) {
+ final PackageRemovedInfo info = new PackageRemovedInfo(this);
+ info.removedPackage = packageName;
+ info.installerPackageName = pkgSetting.installerPackageName;
+ info.removedUsers = new int[] {userId};
+ info.broadcastUsers = new int[] {userId};
+ info.uid = UserHandle.getUid(userId, pkgSetting.appId);
+ info.sendPackageRemovedBroadcasts(true /*killApp*/);
+ }
- // loop through the intent filter's selection criteria; at least one
- // of them must match the searched criteria
- final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
- while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
- final T intentSelection = intentSelectionIter.next();
- if (intentSelection != null && intentSelection.equals(searchAction)) {
- selectionFound = true;
- break;
- }
- }
+ private void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
+ int distractionFlags) {
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+ sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null);
+ }
- // the selection criteria wasn't found in this filter's set; this filter
- // is not a potential match
- if (!selectionFound) {
- intentIter.remove();
- }
- }
- }
+ private void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
+ boolean suspended, PersistableBundle launcherExtras) {
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ if (launcherExtras != null) {
+ extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
+ new Bundle(launcherExtras.deepCopy()));
}
+ sendPackageBroadcast(
+ suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+ : Intent.ACTION_PACKAGES_UNSUSPENDED,
+ null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
+ new int[] {userId}, null);
+ }
- private boolean isProtectedAction(ActivityIntentInfo filter) {
- final Iterator<String> actionsIter = filter.actionsIterator();
- while (actionsIter != null && actionsIter.hasNext()) {
- final String filterAction = actionsIter.next();
- if (PROTECTED_ACTIONS.contains(filterAction)) {
+ /**
+ * 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();
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getApplicationHidden for user " + userId);
+ PackageSetting ps;
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ // writer
+ synchronized (mPackages) {
+ ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ return true;
+ }
+ if (filterAppAccessLPr(ps, callingUid, userId)) {
return true;
}
+ return ps.getHidden(userId);
}
- return false;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
+ }
- /**
- * Adjusts the priority of the given intent filter according to policy.
- * <p>
- * <ul>
- * <li>The priority for non privileged applications is capped to '0'</li>
- * <li>The priority for protected actions on privileged applications is capped to '0'</li>
- * <li>The priority for unbundled updates to privileged applications is capped to the
- * priority defined on the system partition</li>
- * </ul>
- * <p>
- * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
- * allowed to obtain any priority on any action.
- */
- private void adjustPriority(
- List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
- // nothing to do; priority is fine as-is
- if (intent.getPriority() <= 0) {
- return;
- }
-
- final ActivityInfo activityInfo = intent.activity.info;
- final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+ /**
+ * @hide
+ */
+ @Override
+ public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+ int installReason, List<String> whiteListedPermissions) {
+ return installExistingPackageAsUser(packageName, userId, installFlags, installReason,
+ whiteListedPermissions, null);
+ }
- final boolean privilegedApp =
- ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
- if (!privilegedApp) {
- // non-privileged applications can never define a priority >0
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Non-privileged app; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(0);
- return;
- }
+ int installExistingPackageAsUser(@Nullable String packageName, @UserIdInt int userId,
+ @PackageManager.InstallFlags int installFlags,
+ @PackageManager.InstallReason int installReason,
+ @Nullable List<String> whiteListedPermissions, @Nullable IntentSender intentSender) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
+ + " installFlags=" + installFlags + " installReason=" + installReason
+ + " whiteListedPermissions=" + whiteListedPermissions);
+ }
- if (systemActivities == null) {
- // the system package is not disabled; we're parsing the system partition
- if (isProtectedAction(intent)) {
- if (mDeferProtectedFilters) {
- // We can't deal with these just yet. No component should ever obtain a
- // >0 priority for a protected actions, with ONE exception -- the setup
- // wizard. The setup wizard, however, cannot be known until we're able to
- // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
- // until all intent filters have been processed. Chicken, meet egg.
- // Let the filter temporarily have a high priority and rectify the
- // priorities after all system packages have been scanned.
- mProtectedFilters.add(intent);
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; save for later;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- return;
- } else {
- if (DEBUG_FILTERS && mSetupWizardPackage == null) {
- Slog.i(TAG, "No setup wizard;"
- + " All protected intents capped to priority 0");
- }
- if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Found setup wizard;"
- + " allow priority " + intent.getPriority() + ";"
- + " package: " + intent.activity.info.packageName
- + " activity: " + intent.activity.className
- + " priority: " + intent.getPriority());
- }
- // setup wizard gets whatever it wants
- return;
- }
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; cap priority to 0;"
- + " package: " + intent.activity.info.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(0);
- return;
- }
- }
- // privileged apps on the system image get whatever priority they request
- return;
- }
+ final int callingUid = Binder.getCallingUid();
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INSTALL_EXISTING_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Neither user " + callingUid + " nor current process has "
+ + android.Manifest.permission.INSTALL_PACKAGES + ".");
+ }
+ PackageSetting pkgSetting;
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "installExistingPackage for user " + userId);
+ if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
+ return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
+ }
- // privileged app unbundled update ... try to find the same activity
- final PackageParser.Activity foundActivity =
- findMatchingActivity(systemActivities, activityInfo);
- if (foundActivity == null) {
- // this is a new activity; it cannot obtain >0 priority
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "New activity; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(0);
- return;
- }
-
- // found activity, now check for filter equivalence
-
- // a shallow copy is enough; we modify the list, not its contents
- final List<ActivityIntentInfo> intentListCopy =
- new ArrayList<>(foundActivity.intents);
- final List<ActivityIntentInfo> foundFilters = findFilters(intent);
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ boolean installed = false;
+ final boolean instantApp =
+ (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ final boolean fullApp =
+ (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
- // find matching action subsets
- final Iterator<String> actionsIterator = intent.actionsIterator();
- if (actionsIterator != null) {
- getIntentListSubset(
- intentListCopy, new ActionIterGenerator(), actionsIterator);
- if (intentListCopy.size() == 0) {
- // no more intents to match; we're not equivalent
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Mismatched action; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(0);
- return;
+ // writer
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ return PackageManager.INSTALL_FAILED_INVALID_URI;
}
- }
-
- // find matching category subsets
- final Iterator<String> categoriesIterator = intent.categoriesIterator();
- if (categoriesIterator != null) {
- getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
- categoriesIterator);
- if (intentListCopy.size() == 0) {
- // no more intents to match; we're not equivalent
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Mismatched category; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
+ if (!canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
+ // only allow the existing package to be used if it's installed as a full
+ // application for at least one user
+ boolean installAllowed = false;
+ for (int checkUserId : sUserManager.getUserIds()) {
+ installAllowed = !pkgSetting.getInstantApp(checkUserId);
+ if (installAllowed) {
+ break;
+ }
}
- intent.setPriority(0);
- return;
- }
- }
-
- // find matching schemes subsets
- final Iterator<String> schemesIterator = intent.schemesIterator();
- if (schemesIterator != null) {
- getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
- schemesIterator);
- if (intentListCopy.size() == 0) {
- // no more intents to match; we're not equivalent
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
+ if (!installAllowed) {
+ return PackageManager.INSTALL_FAILED_INVALID_URI;
}
- intent.setPriority(0);
- return;
}
- }
-
- // find matching authorities subsets
- final Iterator<IntentFilter.AuthorityEntry>
- authoritiesIterator = intent.authoritiesIterator();
- if (authoritiesIterator != null) {
- getIntentListSubset(intentListCopy,
- new AuthoritiesIterGenerator(),
- authoritiesIterator);
- if (intentListCopy.size() == 0) {
- // no more intents to match; we're not equivalent
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Mismatched authority; cap priority to 0;"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(0);
- return;
+ if (!pkgSetting.getInstalled(userId)) {
+ pkgSetting.setInstalled(true, userId);
+ pkgSetting.setHidden(false, userId);
+ pkgSetting.setInstallReason(installReason, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+ mSettings.writeKernelMappingLPr(pkgSetting);
+ installed = true;
+ } else if (fullApp && pkgSetting.getInstantApp(userId)) {
+ // upgrade app from instant to full; we don't allow app downgrade
+ installed = true;
}
+ setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
}
- // we found matching filter(s); app gets the max priority of all intents
- int cappedPriority = 0;
- for (int i = intentListCopy.size() - 1; i >= 0; --i) {
- cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
- }
- if (intent.getPriority() > cappedPriority) {
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Found matching filter(s);"
- + " cap priority to " + cappedPriority + ";"
- + " package: " + applicationInfo.packageName
- + " activity: " + intent.activity.className
- + " origPrio: " + intent.getPriority());
- }
- intent.setPriority(cappedPriority);
- return;
- }
- // all this for nothing; the requested priority was <= what was on the system
- }
-
- public final void addActivity(PackageParser.Activity a, String type) {
- mActivities.put(a.getComponentName(), a);
- if (DEBUG_SHOW_INFO)
- Log.v(
- TAG, " " + type + " " +
- (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
- if (DEBUG_SHOW_INFO)
- Log.v(TAG, " Class=" + a.info.name);
- final int NI = a.intents.size();
- for (int j=0; j<NI; j++) {
- PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if ("activity".equals(type)) {
- final PackageSetting ps =
- mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
- final List<PackageParser.Activity> systemActivities =
- ps != null && ps.pkg != null ? ps.pkg.activities : null;
- adjustPriority(systemActivities, intent);
+ if (installed) {
+ if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
+ != 0 && pkgSetting.pkg != null) {
+ whiteListedPermissions = pkgSetting.pkg.requestedPermissions;
}
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
+ setWhitelistedRestrictedPermissions(packageName, whiteListedPermissions,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+
+ if (pkgSetting.pkg != null) {
+ synchronized (mInstallLock) {
+ // We don't need to freeze for a brand new install
+ prepareAppDataAfterInstallLIF(pkgSetting.pkg);
+ }
}
- if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Activity " + a.info.name);
+ sendPackageAddedForUser(packageName, pkgSetting, userId);
+ synchronized (mPackages) {
+ updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
- addFilter(intent);
+ // start async restore with no post-install since we finish install here
+ PackageInstalledInfo res =
+ createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
+ res.pkg = pkgSetting.pkg;
+ res.newUsers = new int[]{ userId };
+ PostInstallData postInstallData = intentSender == null ? null :
+ new PostInstallData(null, res, () -> onRestoreComplete(res.returnCode,
+ mContext, intentSender));
+ restoreAndPostInstall(userId, res, postInstallData);
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ static void onRestoreComplete(int returnCode, Context context, IntentSender target) {
+ Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.installStatusToPublicStatus(returnCode));
+ try {
+ target.sendIntent(context, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
}
+ }
- public final void removeActivity(PackageParser.Activity a, String type) {
- mActivities.remove(a.getComponentName());
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " " + type + " "
- + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
- : a.info.name) + ":");
- Log.v(TAG, " Class=" + a.info.name);
+ static void setInstantAppForUser(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);
}
- final int NI = a.intents.size();
- for (int j=0; j<NI; j++) {
- PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
+ } else {
+ for (int currentUserId : sUserManager.getUserIds()) {
+ if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
+ pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
+ } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
+ pkgSetting.setInstantApp(false /*instantApp*/, currentUserId);
}
- removeFilter(intent);
}
}
+ }
- @Override
- protected boolean allowFilterResult(
- PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
- ActivityInfo filterAi = filter.activity.info;
- for (int i=dest.size()-1; i>=0; i--) {
- ActivityInfo destAi = dest.get(i).activityInfo;
- if (destAi.name == filterAi.name
- && destAi.packageName == filterAi.packageName) {
- return false;
- }
- }
+ boolean isUserRestricted(int userId, String restrictionKey) {
+ Bundle restrictions = sUserManager.getUserRestrictions(userId);
+ if (restrictions.getBoolean(restrictionKey, false)) {
+ Log.w(TAG, "User is restricted: " + restrictionKey);
return true;
}
+ return false;
+ }
- @Override
- protected ActivityIntentInfo[] newArray(int size) {
- return new ActivityIntentInfo[size];
- }
+ @Override
+ public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
+ int restrictionFlags, int userId) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
+ "setDistractingPackageRestrictionsAsUser");
- @Override
- protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
- if (!sUserManager.exists(userId)) return true;
- PackageParser.Package p = filter.activity.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting)p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
- }
- }
- return false;
+ 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);
}
+ Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
- @Override
- protected boolean isPackageForFilter(String packageName,
- PackageParser.ActivityIntentInfo info) {
- return packageName.equals(info.activity.owner.packageName);
- }
+ 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;
- @Override
- protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
- int match, int userId) {
- if (!sUserManager.exists(userId)) return null;
- if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
- return null;
- }
- final PackageParser.Activity activity = info.activity;
- PackageSetting ps = (PackageSetting) activity.owner.mExtras;
- if (ps == null) {
- return null;
- }
- final PackageUserState userState = ps.readUserState(userId);
- ActivityInfo ai =
- PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
- if (ai == null) {
- return null;
- }
- final boolean matchExplicitlyVisibleOnly =
- (mFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
- final boolean matchVisibleToInstantApp =
- (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
- final boolean componentVisible =
- matchVisibleToInstantApp
- && info.isVisibleToInstantApp()
- && (!matchExplicitlyVisibleOnly || info.isExplicitlyVisibleToInstantApp());
- final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
- // throw out filters that aren't visible to ephemeral apps
- if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
- return null;
- }
- // throw out instant app filters if we're not explicitly requesting them
- if (!matchInstantApp && userState.instantApp) {
- return null;
- }
- // throw out instant app filters if updates are available; will trigger
- // instant app resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
- return null;
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ final PackageSetting pkgSetting;
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ Slog.w(TAG, "Could not find package setting for package: " + packageName
+ + ". Skipping...");
+ unactionedPackages.add(packageName);
+ continue;
+ }
}
- final ResolveInfo res = new ResolveInfo();
- res.activityInfo = ai;
- if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
- res.filter = info;
+ if (canRestrict != null && !canRestrict[i]) {
+ unactionedPackages.add(packageName);
+ continue;
}
- if (info != null) {
- res.handleAllWebDataURI = info.handleAllWebDataURI();
- }
- res.priority = info.getPriority();
- res.preferredOrder = activity.owner.mPreferredOrder;
- //System.out.println("Result: " + res.activityInfo.className +
- // " = " + res.priority);
- res.match = match;
- res.isDefault = info.hasDefault;
- res.labelRes = info.labelRes;
- res.nonLocalizedLabel = info.nonLocalizedLabel;
- if (userNeedsBadging(userId)) {
- res.noResourceId = true;
- } else {
- res.icon = info.icon;
+ synchronized (mPackages) {
+ final int oldDistractionFlags = pkgSetting.getDistractionFlags(userId);
+ if (restrictionFlags != oldDistractionFlags) {
+ pkgSetting.setDistractionFlags(restrictionFlags, userId);
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+ }
}
- res.iconResourceId = info.icon;
- res.system = res.activityInfo.applicationInfo.isSystemApp();
- res.isInstantAppAvailable = userState.instantApp;
- return res;
}
- @Override
- protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
- }
-
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ActivityIntentInfo filter) {
- out.print(prefix); out.print(
- Integer.toHexString(System.identityHashCode(filter.activity)));
- out.print(' ');
- filter.activity.printComponentShortName(out);
- out.print(" filter ");
- out.println(Integer.toHexString(System.identityHashCode(filter)));
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+ restrictionFlags);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
}
+ return unactionedPackages.toArray(new String[0]);
+ }
- @Override
- protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {
- return filter.activity;
+ private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid,
+ int userId, String callingMethod) {
+ if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+ return;
}
- protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- PackageParser.Activity activity = (PackageParser.Activity)label;
- out.print(prefix); out.print(
- Integer.toHexString(System.identityHashCode(activity)));
- out.print(' ');
- activity.printComponentShortName(out);
- if (count > 1) {
- out.print(" ("); out.print(count); out.print(" filters)");
+ final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ if (ownerPackage != null) {
+ final int ownerUid = getPackageUid(ownerPackage, 0, userId);
+ if (ownerUid == callingUid) {
+ return;
}
- out.println();
+ throw new UnsupportedOperationException("Cannot suspend/unsuspend packages. User "
+ + userId + " has an active DO or PO");
}
- // Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
- = new ArrayMap<ComponentName, PackageParser.Activity>();
- private int mFlags;
- }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
+ callingMethod);
- private final class ServiceIntentResolver
- extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, int userId) {
- mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(intent, resolvedType, defaultOnly, userId);
- }
+ final int packageUid = getPackageUid(callingPackage, 0, userId);
+ final boolean allowedPackageUid = packageUid == callingUid;
+ final boolean allowedShell = callingUid == SHELL_UID
+ && UserHandle.isSameApp(packageUid, callingUid);
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
- int userId) {
- if (!sUserManager.exists(userId)) return null;
- mFlags = flags;
- return super.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId);
+ if (!allowedShell && !allowedPackageUid) {
+ throw new SecurityException("Calling package " + callingPackage + " in user "
+ + userId + " does not belong to calling uid " + callingUid);
}
+ }
- public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, ArrayList<PackageParser.Service> packageServices, int userId) {
- if (!sUserManager.exists(userId)) return null;
- if (packageServices == null) {
- return null;
- }
- mFlags = flags;
- final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final int N = packageServices.size();
- ArrayList<PackageParser.ServiceIntentInfo[]> listCut =
- new ArrayList<PackageParser.ServiceIntentInfo[]>(N);
+ @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");
- ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
- for (int i = 0; i < N; ++i) {
- intentFilters = packageServices.get(i).intents;
- if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ServiceIntentInfo[] array =
- new PackageParser.ServiceIntentInfo[intentFilters.size()];
- intentFilters.toArray(array);
- listCut.add(array);
- }
- }
- return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return packageNames;
}
- public final void addService(PackageParser.Service s) {
- mServices.put(s.getComponentName(), s);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " "
- + (s.info.nonLocalizedLabel != null
- ? s.info.nonLocalizedLabel : s.info.name) + ":");
- Log.v(TAG, " Class=" + s.info.name);
+ 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[] 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 int NI = s.intents.size();
- int j;
- for (j=0; j<NI; j++) {
- PackageParser.ServiceIntentInfo intent = s.intents.get(j);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
- }
- if (!intent.debugCheck()) {
- Log.w(TAG, "==> For Service " + s.info.name);
+ final PackageSetting pkgSetting;
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ Slog.w(TAG, "Could not find package setting for package: " + packageName
+ + ". Skipping suspending/un-suspending.");
+ unactionedPackages.add(packageName);
+ continue;
}
- addFilter(intent);
}
- }
-
- public final void removeService(PackageParser.Service s) {
- mServices.remove(s.getComponentName());
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " " + (s.info.nonLocalizedLabel != null
- ? s.info.nonLocalizedLabel : s.info.name) + ":");
- Log.v(TAG, " Class=" + s.info.name);
+ if (canSuspend != null && !canSuspend[i]) {
+ unactionedPackages.add(packageName);
+ continue;
}
- final int NI = s.intents.size();
- int j;
- for (j=0; j<NI; j++) {
- PackageParser.ServiceIntentInfo intent = s.intents.get(j);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
- }
- removeFilter(intent);
+ synchronized (mPackages) {
+ pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
+ launcherExtras, userId);
}
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
- @Override
- protected boolean allowFilterResult(
- PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
- ServiceInfo filterSi = filter.service.info;
- for (int i=dest.size()-1; i>=0; i--) {
- ServiceInfo destAi = dest.get(i).serviceInfo;
- if (destAi.name == filterSi.name
- && destAi.packageName == filterSi.packageName) {
- return false;
- }
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendPackagesSuspendedForUser(
+ changedPackages, changedUids.toArray(), userId, suspended, launcherExtras);
+ sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(userId);
}
- return true;
}
+ return unactionedPackages.toArray(new String[unactionedPackages.size()]);
+ }
- @Override
- protected PackageParser.ServiceIntentInfo[] newArray(int size) {
- return new PackageParser.ServiceIntentInfo[size];
+ @Override
+ public PersistableBundle 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);
}
-
- @Override
- protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
- if (!sUserManager.exists(userId)) return true;
- PackageParser.Package p = filter.service.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting)p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
- }
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
}
- return false;
- }
-
- @Override
- protected boolean isPackageForFilter(String packageName,
- PackageParser.ServiceIntentInfo info) {
- return packageName.equals(info.service.owner.packageName);
+ final PackageUserState packageUserState = ps.readUserState(userId);
+ if (packageUserState.suspended) {
+ return packageUserState.suspendedAppExtras;
+ }
+ return null;
}
+ }
- @Override
- protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
- int match, int userId) {
- if (!sUserManager.exists(userId)) return null;
- final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
- if (!mSettings.isEnabledAndMatchLPr(info.service.info, mFlags, userId)) {
- return null;
+ private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended,
+ PersistableBundle appExtras, int userId) {
+ final String action;
+ final Bundle intentExtras = new Bundle();
+ if (suspended) {
+ action = Intent.ACTION_MY_PACKAGE_SUSPENDED;
+ if (appExtras != null) {
+ final Bundle bundledAppExtras = new Bundle(appExtras.deepCopy());
+ intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, bundledAppExtras);
}
- final PackageParser.Service service = info.service;
- PackageSetting ps = (PackageSetting) service.owner.mExtras;
- if (ps == null) {
- return null;
- }
- final PackageUserState userState = ps.readUserState(userId);
- ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
- userState, userId);
- if (si == null) {
- return null;
- }
- final boolean matchVisibleToInstantApp =
- (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
- final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
- // throw out filters that aren't visible to ephemeral apps
- if (matchVisibleToInstantApp
- && !(info.isVisibleToInstantApp() || userState.instantApp)) {
- return null;
- }
- // throw out ephemeral filters if we're not explicitly requesting them
- if (!isInstantApp && userState.instantApp) {
- return null;
+ } else {
+ action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
+ }
+ mHandler.post(() -> {
+ try {
+ 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) {
+ doSendBroadcast(am, action, null, intentExtras,
+ Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
+ targetUserIds, false);
+ }
+ } catch (RemoteException ex) {
+ // Shouldn't happen as AMS is in the same process.
}
- // throw out instant app filters if updates are available; will trigger
- // instant app resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
- return null;
+ });
+ }
+
+ @Override
+ public boolean isPackageSuspendedForUser(String packageName, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "isPackageSuspendedForUser for user " + userId);
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+ throw new IllegalArgumentException("Unknown target package: " + packageName);
}
- final ResolveInfo res = new ResolveInfo();
- res.serviceInfo = si;
- if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
- res.filter = filter;
- }
- res.priority = info.getPriority();
- res.preferredOrder = service.owner.mPreferredOrder;
- res.match = match;
- res.isDefault = info.hasDefault;
- res.labelRes = info.labelRes;
- res.nonLocalizedLabel = info.nonLocalizedLabel;
- res.icon = info.icon;
- res.system = res.serviceInfo.applicationInfo.isSystemApp();
- return res;
+ return ps.getSuspended(userId);
}
+ }
- @Override
- protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
+ /**
+ * Immediately unsuspends any packages suspended by the given package. To be called
+ * when such a package's data is cleared or it is removed from the device.
+ *
+ * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
+ * synchronously
+ *
+ * @param packageName The package holding {@link Manifest.permission#SUSPEND_APPS} permission
+ * @param affectedUser The user for which the changes are taking place.
+ */
+ void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+ final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+ : new int[] {affectedUser};
+ for (int userId : userIds) {
+ unsuspendForSuspendingPackages(packageName::equals, userId);
}
+ }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ServiceIntentInfo filter) {
- out.print(prefix); out.print(
- Integer.toHexString(System.identityHashCode(filter.service)));
- out.print(' ');
- filter.service.printComponentShortName(out);
- out.print(" filter ");
- out.println(Integer.toHexString(System.identityHashCode(filter)));
+ /**
+ * Immediately unsuspends any packages in the given users not suspended by the platform or root.
+ * To be called when a profile owner or a device owner is added.
+ *
+ * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
+ * synchronously
+ *
+ * @param userIds The users for which to unsuspend packages
+ */
+ void unsuspendForNonSystemSuspendingPackages(ArraySet<Integer> userIds) {
+ final int sz = userIds.size();
+ for (int i = 0; i < sz; i++) {
+ unsuspendForSuspendingPackages(
+ (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ userIds.valueAt(i));
}
+ }
- @Override
- protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) {
- return filter.service;
+ private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
+ final List<String> affectedPackages = new ArrayList<>();
+ final IntArray affectedUids = new IntArray();
+ synchronized (mPackages) {
+ for (PackageSetting ps : mSettings.mPackages.values()) {
+ final PackageUserState pus = ps.readUserState(userId);
+ if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
+ ps.setSuspended(false, null, null, null, null, userId);
+ affectedPackages.add(ps.name);
+ affectedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+ }
+ }
+ }
+ if (!affectedPackages.isEmpty()) {
+ final String[] packageArray = affectedPackages.toArray(
+ new String[affectedPackages.size()]);
+ sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
+ sendPackagesSuspendedForUser(
+ packageArray, affectedUids.toArray(), userId, false, null);
+ // Write package restrictions immediately to avoid an inconsistent state.
+ mSettings.writePackageRestrictionsLPr(userId);
}
+ }
- protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- PackageParser.Service service = (PackageParser.Service)label;
- out.print(prefix); out.print(
- Integer.toHexString(System.identityHashCode(service)));
- out.print(' ');
- service.printComponentShortName(out);
- if (count > 1) {
- out.print(" ("); out.print(count); out.print(" filters)");
+ @Override
+ public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
+ Preconditions.checkNotNull("packageNames cannot be null", packageNames);
+ 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);
+ }
+ 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]);
}
- out.println();
}
-
-// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
-// final Iterator<ResolveInfo> i = resolveInfoList.iterator();
-// final List<ResolveInfo> retList = Lists.newArrayList();
-// while (i.hasNext()) {
-// final ResolveInfo resolveInfo = (ResolveInfo) i;
-// if (isEnabledLP(resolveInfo.serviceInfo)) {
-// retList.add(resolveInfo);
-// }
-// }
-// return retList;
-// }
-
- // Keys are String (activity class name), values are Activity.
- private final ArrayMap<ComponentName, PackageParser.Service> mServices
- = new ArrayMap<ComponentName, PackageParser.Service>();
- private int mFlags;
+ return unactionablePackages.toArray(new String[unactionablePackages.size()]);
}
- private final class ProviderIntentResolver
- extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
- boolean defaultOnly, int userId) {
- mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(intent, resolvedType, defaultOnly, userId);
- }
-
- public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
- int userId) {
- if (!sUserManager.exists(userId))
- return null;
- mFlags = flags;
- return super.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId);
- }
-
- public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
- int flags, ArrayList<PackageParser.Provider> packageProviders, int userId) {
- if (!sUserManager.exists(userId))
- return null;
- if (packageProviders == null) {
- return null;
- }
- mFlags = flags;
- final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
- final int N = packageProviders.size();
- ArrayList<PackageParser.ProviderIntentInfo[]> listCut =
- new ArrayList<PackageParser.ProviderIntentInfo[]>(N);
+ /**
+ * 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 long callingId = Binder.clearCallingIdentity();
+ try {
+ final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ final String dialerPackageName = getDefaultDialerPackageName(userId);
+ for (int i = 0; i < packageNames.length; i++) {
+ canSuspend[i] = false;
+ final String packageName = packageNames[i];
- ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
- for (int i = 0; i < N; ++i) {
- intentFilters = packageProviders.get(i).intents;
- if (intentFilters != null && intentFilters.size() > 0) {
- PackageParser.ProviderIntentInfo[] array =
- new PackageParser.ProviderIntentInfo[intentFilters.size()];
- intentFilters.toArray(array);
- listCut.add(array);
+ if (isPackageDeviceAdmin(packageName, userId)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": has an active device admin");
+ continue;
}
- }
- return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
- }
-
- public final void addProvider(PackageParser.Provider p) {
- if (mProviders.containsKey(p.getComponentName())) {
- Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
- return;
- }
-
- mProviders.put(p.getComponentName(), p);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " "
- + (p.info.nonLocalizedLabel != null
- ? p.info.nonLocalizedLabel : p.info.name) + ":");
- Log.v(TAG, " Class=" + p.info.name);
- }
- final int NI = p.intents.size();
- int j;
- for (j = 0; j < NI; j++) {
- PackageParser.ProviderIntentInfo intent = p.intents.get(j);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
+ 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 (!intent.debugCheck()) {
- Log.w(TAG, "==> For Provider " + p.info.name);
+ if (packageName.equals(mRequiredUninstallerPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for package uninstallation");
+ continue;
}
- addFilter(intent);
- }
- }
-
- public final void removeProvider(PackageParser.Provider p) {
- mProviders.remove(p.getComponentName());
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " " + (p.info.nonLocalizedLabel != null
- ? p.info.nonLocalizedLabel : p.info.name) + ":");
- Log.v(TAG, " Class=" + p.info.name);
- }
- final int NI = p.intents.size();
- int j;
- for (j = 0; j < NI; j++) {
- PackageParser.ProviderIntentInfo intent = p.intents.get(j);
- if (DEBUG_SHOW_INFO) {
- Log.v(TAG, " IntentFilter:");
- intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
+ if (packageName.equals(mRequiredVerifierPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for package verification");
+ continue;
}
- removeFilter(intent);
- }
- }
-
- @Override
- protected boolean allowFilterResult(
- PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) {
- ProviderInfo filterPi = filter.provider.info;
- for (int i = dest.size() - 1; i >= 0; i--) {
- ProviderInfo destPi = dest.get(i).providerInfo;
- if (destPi.name == filterPi.name
- && destPi.packageName == filterPi.packageName) {
- return false;
+ if (packageName.equals(dialerPackageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": is the default dialer");
+ continue;
}
- }
- return true;
- }
-
- @Override
- protected PackageParser.ProviderIntentInfo[] newArray(int size) {
- return new PackageParser.ProviderIntentInfo[size];
- }
+ if (packageName.equals(mRequiredPermissionControllerPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for permissions management");
+ continue;
+ }
+ synchronized (mPackages) {
+ if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": protected package");
+ continue;
+ }
- @Override
- protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) {
- if (!sUserManager.exists(userId))
- return true;
- PackageParser.Package p = filter.provider.owner;
- if (p != null) {
- PackageSetting ps = (PackageSetting) p.mExtras;
- if (ps != null) {
- // System apps are never considered stopped for purposes of
- // filtering, because there may be no way for the user to
- // actually re-launch them.
- return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
- && ps.getStopped(userId);
+ // 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.
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+ Slog.w(TAG, "Cannot suspend package: " + packageName
+ + " providing static shared library: "
+ + pkg.staticSharedLibName);
+ continue;
+ }
+ }
+ if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+ Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
+ continue;
}
+ canSuspend[i] = true;
}
- return false;
- }
-
- @Override
- protected boolean isPackageForFilter(String packageName,
- PackageParser.ProviderIntentInfo info) {
- return packageName.equals(info.provider.owner.packageName);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
+ return canSuspend;
+ }
- @Override
- protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter,
- int match, int userId) {
- if (!sUserManager.exists(userId))
- return null;
- final PackageParser.ProviderIntentInfo info = filter;
- if (!mSettings.isEnabledAndMatchLPr(info.provider.info, mFlags, userId)) {
- return null;
- }
- final PackageParser.Provider provider = info.provider;
- PackageSetting ps = (PackageSetting) provider.owner.mExtras;
- if (ps == null) {
- return null;
- }
- final PackageUserState userState = ps.readUserState(userId);
- final boolean matchVisibleToInstantApp =
- (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
- final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
- // throw out filters that aren't visible to instant applications
- if (matchVisibleToInstantApp
- && !(info.isVisibleToInstantApp() || userState.instantApp)) {
- return null;
- }
- // throw out instant application filters if we're not explicitly requesting them
- if (!isInstantApp && userState.instantApp) {
- return null;
- }
- // throw out instant application filters if updates are available; will trigger
- // instant application resolution
- if (userState.instantApp && ps.isUpdateAvailable()) {
- return null;
- }
- ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags,
- userState, userId);
- if (pi == null) {
- return null;
- }
- final ResolveInfo res = new ResolveInfo();
- res.providerInfo = pi;
- if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
- res.filter = filter;
- }
- res.priority = info.getPriority();
- res.preferredOrder = provider.owner.mPreferredOrder;
- res.match = match;
- res.isDefault = info.hasDefault;
- res.labelRes = info.labelRes;
- res.nonLocalizedLabel = info.nonLocalizedLabel;
- res.icon = info.icon;
- res.system = res.providerInfo.applicationInfo.isSystemApp();
- return res;
- }
+ private String getActiveLauncherPackageName(int userId) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = resolveIntent(
+ intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ userId);
- @Override
- protected void sortResults(List<ResolveInfo> results) {
- Collections.sort(results, mResolvePrioritySorter);
- }
+ return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
+ }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PackageParser.ProviderIntentInfo filter) {
- out.print(prefix);
- out.print(
- Integer.toHexString(System.identityHashCode(filter.provider)));
- out.print(' ');
- filter.provider.printComponentShortName(out);
- out.print(" filter ");
- out.println(Integer.toHexString(System.identityHashCode(filter)));
+ @Nullable
+ private String getDefaultDialerPackageName(@UserIdInt int userId) {
+ PackageManagerInternal.DefaultDialerProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultDialerProvider;
}
-
- @Override
- protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) {
- return filter.provider;
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultDialerProvider is null");
+ return null;
}
+ return provider.getDefaultDialer(userId);
+ }
- protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
- PackageParser.Provider provider = (PackageParser.Provider)label;
- out.print(prefix); out.print(
- Integer.toHexString(System.identityHashCode(provider)));
- out.print(' ');
- provider.printComponentShortName(out);
- if (count > 1) {
- out.print(" ("); out.print(count); out.print(" filters)");
- }
- out.println();
- }
+ @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");
- private final ArrayMap<ComponentName, PackageParser.Provider> mProviders
- = new ArrayMap<ComponentName, PackageParser.Provider>();
- private int mFlags;
+ final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCode, Binder.getCallingUid());
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessage(msg);
}
- static final class EphemeralIntentResolver
- extends IntentResolver<AuxiliaryResolveInfo, AuxiliaryResolveInfo> {
- /**
- * The result that has the highest defined order. Ordering applies on a
- * per-package basis. Mapping is from package name to Pair of order and
- * EphemeralResolveInfo.
- * <p>
- * NOTE: This is implemented as a field variable for convenience and efficiency.
- * By having a field variable, we're able to track filter ordering as soon as
- * a non-zero order is defined. Otherwise, multiple loops across the result set
- * would be needed to apply ordering. If the intent resolver becomes re-entrant,
- * this needs to be contained entirely within {@link #filterResults}.
- */
- final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = new ArrayMap<>();
+ @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");
- @Override
- protected AuxiliaryResolveInfo[] newArray(int size) {
- return new AuxiliaryResolveInfo[size];
- }
+ final PackageVerificationState state = mPendingVerification.get(id);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCodeAtTimeout, Binder.getCallingUid());
- @Override
- protected boolean isPackageForFilter(String packageName, AuxiliaryResolveInfo responseObj) {
- return true;
+ if (millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
+ millisecondsToDelay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
}
-
- @Override
- protected AuxiliaryResolveInfo newResult(AuxiliaryResolveInfo responseObj, int match,
- int userId) {
- if (!sUserManager.exists(userId)) {
- return null;
- }
- final String packageName = responseObj.resolveInfo.getPackageName();
- final Integer order = responseObj.getOrder();
- final Pair<Integer, InstantAppResolveInfo> lastOrderResult =
- mOrderResult.get(packageName);
- // ordering is enabled and this item's order isn't high enough
- if (lastOrderResult != null && lastOrderResult.first >= order) {
- return null;
- }
- final InstantAppResolveInfo res = responseObj.resolveInfo;
- if (order > 0) {
- // non-zero order, enable ordering
- mOrderResult.put(packageName, new Pair<>(order, res));
- }
- return responseObj;
+ if (millisecondsToDelay < 0) {
+ millisecondsToDelay = 0;
+ }
+ if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
+ && (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
+ verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT;
}
- @Override
- protected void filterResults(List<AuxiliaryResolveInfo> results) {
- // only do work if ordering is enabled [most of the time it won't be]
- if (mOrderResult.size() == 0) {
- return;
- }
- int resultSize = results.size();
- for (int i = 0; i < resultSize; i++) {
- final InstantAppResolveInfo info = results.get(i).resolveInfo;
- final String packageName = info.getPackageName();
- final Pair<Integer, InstantAppResolveInfo> savedInfo = mOrderResult.get(packageName);
- if (savedInfo == null) {
- // package doesn't having ordering
- continue;
- }
- if (savedInfo.second == info) {
- // circled back to the highest ordered item; remove from order list
- mOrderResult.remove(packageName);
- if (mOrderResult.size() == 0) {
- // no more ordered items
- break;
- }
- continue;
- }
- // item has a worse order, remove it from the result list
- results.remove(i);
- resultSize--;
- i--;
- }
+ 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 static final Comparator<ResolveInfo> mResolvePrioritySorter =
- new Comparator<ResolveInfo>() {
- public int compare(ResolveInfo r1, ResolveInfo r2) {
- int v1 = r1.priority;
- int v2 = r2.priority;
- //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- v1 = r1.preferredOrder;
- v2 = r2.preferredOrder;
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- if (r1.isDefault != r2.isDefault) {
- return r1.isDefault ? -1 : 1;
- }
- v1 = r1.match;
- v2 = r2.match;
- //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
- if (v1 != v2) {
- return (v1 > v2) ? -1 : 1;
- }
- if (r1.system != r2.system) {
- return r1.system ? -1 : 1;
- }
- if (r1.activityInfo != null) {
- return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
- }
- if (r1.serviceInfo != null) {
- return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
+ private void broadcastPackageVerified(int verificationId, Uri packageUri,
+ int verificationCode, UserHandle user) {
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
+ intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+ intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
+
+ mContext.sendBroadcastAsUser(intent, user,
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+ }
+
+ private ComponentName matchComponentForVerifier(String packageName,
+ List<ResolveInfo> receivers) {
+ ActivityInfo targetReceiver = null;
+
+ final int NR = receivers.size();
+ for (int i = 0; i < NR; i++) {
+ final ResolveInfo info = receivers.get(i);
+ if (info.activityInfo == null) {
+ continue;
}
- if (r1.providerInfo != null) {
- return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
+
+ if (packageName.equals(info.activityInfo.packageName)) {
+ targetReceiver = info.activityInfo;
+ break;
}
- return 0;
}
- };
- private static final Comparator<ProviderInfo> mProviderInitOrderSorter =
- new Comparator<ProviderInfo>() {
- public int compare(ProviderInfo p1, ProviderInfo p2) {
- final int v1 = p1.initOrder;
- final int v2 = p2.initOrder;
- return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
+ if (targetReceiver == null) {
+ return null;
}
- };
-
- public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
- final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
- final int[] userIds) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- final IActivityManager am = ActivityManager.getService();
- if (am == null) return;
- final int[] resolvedUserIds;
- if (userIds == null) {
- resolvedUserIds = am.getRunningUserIds();
- } else {
- resolvedUserIds = userIds;
- }
- for (int id : resolvedUserIds) {
- final Intent intent = new Intent(action,
- pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
- if (extras != null) {
- intent.putExtras(extras);
- }
- if (targetPkg != null) {
- intent.setPackage(targetPkg);
- }
- // Modify the UID when posting to other users
- int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid > 0 && UserHandle.getUserId(uid) != id) {
- uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
- intent.putExtra(Intent.EXTRA_UID, uid);
- }
- intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
- if (DEBUG_BROADCASTS) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "Sending to user " + id + ": "
- + intent.toShortString(false, true, false, false)
- + " " + intent.getExtras(), here);
- }
- am.broadcastIntent(null, intent, null, finishedReceiver,
- 0, null, null, null, android.app.AppOpsManager.OP_NONE,
- null, finishedReceiver != null, false, id);
- }
- } catch (RemoteException ex) {
- }
- }
- });
- }
- /**
- * Check if the external storage media is available. This is true if there
- * is a mounted external storage medium or if the external storage is
- * emulated.
- */
- private boolean isExternalMediaAvailable() {
- return mMediaMounted || Environment.isExternalStorageEmulated();
+ return new ComponentName(targetReceiver.packageName, targetReceiver.name);
}
- @Override
- public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
+ List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
+ if (pkgInfo.verifiers.length == 0) {
return null;
}
- // writer
- synchronized (mPackages) {
- if (!isExternalMediaAvailable()) {
- // If the external storage is no longer mounted at this point,
- // the caller may not have been able to delete all of this
- // packages files and can not delete any more. Bail.
- return null;
- }
- final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned;
- if (lastPackage != null) {
- pkgs.remove(lastPackage);
- }
- if (pkgs.size() > 0) {
- return pkgs.get(0);
- }
- }
- return null;
- }
- void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
- final Message msg = mHandler.obtainMessage(START_CLEANING_PACKAGE,
- userId, andCode ? 1 : 0, packageName);
- if (mSystemReady) {
- msg.sendToTarget();
- } else {
- if (mPostSystemReadyMessages == null) {
- mPostSystemReadyMessages = new ArrayList<>();
+ final int N = pkgInfo.verifiers.length;
+ final List<ComponentName> sufficientVerifiers = new ArrayList<>(N + 1);
+ for (int i = 0; i < N; i++) {
+ final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
+
+ final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
+ receivers);
+ if (comp == null) {
+ continue;
}
- mPostSystemReadyMessages.add(msg);
- }
- }
- void startCleaningPackages() {
- // reader
- if (!isExternalMediaAvailable()) {
- return;
- }
- synchronized (mPackages) {
- if (mSettings.mPackagesToBeCleaned.isEmpty()) {
- return;
- }
- }
- Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
- intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
- IActivityManager am = ActivityManager.getService();
- if (am != null) {
- int dcsUid = -1;
- synchronized (mPackages) {
- if (!mDefaultContainerWhitelisted) {
- mDefaultContainerWhitelisted = true;
- PackageSetting ps = mSettings.mPackages.get(DEFAULT_CONTAINER_PACKAGE);
- dcsUid = UserHandle.getUid(UserHandle.USER_SYSTEM, ps.appId);
- }
+ final int verifierUid = getUidForVerifier(verifierInfo);
+ if (verifierUid == -1) {
+ continue;
}
- try {
- if (dcsUid > 0) {
- am.backgroundWhitelistUid(dcsUid);
- }
- am.startService(null, intent, null, false, mContext.getOpPackageName(),
- UserHandle.USER_SYSTEM);
- } catch (RemoteException e) {
+
+ if (DEBUG_VERIFY) {
+ Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
+ + " with the correct signature");
}
+ sufficientVerifiers.add(comp);
+ verificationState.addSufficientVerifier(verifierUid);
}
+
+ return sufficientVerifiers;
}
- @Override
- public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
- int installFlags, String installerPackageName, int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+ private int getUidForVerifier(VerifierInfo verifierInfo) {
+ synchronized (mPackages) {
+ final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
+ if (pkg == null) {
+ return -1;
+ } else if (pkg.mSigningDetails.signatures.length != 1) {
+ Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ + " has more than one signature; ignoring");
+ return -1;
+ }
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
+ /*
+ * If the public key of the package's signature does not match
+ * our expected public key, then this is a different package and
+ * we should skip.
+ */
- if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
+ final byte[] expectedPublicKey;
try {
- if (observer != null) {
- observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
- }
- } catch (RemoteException re) {
+ final Signature verifierSig = pkg.mSigningDetails.signatures[0];
+ final PublicKey publicKey = verifierSig.getPublicKey();
+ expectedPublicKey = publicKey.getEncoded();
+ } catch (CertificateException e) {
+ return -1;
}
- return;
- }
- if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
- installFlags |= PackageManager.INSTALL_FROM_ADB;
+ final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
- } else {
- // Caller holds INSTALL_PACKAGES permission, so we're less strict
- // about installerPackageName.
+ if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
+ Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ + " does not have the expected public key; ignoring");
+ return -1;
+ }
- installFlags &= ~PackageManager.INSTALL_FROM_ADB;
- installFlags &= ~PackageManager.INSTALL_ALL_USERS;
+ return pkg.applicationInfo.uid;
}
+ }
- UserHandle user;
- if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
- user = UserHandle.ALL;
- } else {
- user = new UserHandle(userId);
- }
+ private void setEnableRollbackCode(int token, int enableRollbackCode) {
+ final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
+ msg.arg1 = token;
+ msg.arg2 = enableRollbackCode;
+ mHandler.sendMessage(msg);
+ }
- // Only system components can circumvent runtime permissions when installing.
- if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
- && mContext.checkCallingOrSelfPermission(Manifest.permission
- .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException("You need the "
- + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
- + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
- }
+ @Override
+ public void finishPackageInstall(int token, boolean didLaunch) {
+ enforceSystemOrRoot("Only the system is allowed to finish installs");
- if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
- || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- throw new IllegalArgumentException(
- "New installs into ASEC containers no longer supported");
+ if (DEBUG_INSTALL) {
+ Slog.v(TAG, "BM finishing package install for " + token);
}
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- final File originFile = new File(originPath);
- final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
-
- final Message msg = mHandler.obtainMessage(INIT_COPY);
- final VerificationInfo verificationInfo = new VerificationInfo(
- null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
- final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
- installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
- null /*packageAbiOverride*/, null /*grantedPermissions*/,
- null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
- params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
-
+ final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
mHandler.sendMessage(msg);
}
-
/**
- * Ensure that the install reason matches what we know about the package installer (e.g. whether
- * it is acting on behalf on an enterprise or the user).
+ * Get the verification agent timeout. Used for both the APK verifier and the
+ * intent filter verifier.
*
- * Note that the ordering of the conditionals in this method is important. The checks we perform
- * are as follows, in this order:
+ * @return verification timeout in milliseconds
+ */
+ private long getVerificationTimeout() {
+ return android.provider.Settings.Global.getLong(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
+ DEFAULT_VERIFICATION_TIMEOUT);
+ }
+
+ /**
+ * Get the default verification agent response code.
*
- * 1) If the install is being performed by a system app, we can trust the app to have set the
- * install reason correctly. Thus, we pass through the install reason unchanged, no matter
- * what it is.
- * 2) If the install is being performed by a device or profile owner app, the install reason
- * should be enterprise policy. However, we cannot be sure that the device or profile owner
- * set the install reason correctly. If the app targets an older SDK version where install
- * reasons did not exist yet, or if the app author simply forgot, the install reason may be
- * unset or wrong. Thus, we force the install reason to be enterprise policy.
- * 3) In all other cases, the install is being performed by a regular app that is neither part
- * of the system nor a device or profile owner. We have no reason to believe that this app is
- * acting on behalf of the enterprise admin. Thus, we check whether the install reason was
- * set to enterprise policy and if so, change it to unknown instead.
+ * @return default verification response code
*/
- private int fixUpInstallReason(String installerPackageName, int installerUid,
- int installReason) {
- if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
- == PERMISSION_GRANTED) {
- // If the install is being performed by a system app, we trust that app to have set the
- // install reason correctly.
- return installReason;
+ private int getDefaultVerificationResponse(UserHandle user) {
+ if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
+ return PackageManager.VERIFICATION_REJECT;
}
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+ DEFAULT_VERIFICATION_RESPONSE);
+ }
- final IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
- if (dpm != null) {
- ComponentName owner = null;
- try {
- owner = dpm.getDeviceOwnerComponent(true /* callingUserOnly */);
- if (owner == null) {
- owner = dpm.getProfileOwner(UserHandle.getUserId(installerUid));
- }
- } catch (RemoteException e) {
- }
- if (owner != null && owner.getPackageName().equals(installerPackageName)) {
- // If the install is being performed by a device or profile owner, the install
- // reason should be enterprise policy.
- return PackageManager.INSTALL_REASON_POLICY;
- }
+ /**
+ * Check whether or not package verification has been enabled.
+ *
+ * @return true if verification should be performed
+ */
+ private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
+ if (!DEFAULT_VERIFY_ENABLE) {
+ return false;
}
- if (installReason == PackageManager.INSTALL_REASON_POLICY) {
- // If the install is being performed by a regular app (i.e. neither system app nor
- // device or profile owner), we have no reason to believe that the app is acting on
- // behalf of an enterprise. If the app set the install reason to enterprise policy,
- // change it to unknown instead.
- return PackageManager.INSTALL_REASON_UNKNOWN;
+ if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+ return false;
}
- // If the install is being performed by a regular app and the install reason was set to any
- // value but enterprise policy, leave the install reason unchanged.
- return installReason;
- }
+ boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
- void installStage(String packageName, File stagedDir, String stagedCid,
- IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
- String installerPackageName, int installerUid, UserHandle user,
- Certificate[][] certificates) {
- if (DEBUG_EPHEMERAL) {
- if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + packageName);
+ // Check if installing from ADB
+ if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
+ // Do not run verification in a test harness environment
+ if (ActivityManager.isRunningInTestHarness()) {
+ return false;
+ }
+ if (ensureVerifyAppsEnabled) {
+ return true;
+ }
+ // Check if the developer does not want package verification for ADB installs
+ if (android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
+ return false;
}
- }
- final VerificationInfo verificationInfo = new VerificationInfo(
- sessionParams.originatingUri, sessionParams.referrerUri,
- sessionParams.originatingUid, installerUid);
-
- final OriginInfo origin;
- if (stagedDir != null) {
- origin = OriginInfo.fromStagedFile(stagedDir);
} else {
- origin = OriginInfo.fromStagedContainer(stagedCid);
+ // only when not installed from ADB, skip verification for instant apps when
+ // the installer and verifier are the same.
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ if (mInstantAppInstallerActivity != null
+ && mInstantAppInstallerActivity.packageName.equals(
+ mRequiredVerifierPackage)) {
+ try {
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(installerUid, mRequiredVerifierPackage);
+ if (DEBUG_VERIFY) {
+ Slog.i(TAG, "disable verification for instant app");
+ }
+ return false;
+ } catch (SecurityException ignore) { }
+ }
+ }
}
- final Message msg = mHandler.obtainMessage(INIT_COPY);
- final int installReason = fixUpInstallReason(installerPackageName, installerUid,
- sessionParams.installReason);
- final InstallParams params = new InstallParams(origin, null, observer,
- sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
- verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, certificates, installReason);
- params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
- msg.obj = params;
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
- System.identityHashCode(msg.obj));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(msg.obj));
+ if (ensureVerifyAppsEnabled) {
+ return true;
+ }
- mHandler.sendMessage(msg);
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
}
- private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
- int userId) {
- final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
- sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
- false /*startReceiver*/, pkgSetting.appId, userId);
+ @Override
+ public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
+ throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
+ "Only intentfilter verification agents can verify applications");
- // Send a session commit broadcast
- final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
- info.installReason = pkgSetting.getInstallReason(userId);
- info.appPackageName = packageName;
- sendSessionCommitBroadcast(info, userId);
+ final Message msg = mHandler.obtainMessage(INTENT_FILTER_VERIFIED);
+ final IntentFilterVerificationResponse response = new IntentFilterVerificationResponse(
+ Binder.getCallingUid(), verificationCode, failedDomains);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessage(msg);
}
- public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int... userIds) {
- if (ArrayUtils.isEmpty(userIds)) {
- return;
+ @Override
+ public int getIntentVerificationStatus(String packageName, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (UserHandle.getUserId(callingUid) != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "getIntentVerificationStatus" + userId);
}
- Bundle extras = new Bundle(1);
- // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast
- extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userIds[0], appId));
-
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- packageName, extras, 0, null, null, userIds);
- if (sendBootCompleted) {
- mHandler.post(() -> {
- for (int userId : userIds) {
- sendBootCompletedBroadcastToSystemApp(
- packageName, includeStopped, userId);
- }
- }
- );
- }
- }
-
- /**
- * The just-installed/enabled app is bundled on the system, so presumed to be able to run
- * automatically without needing an explicit launch.
- * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
- */
- private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
- int userId) {
- // If user is not running, the app didn't miss any broadcast
- if (!mUserManagerInternal.isUserRunning(userId)) {
- return;
- }
- final IActivityManager am = ActivityManager.getService();
- try {
- // Deliver LOCKED_BOOT_COMPLETED first
- Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
- .setPackage(packageName);
- if (includeStopped) {
- lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- }
- final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
- am.broadcastIntent(null, lockedBcIntent, null, null, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, null, false, false, userId);
-
- // Deliver BOOT_COMPLETED only if user is unlocked
- if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) {
- Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
- if (includeStopped) {
- bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- }
- am.broadcastIntent(null, bcIntent, null, null, 0, null, null, requiredPermissions,
- android.app.AppOpsManager.OP_NONE, null, false, false, userId);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
- public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
- int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
- PackageSetting pkgSetting;
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "setApplicationHiddenSetting for user " + userId);
-
- if (hidden && isPackageDeviceAdmin(packageName, userId)) {
- Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin");
- return false;
- }
-
- long callingId = Binder.clearCallingIdentity();
- try {
- boolean sendAdded = false;
- boolean sendRemoved = false;
- // writer
- synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null) {
- return false;
- }
- if (filterAppAccessLPr(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.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.staticSharedLibName != null) {
- Slog.w(TAG, "Cannot hide package: " + packageName
- + " providing static shared library: "
- + pkg.staticSharedLibName);
- return false;
- }
- // Only allow protected packages to hide themselves.
- if (hidden && !UserHandle.isSameApp(callingUid, pkgSetting.appId)
- && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
- Slog.w(TAG, "Not hiding protected package: " + packageName);
- return false;
- }
-
- if (pkgSetting.getHidden(userId) != hidden) {
- pkgSetting.setHidden(hidden, userId);
- mSettings.writePackageRestrictionsLPr(userId);
- if (hidden) {
- sendRemoved = true;
- } else {
- sendAdded = true;
- }
- }
- }
- if (sendAdded) {
- sendPackageAddedForUser(packageName, pkgSetting, userId);
- return true;
- }
- if (sendRemoved) {
- killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
- "hiding pkg");
- sendApplicationHiddenForUser(packageName, pkgSetting, userId);
- return true;
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- return false;
- }
-
- private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
- int userId) {
- final PackageRemovedInfo info = new PackageRemovedInfo(this);
- info.removedPackage = packageName;
- info.installerPackageName = pkgSetting.installerPackageName;
- info.removedUsers = new int[] {userId};
- info.broadcastUsers = new int[] {userId};
- info.uid = UserHandle.getUid(userId, pkgSetting.appId);
- info.sendPackageRemovedBroadcasts(true /*killApp*/);
- }
-
- private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
- if (pkgList.length > 0) {
- Bundle extras = new Bundle(1);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
-
- sendPackageBroadcast(
- suspended ? Intent.ACTION_PACKAGES_SUSPENDED
- : Intent.ACTION_PACKAGES_UNSUSPENDED,
- null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
- new int[] {userId});
- }
- }
-
- /**
- * 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;
- long callingId = Binder.clearCallingIdentity();
- try {
- // writer
- synchronized (mPackages) {
- ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- return true;
- }
- if (filterAppAccessLPr(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) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
- null);
- PackageSetting pkgSetting;
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "installExistingPackage for user " + userId);
- if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
- return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
- }
-
- long callingId = Binder.clearCallingIdentity();
- try {
- boolean installed = false;
- final boolean instantApp =
- (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- final boolean fullApp =
- (installFlags & PackageManager.INSTALL_FULL_APP) != 0;
-
- // writer
- synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null) {
- return PackageManager.INSTALL_FAILED_INVALID_URI;
- }
- if (!canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
- // only allow the existing package to be used if it's installed as a full
- // application for at least one user
- boolean installAllowed = false;
- for (int checkUserId : sUserManager.getUserIds()) {
- installAllowed = !pkgSetting.getInstantApp(checkUserId);
- if (installAllowed) {
- break;
- }
- }
- if (!installAllowed) {
- return PackageManager.INSTALL_FAILED_INVALID_URI;
- }
- }
- if (!pkgSetting.getInstalled(userId)) {
- pkgSetting.setInstalled(true, userId);
- pkgSetting.setHidden(false, userId);
- pkgSetting.setInstallReason(installReason, userId);
- mSettings.writePackageRestrictionsLPr(userId);
- mSettings.writeKernelMappingLPr(pkgSetting);
- installed = true;
- } else if (fullApp && pkgSetting.getInstantApp(userId)) {
- // upgrade app from instant to full; we don't allow app downgrade
- installed = true;
- }
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
- }
-
- if (installed) {
- if (pkgSetting.pkg != null) {
- synchronized (mInstallLock) {
- // We don't need to freeze for a brand new install
- prepareAppDataAfterInstallLIF(pkgSetting.pkg);
- }
- }
- sendPackageAddedForUser(packageName, pkgSetting, userId);
- synchronized (mPackages) {
- updateSequenceNumberLP(pkgSetting, new int[]{ userId });
- }
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- void setInstantAppForUser(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 : sUserManager.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 = sUserManager.getUserRestrictions(userId);
- if (restrictions.getBoolean(restrictionKey, false)) {
- Log.w(TAG, "User is restricted: " + restrictionKey);
- return true;
- }
- return false;
- }
-
- @Override
- public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
- int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "setPackagesSuspended for user " + userId);
-
- if (ArrayUtils.isEmpty(packageNames)) {
- return packageNames;
- }
-
- // List of package names for whom the suspended state has changed.
- List<String> changedPackages = new ArrayList<>(packageNames.length);
- // List of package names for whom the suspended state is not set as requested in this
- // method.
- List<String> unactionedPackages = new ArrayList<>(packageNames.length);
- long callingId = Binder.clearCallingIdentity();
- try {
- for (int i = 0; i < packageNames.length; i++) {
- String packageName = packageNames[i];
- boolean changed = false;
- final int appId;
- synchronized (mPackages) {
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null
- || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
- Slog.w(TAG, "Could not find package setting for package \"" + packageName
- + "\". Skipping suspending/un-suspending.");
- unactionedPackages.add(packageName);
- continue;
- }
- appId = pkgSetting.appId;
- if (pkgSetting.getSuspended(userId) != suspended) {
- if (!canSuspendPackageForUserLocked(packageName, userId)) {
- unactionedPackages.add(packageName);
- continue;
- }
- pkgSetting.setSuspended(suspended, userId);
- mSettings.writePackageRestrictionsLPr(userId);
- changed = true;
- changedPackages.add(packageName);
- }
- }
-
- if (changed && suspended) {
- killApplication(packageName, UserHandle.getUid(userId, appId),
- "suspending package");
- }
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
-
- if (!changedPackages.isEmpty()) {
- sendPackagesSuspendedForUser(changedPackages.toArray(
- new String[changedPackages.size()]), userId, suspended);
- }
-
- return unactionedPackages.toArray(new String[unactionedPackages.size()]);
- }
-
- @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 (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown target package: " + packageName);
- }
- return ps.getSuspended(userId);
- }
- }
-
- private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
- if (isPackageDeviceAdmin(packageName, userId)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": has an active device admin");
- return false;
- }
-
- String activeLauncherPackageName = getActiveLauncherPackageName(userId);
- if (packageName.equals(activeLauncherPackageName)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": contains the active launcher");
- return false;
- }
-
- if (packageName.equals(mRequiredInstallerPackage)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": required for package installation");
- return false;
- }
-
- if (packageName.equals(mRequiredUninstallerPackage)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": required for package uninstallation");
- return false;
- }
-
- if (packageName.equals(mRequiredVerifierPackage)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": required for package verification");
- return false;
- }
-
- if (packageName.equals(getDefaultDialerPackageName(userId))) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": is the default dialer");
- return false;
- }
-
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
- Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
- + "\": protected package");
- return false;
- }
-
- // 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.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
- Slog.w(TAG, "Cannot suspend package: " + packageName
- + " providing static shared library: "
- + pkg.staticSharedLibName);
- return false;
- }
-
- return true;
- }
-
- private String getActiveLauncherPackageName(int userId) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = resolveIntent(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY,
- userId);
-
- return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
- }
-
- private String getDefaultDialerPackageName(int userId) {
- synchronized (mPackages) {
- return mSettings.getDefaultDialerPackageNameLPw(userId);
- }
- }
-
- @Override
- public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can verify applications");
-
- final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
- final PackageVerificationResponse response = new PackageVerificationResponse(
- verificationCode, Binder.getCallingUid());
- msg.arg1 = id;
- msg.obj = response;
- mHandler.sendMessage(msg);
- }
-
- @Override
- public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
- long millisecondsToDelay) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can extend verification timeouts");
-
- final PackageVerificationState state = mPendingVerification.get(id);
- final PackageVerificationResponse response = new PackageVerificationResponse(
- verificationCodeAtTimeout, Binder.getCallingUid());
-
- if (millisecondsToDelay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
- millisecondsToDelay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
- }
- if (millisecondsToDelay < 0) {
- millisecondsToDelay = 0;
- }
- if ((verificationCodeAtTimeout != PackageManager.VERIFICATION_ALLOW)
- && (verificationCodeAtTimeout != PackageManager.VERIFICATION_REJECT)) {
- verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT;
- }
-
- if ((state != null) && !state.timeoutExtended()) {
- state.extendTimeout();
-
- final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
- msg.arg1 = id;
- msg.obj = response;
- mHandler.sendMessageDelayed(msg, millisecondsToDelay);
- }
- }
-
- private void broadcastPackageVerified(int verificationId, Uri packageUri,
- int verificationCode, UserHandle user) {
- final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
- intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
- intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
-
- mContext.sendBroadcastAsUser(intent, user,
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
- }
-
- private ComponentName matchComponentForVerifier(String packageName,
- List<ResolveInfo> receivers) {
- ActivityInfo targetReceiver = null;
-
- final int NR = receivers.size();
- for (int i = 0; i < NR; i++) {
- final ResolveInfo info = receivers.get(i);
- if (info.activityInfo == null) {
- continue;
- }
-
- if (packageName.equals(info.activityInfo.packageName)) {
- targetReceiver = info.activityInfo;
- break;
- }
- }
-
- if (targetReceiver == null) {
- return null;
- }
-
- return new ComponentName(targetReceiver.packageName, targetReceiver.name);
- }
-
- private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
- List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
- if (pkgInfo.verifiers.length == 0) {
- return null;
- }
-
- final int N = pkgInfo.verifiers.length;
- final List<ComponentName> sufficientVerifiers = new ArrayList<ComponentName>(N + 1);
- for (int i = 0; i < N; i++) {
- final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
-
- final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
- receivers);
- if (comp == null) {
- continue;
- }
-
- final int verifierUid = getUidForVerifier(verifierInfo);
- if (verifierUid == -1) {
- continue;
- }
-
- if (DEBUG_VERIFY) {
- Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
- + " with the correct signature");
- }
- sufficientVerifiers.add(comp);
- verificationState.addSufficientVerifier(verifierUid);
- }
-
- return sufficientVerifiers;
- }
-
- private int getUidForVerifier(VerifierInfo verifierInfo) {
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
- if (pkg == null) {
- return -1;
- } else if (pkg.mSignatures.length != 1) {
- Slog.i(TAG, "Verifier package " + verifierInfo.packageName
- + " has more than one signature; ignoring");
- return -1;
- }
-
- /*
- * If the public key of the package's signature does not match
- * our expected public key, then this is a different package and
- * we should skip.
- */
-
- final byte[] expectedPublicKey;
- try {
- final Signature verifierSig = pkg.mSignatures[0];
- final PublicKey publicKey = verifierSig.getPublicKey();
- expectedPublicKey = publicKey.getEncoded();
- } catch (CertificateException e) {
- return -1;
- }
-
- final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
-
- if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
- Slog.i(TAG, "Verifier package " + verifierInfo.packageName
- + " does not have the expected public key; ignoring");
- return -1;
- }
-
- return pkg.applicationInfo.uid;
- }
- }
-
- @Override
- public void finishPackageInstall(int token, boolean didLaunch) {
- enforceSystemOrRoot("Only the system is allowed to finish installs");
-
- if (DEBUG_INSTALL) {
- Slog.v(TAG, "BM finishing package install for " + token);
- }
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
-
- final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
- mHandler.sendMessage(msg);
- }
-
- /**
- * Get the verification agent timeout. Used for both the APK verifier and the
- * intent filter verifier.
- *
- * @return verification timeout in milliseconds
- */
- private long getVerificationTimeout() {
- return android.provider.Settings.Global.getLong(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
- DEFAULT_VERIFICATION_TIMEOUT);
- }
-
- /**
- * Get the default verification agent response code.
- *
- * @return default verification response code
- */
- private int getDefaultVerificationResponse(UserHandle user) {
- if (sUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, user.getIdentifier())) {
- return PackageManager.VERIFICATION_REJECT;
- }
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
- DEFAULT_VERIFICATION_RESPONSE);
- }
-
- /**
- * Check whether or not package verification has been enabled.
- *
- * @return true if verification should be performed
- */
- private boolean isVerificationEnabled(int userId, int installFlags, int installerUid) {
- if (!DEFAULT_VERIFY_ENABLE) {
- return false;
- }
-
- boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
-
- // Check if installing from ADB
- if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
- // Do not run verification in a test harness environment
- if (ActivityManager.isRunningInTestHarness()) {
- return false;
- }
- if (ensureVerifyAppsEnabled) {
- return true;
- }
- // Check if the developer does not want package verification for ADB installs
- if (android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) {
- return false;
- }
- } else {
- // only when not installed from ADB, skip verification for instant apps when
- // the installer and verifier are the same.
- if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- if (mInstantAppInstallerActivity != null
- && mInstantAppInstallerActivity.packageName.equals(
- mRequiredVerifierPackage)) {
- try {
- mContext.getSystemService(AppOpsManager.class)
- .checkPackage(installerUid, mRequiredVerifierPackage);
- if (DEBUG_VERIFY) {
- Slog.i(TAG, "disable verification for instant app");
- }
- return false;
- } catch (SecurityException ignore) { }
- }
- }
- }
-
- if (ensureVerifyAppsEnabled) {
- return true;
- }
-
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
- }
-
- @Override
- public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
- throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
- "Only intentfilter verification agents can verify applications");
-
- final Message msg = mHandler.obtainMessage(INTENT_FILTER_VERIFIED);
- final IntentFilterVerificationResponse response = new IntentFilterVerificationResponse(
- Binder.getCallingUid(), verificationCode, failedDomains);
- msg.arg1 = id;
- msg.obj = response;
- mHandler.sendMessage(msg);
- }
-
- @Override
- public int getIntentVerificationStatus(String packageName, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (UserHandle.getUserId(callingUid) != userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "getIntentVerificationStatus" + userId);
- }
- if (getInstantAppPackageName(callingUid) != null) {
- return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
- }
- synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
- return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
- }
- return mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
+ if (getInstantAppPackageName(callingUid) != null) {
+ return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null
+ || filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+ return mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
}
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
-
+ if (userId == UserHandle.USER_ALL) {
+ return false;
+ }
+ PackageManagerInternal.DefaultBrowserProvider provider;
synchronized (mPackages) {
- boolean result = mSettings.setDefaultBrowserPackageNameLPw(packageName, userId);
- if (packageName != null) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
- packageName, userId);
+ provider = mDefaultBrowserProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultBrowserProvider is null");
+ return false;
+ }
+ boolean successful = provider.setDefaultBrowser(packageName, userId);
+ if (!successful) {
+ return false;
+ }
+ if (packageName != null) {
+ synchronized (mPackages) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
+ }
+ }
+ return true;
+ }
+
+ private void setDefaultBrowserAsyncLPw(@Nullable String packageName, @UserIdInt int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return;
+ }
+ if (mDefaultBrowserProvider == null) {
+ Slog.e(TAG, "mDefaultBrowserProvider is null");
+ return;
+ }
+ mDefaultBrowserProvider.setDefaultBrowserAsync(packageName, userId);
+ if (packageName != null) {
+ synchronized (mPackages) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
- return result;
}
}
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
+ PackageManagerInternal.DefaultBrowserProvider provider;
synchronized (mPackages) {
- return mSettings.getDefaultBrowserPackageNameLPw(userId);
+ provider = mDefaultBrowserProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultBrowserProvider is null");
+ return null;
}
+ return provider.getDefaultBrowser(userId);
}
/**
}
Signature[] callerSignature;
- Object obj = mSettings.getUserIdLPr(callingUid);
+ final int appId = UserHandle.getAppId(callingUid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
- callerSignature = ((SharedUserSetting)obj).signatures.mSignatures;
+ callerSignature =
+ ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
} else if (obj instanceof PackageSetting) {
- callerSignature = ((PackageSetting)obj).signatures.mSignatures;
+ callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures;
} else {
throw new SecurityException("Bad object " + obj + " for uid " + callingUid);
}
// not signed with the same cert as the caller.
if (installerPackageSetting != null) {
if (compareSignatures(callerSignature,
- installerPackageSetting.signatures.mSignatures)
+ installerPackageSetting.signatures.mSigningDetails.signatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
"Caller does not have same cert as new installer package "
// okay to change it.
if (setting != null) {
if (compareSignatures(callerSignature,
- setting.signatures.mSignatures)
+ setting.signatures.mSigningDetails.signatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
"Caller does not have same cert as old installer package "
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- // Result object to be returned
- PackageInstalledInfo res = new PackageInstalledInfo();
- res.setReturnCode(currentStatus);
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = null;
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- args.doPreInstall(res.returnCode);
- synchronized (mInstallLock) {
- installPackageTracedLI(args, res);
- }
- args.doPostInstall(res.returnCode, res.uid);
- }
-
- // A restore should be performed at this point if (a) the install
- // succeeded, (b) the operation is not an update, and (c) the new
- // package has not opted out of backup participation.
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
- final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
- boolean doRestore = !update
- && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
-
- // Set up the post-install work request bookkeeping. This will be used
- // and cleaned up by the post-install event handling regardless of whether
- // there's a restore pass performed. Token values are >= 1.
- int token;
- if (mNextInstallToken < 0) mNextInstallToken = 1;
- token = mNextInstallToken++;
-
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
- if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
- // Pass responsibility to the Backup Manager. It will perform a
- // restore if appropriate, then pass responsibility back to the
- // Package Manager to run the post-install observer callbacks
- // and broadcasts.
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (bm != null) {
- if (DEBUG_INSTALL) Log.v(TAG, "token " + token
- + " to BM for possible restore");
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- try {
- // TODO: http://b/22388012
- if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
- } else {
- doRestore = false;
- }
- } catch (RemoteException e) {
- // can't happen; the backup manager is local
- } catch (Exception e) {
- Slog.e(TAG, "Exception trying to enqueue restore", e);
- doRestore = false;
- }
+ if (args.mMultiPackageInstallParams != null) {
+ args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
+ } else {
+ PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
+ processInstallRequestsAsync(
+ res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+ }
+ }
+
+ // Queue up an async operation since the package installation may take a little while.
+ private void processInstallRequestsAsync(boolean success,
+ List<InstallRequest> installRequests) {
+ mHandler.post(() -> {
+ if (success) {
+ for (InstallRequest request : installRequests) {
+ request.args.doPreInstall(request.installResult.returnCode);
+ }
+ synchronized (mInstallLock) {
+ installPackagesTracedLI(installRequests);
+ }
+ for (InstallRequest request : installRequests) {
+ request.args.doPostInstall(
+ request.installResult.returnCode, request.installResult.uid);
+ }
+ }
+ for (InstallRequest request : installRequests) {
+ restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
+ new PostInstallData(request.args, request.installResult, null));
+ }
+ });
+ }
+
+ private PackageInstalledInfo createPackageInstalledInfo(
+ int currentStatus) {
+ PackageInstalledInfo res = new PackageInstalledInfo();
+ res.setReturnCode(currentStatus);
+ res.uid = -1;
+ res.pkg = null;
+ res.removedInfo = null;
+ return res;
+ }
+
+ /** @param data Post-install is performed only if this is non-null. */
+ private void restoreAndPostInstall(
+ int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package="
+ + res.pkg.packageName);
+ }
+
+ // A restore should be performed at this point if (a) the install
+ // succeeded, (b) the operation is not an update, and (c) the new
+ // package has not opted out of backup participation.
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
+ final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+ boolean doRestore = !update
+ && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
+
+ // Set up the post-install work request bookkeeping. This will be used
+ // and cleaned up by the post-install event handling regardless of whether
+ // there's a restore pass performed. Token values are >= 1.
+ int token;
+ if (mNextInstallToken < 0) mNextInstallToken = 1;
+ token = mNextInstallToken++;
+ if (data != null) {
+ mRunningInstalls.put(token, data);
+ } else if (DEBUG_INSTALL) {
+ Log.v(TAG, "No post-install required for " + token);
+ }
+
+ if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+ // Pass responsibility to the Backup Manager. It will perform a
+ // restore if appropriate, then pass responsibility back to the
+ // Package Manager to run the post-install observer callbacks
+ // and broadcasts.
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
+ // in the BackupManager. USER_ALL is used in compatibility tests.
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_SYSTEM;
+ }
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
+ }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+ try {
+ if (bm.isBackupServiceActive(userId)) {
+ bm.restoreAtInstallForUser(
+ userId, res.pkg.applicationInfo.packageName, token);
} else {
- Slog.e(TAG, "Backup Manager not found!");
doRestore = false;
}
+ } catch (RemoteException e) {
+ // can't happen; the backup manager is local
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception trying to enqueue restore", e);
+ doRestore = false;
}
+ } else {
+ Slog.e(TAG, "Backup Manager not found!");
+ doRestore = false;
+ }
+ }
- if (!doRestore) {
- // No restore possible, or the Backup Manager was mysteriously not
- // available -- just fire the post-install work request directly.
- if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+ // If this is an update to a package that might be potentially downgraded, then we
+ // need to check with the rollback manager whether there's any userdata that might
+ // need to be restored for the package.
+ //
+ // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+ IRollbackManager rm = IRollbackManager.Stub.asInterface(
+ ServiceManager.getService(Context.ROLLBACK_SERVICE));
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+ final String packageName = res.pkg.applicationInfo.packageName;
+ final String seInfo = res.pkg.applicationInfo.seInfo;
+ final int[] allUsers = sUserManager.getUserIds();
+ final int[] installedUsers;
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
- mHandler.sendMessage(msg);
+ final PackageSetting ps;
+ int appId = -1;
+ long ceDataInode = -1;
+ synchronized (mSettings) {
+ ps = mSettings.getPackageLPr(packageName);
+ if (ps != null) {
+ appId = ps.appId;
+ ceDataInode = ps.getCeDataInode(userId);
}
+
+ // NOTE: We ignore the user specified in the InstallParam because we know this is
+ // an update, and hence need to restore data for all installed users.
+ installedUsers = ps.queryInstalledUsers(allUsers, true);
}
- });
+
+ if (ps != null) {
+ try {
+ rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
+ seInfo, token);
+ } catch (RemoteException re) {
+ // Cannot happen, the RollbackManager is hosted in the same process.
+ }
+ doRestore = true;
+ }
+ }
+
+ if (!doRestore) {
+ // No restore possible, or the Backup Manager was mysteriously not
+ // available -- just fire the post-install work request directly.
+ if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+
+ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ mHandler.sendMessage(msg);
+ }
}
/**
* the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL
* handling.
*/
- void notifyFirstLaunch(final String pkgName, final String installerPackage, final int userId) {
+ 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(new Runnable() {
- @Override
- public void run() {
- for (int i = 0; i < mRunningInstalls.size(); i++) {
- final PostInstallData data = mRunningInstalls.valueAt(i);
- if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- continue;
- }
- if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) {
- // right package; but is it for the right user?
- for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
- if (userId == data.res.newUsers[uIndex]) {
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + pkgName
- + " being restored so deferring FIRST_LAUNCH");
- }
- return;
+ mHandler.post(() -> {
+ for (int i = 0; i < mRunningInstalls.size(); i++) {
+ final PostInstallData data = mRunningInstalls.valueAt(i);
+ if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ continue;
+ }
+ if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
+ // right package; but is it for the right user?
+ for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
+ if (userId == data.res.newUsers[uIndex]) {
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + packageName
+ + " being restored so deferring FIRST_LAUNCH");
}
+ return;
}
}
}
- // didn't find it, so not being restored
- if (DEBUG_BACKUP) {
- Slog.i(TAG, "Package " + pkgName + " sending normal FIRST_LAUNCH");
- }
- sendFirstLaunchBroadcast(pkgName, installerPackage, new int[] {userId});
}
+ // didn't find it, so not being restored
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
+ }
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
+ sendFirstLaunchBroadcast(packageName, installerPackage, userIds, instantUserIds);
});
}
- private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds) {
+ private void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
+ int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
- installerPkg, null, userIds);
+ installerPkg, null, userIds, instantUserIds);
}
private abstract class HandlerParams {
- private static final int MAX_RETRIES = 4;
-
- /**
- * Number of times startCopy() has been attempted and had a non-fatal
- * error.
- */
- private int mRetries = 0;
-
/** User handle for the user requesting the information or installation. */
private final UserHandle mUser;
String traceMethod;
return mUser;
}
+ /**
+ * Gets the user handle for the user that the rollback agent should
+ * use to look up information about this installation when enabling
+ * rollback.
+ */
+ UserHandle getRollbackUser() {
+ // The session for packages installed for "all" users is
+ // associated with the "system" user.
+ if (mUser == UserHandle.ALL) {
+ return UserHandle.SYSTEM;
+ }
+ return mUser;
+ }
+
HandlerParams setTraceMethod(String traceMethod) {
this.traceMethod = traceMethod;
return this;
return this;
}
- final boolean startCopy() {
- boolean res;
- try {
- if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-
- if (++mRetries > MAX_RETRIES) {
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
- mHandler.sendEmptyMessage(MCS_GIVE_UP);
- handleServiceError();
- return false;
- } else {
- handleStartCopy();
- res = true;
- }
- } catch (RemoteException e) {
- if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
- mHandler.sendEmptyMessage(MCS_RECONNECT);
- res = false;
- }
- handleReturnCode();
- return res;
- }
-
- final void serviceError() {
- if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
- handleServiceError();
+ final void startCopy() {
+ if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
+ handleStartCopy();
handleReturnCode();
}
- abstract void handleStartCopy() throws RemoteException;
- abstract void handleServiceError();
+ abstract void handleStartCopy();
abstract void handleReturnCode();
}
- private static void clearDirectory(IMediaContainerService mcs, File[] paths) {
- for (File path : paths) {
- try {
- mcs.clearDirectory(path.getAbsolutePath());
- } catch (RemoteException e) {
- }
- }
- }
-
static class OriginInfo {
/**
* Location where install is coming from, before it has been
* file, or a cluster directory. This location may be untrusted.
*/
final File file;
- final String cid;
/**
- * Flag indicating that {@link #file} or {@link #cid} has already been
- * staged, meaning downstream users don't need to defensively copy the
- * contents.
+ * Flag indicating that {@link #file} has already been staged, meaning downstream users
+ * don't need to defensively copy the contents.
*/
final boolean staged;
/**
- * Flag indicating that {@link #file} or {@link #cid} is an already
- * installed app that is being moved.
+ * Flag indicating that {@link #file} is an already installed app that is being moved.
*/
final boolean existing;
final File resolvedFile;
static OriginInfo fromNothing() {
- return new OriginInfo(null, null, false, false);
+ return new OriginInfo(null, false, false);
}
static OriginInfo fromUntrustedFile(File file) {
- return new OriginInfo(file, null, false, false);
+ return new OriginInfo(file, false, false);
}
static OriginInfo fromExistingFile(File file) {
- return new OriginInfo(file, null, false, true);
+ return new OriginInfo(file, false, true);
}
static OriginInfo fromStagedFile(File file) {
- return new OriginInfo(file, null, true, false);
- }
-
- static OriginInfo fromStagedContainer(String cid) {
- return new OriginInfo(null, cid, true, false);
+ return new OriginInfo(file, true, false);
}
- private OriginInfo(File file, String cid, boolean staged, boolean existing) {
+ private OriginInfo(File file, boolean staged, boolean existing) {
this.file = file;
- this.cid = cid;
this.staged = staged;
this.existing = existing;
- if (cid != null) {
- resolvedPath = PackageHelper.getSdDir(cid);
- resolvedFile = new File(resolvedPath);
- } else if (file != null) {
+ if (file != null) {
resolvedPath = file.getAbsolutePath();
resolvedFile = file;
} else {
}
}
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ class MultiPackageInstallParams extends HandlerParams {
+
+ private int mRet = INSTALL_SUCCEEDED;
+ @NonNull
+ private final ArrayList<InstallParams> mChildParams;
+ @NonNull
+ private final Map<InstallArgs, Integer> mCurrentState;
+
+ MultiPackageInstallParams(
+ @NonNull UserHandle user,
+ @NonNull List<ActiveInstallSession> activeInstallSessions)
+ throws PackageManagerException {
+ super(user);
+ if (activeInstallSessions.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = new ArrayList<>(activeInstallSessions.size());
+ for (int i = 0; i < activeInstallSessions.size(); i++) {
+ final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
+ childParams.mParentInstallParams = this;
+ this.mChildParams.add(childParams);
+ }
+ this.mCurrentState = new ArrayMap<>(mChildParams.size());
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (InstallParams params : mChildParams) {
+ params.handleStartCopy();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ }
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (InstallParams params : mChildParams) {
+ params.handleReturnCode();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ }
+ }
+ }
+
+ void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+ mCurrentState.put(args, currentStatus);
+ if (mCurrentState.size() != mChildParams.size()) {
+ return;
+ }
+ int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+ for (Integer status : mCurrentState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ completeStatus = status;
+ break;
+ }
+ }
+ final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
+ for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
+ installRequests.add(new InstallRequest(entry.getKey(),
+ createPackageInstalledInfo(completeStatus)));
+ }
+ processInstallRequestsAsync(
+ completeStatus == PackageManager.INSTALL_SUCCEEDED,
+ installRequests);
+ }
+ }
+
class InstallParams extends HandlerParams {
+ // TODO: see if we can collapse this into ActiveInstallSession
+
final OriginInfo origin;
final MoveInfo move;
final IPackageInstallObserver2 observer;
int installFlags;
final String installerPackageName;
final String volumeUuid;
+ private boolean mVerificationCompleted;
+ private boolean mEnableRollbackCompleted;
private InstallArgs mArgs;
- private int mRet;
+ int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
+ final List<String> whitelistedRestrictedPermissions;
final VerificationInfo verificationInfo;
- final Certificate[][] certificates;
+ final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable
+ MultiPackageInstallParams mParentInstallParams;
+ final long requiredInstalledVersionCode;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, Certificate[][] certificates, int installReason) {
+ String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+ PackageParser.SigningDetails signingDetails, int installReason,
+ long requiredInstalledVersionCode) {
super(user);
this.origin = origin;
this.move = move;
this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
this.grantedRuntimePermissions = grantedPermissions;
- this.certificates = certificates;
+ this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
+ this.signingDetails = signingDetails;
this.installReason = installReason;
+ this.requiredInstalledVersionCode = requiredInstalledVersionCode;
+ }
+
+ InstallParams(ActiveInstallSession activeInstallSession) {
+ super(activeInstallSession.getUser());
+ if (DEBUG_INSTANT) {
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
+ }
+ }
+ verificationInfo = new VerificationInfo(
+ activeInstallSession.getSessionParams().originatingUri,
+ activeInstallSession.getSessionParams().referrerUri,
+ activeInstallSession.getSessionParams().originatingUid,
+ activeInstallSession.getInstallerUid());
+ origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+ move = null;
+ installReason = fixUpInstallReason(activeInstallSession.getInstallerPackageName(),
+ activeInstallSession.getInstallerUid(),
+ activeInstallSession.getSessionParams().installReason);
+ observer = activeInstallSession.getObserver();
+ installFlags = activeInstallSession.getSessionParams().installFlags;
+ installerPackageName = activeInstallSession.getInstallerPackageName();
+ volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
+ packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
+ grantedRuntimePermissions = activeInstallSession.getSessionParams()
+ .grantedRuntimePermissions;
+ whitelistedRestrictedPermissions = activeInstallSession.getSessionParams()
+ .whitelistedRestrictedPermissions;
+ signingDetails = activeInstallSession.getSigningDetails();
+ requiredInstalledVersionCode = activeInstallSession.getSessionParams()
+ .requiredInstalledVersionCode;
}
@Override
public String toString() {
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
- + " file=" + origin.file + " cid=" + origin.cid + "}";
+ + " file=" + origin.file + "}";
}
private int installLocationPolicy(PackageInfoLite pkgLite) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
- boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
// reader
synchronized (mPackages) {
// Currently installed package which the new package is attempting to replace or
}
}
+ if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
+ if (dataOwnerPkg == null) {
+ Slog.w(TAG, "Required installed version code was "
+ + requiredInstalledVersionCode
+ + " but package is not installed");
+ return PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION;
+ }
+
+ if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
+ Slog.w(TAG, "Required installed version code was "
+ + requiredInstalledVersionCode
+ + " but actual installed version is "
+ + dataOwnerPkg.getLongVersionCode());
+ return PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION;
+ }
+ }
+
if (dataOwnerPkg != null) {
- // If installed, the package will get access to data left on the device by its
- // predecessor. As a security measure, this is permited only if this is not a
- // version downgrade or if the predecessor package is marked as debuggable and
- // a downgrade is explicitly requested.
- //
- // On debuggable platform builds, downgrades are permitted even for
- // non-debuggable packages to make testing easier. Debuggable platform builds do
- // not offer security guarantees and thus it's OK to disable some security
- // mechanisms to make debugging/testing easier on those builds. However, even on
- // debuggable builds downgrades of packages are permitted only if requested via
- // installFlags. This is because we aim to keep the behavior of debuggable
- // platform builds as close as possible to the behavior of non-debuggable
- // platform builds.
- final boolean downgradeRequested =
- (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
- final boolean packageDebuggable =
- (dataOwnerPkg.applicationInfo.flags
- & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- final boolean downgradePermitted =
- (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
- if (!downgradePermitted) {
+ if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
+ dataOwnerPkg.applicationInfo.flags)) {
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for updated system application.
if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (onSd) {
- Slog.w(TAG, "Cannot install update to system app on sdcard");
- return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
- }
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
} else {
- if (onSd) {
- // Install flag overrides everything.
- return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
- }
// If current upgrade specifies particular preference
if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
// Application explicitly specified internal.
}
}
}
- // All the special cases have been taken care of.
- // Return result based on recommended install location.
- if (onSd) {
- return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
- }
return pkgLite.recommendedInstallLocation;
}
* policy if needed and then create install arguments based
* on the install location.
*/
- public void handleStartCopy() throws RemoteException {
+ public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
- installFlags &= ~PackageManager.INSTALL_EXTERNAL;
- } else if (origin.cid != null) {
- installFlags |= PackageManager.INSTALL_EXTERNAL;
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
- final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
- if (onInt && onSd) {
- // Check if both bits are set.
- Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else if (onSd && ephemeral) {
- Slog.w(TAG, "Conflicting flags specified for installing ephemeral on external");
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else {
- pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
- packageAbiOverride);
-
- if (DEBUG_EPHEMERAL && ephemeral) {
- Slog.v(TAG, "pkgLite for install: " + pkgLite);
- }
- /*
- * If we have too little free space, try to free cache
- * before giving up.
- */
- if (!origin.staged && pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- // TODO: focus freeing disk space on the target device
- final StorageManager storage = StorageManager.from(mContext);
- final long lowThreshold = storage.getStorageLowBytes(
- Environment.getDataDirectory());
+ pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+ origin.resolvedPath, installFlags, packageAbiOverride);
- final long sizeBytes = mContainerService.calculateInstalledSize(
- origin.resolvedPath, isForwardLocked(), packageAbiOverride);
+ if (DEBUG_INSTANT && ephemeral) {
+ Slog.v(TAG, "pkgLite for install: " + pkgLite);
+ }
+ /*
+ * If we have too little free space, try to free cache
+ * before giving up.
+ */
+ if (!origin.staged && pkgLite.recommendedInstallLocation
+ == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+ // TODO: focus freeing disk space on the target device
+ final StorageManager storage = StorageManager.from(mContext);
+ final long lowThreshold = storage.getStorageLowBytes(
+ Environment.getDataDirectory());
+
+ final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
+ origin.resolvedPath, packageAbiOverride);
+ if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
- pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
- installFlags, packageAbiOverride);
+ pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+ origin.resolvedPath, installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
+ }
- /*
- * The cache free must have deleted the file we
- * downloaded to install.
- *
- * TODO: fix the "freeCache" call to not delete
- * the file we care about.
- */
- if (pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
- pkgLite.recommendedInstallLocation
+ /*
+ * The cache free must have deleted the file we downloaded to install.
+ *
+ * TODO: fix the "freeCache" call to not delete the file we care about.
+ */
+ if (pkgLite.recommendedInstallLocation
+ == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+ pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
- }
}
}
+
if (ret == PackageManager.INSTALL_SUCCEEDED) {
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
- } else if (!onSd && !onInt) {
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
+ ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+ } else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
- installFlags |= PackageManager.INSTALL_EXTERNAL;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
- if (DEBUG_EPHEMERAL) {
+ if (DEBUG_INSTANT) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
- installFlags &= ~(PackageManager.INSTALL_EXTERNAL
- |PackageManager.INSTALL_INTERNAL);
+ installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
- installFlags &= ~PackageManager.INSTALL_EXTERNAL;
}
}
}
}
final InstallArgs args = createInstallArgs(this);
+ mVerificationCompleted = true;
+ mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+ pkgLite.getLongVersionCode());
+
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
}
final PackageVerificationState verificationState = new PackageVerificationState(
- requiredUid, args);
+ requiredUid, this);
mPendingVerification.append(verificationId, verificationState);
/*
* We don't want the copy to proceed until verification
- * succeeds, so null out this field.
+ * succeeds.
*/
- mArgs = null;
+ mVerificationCompleted = false;
}
- } else {
- /*
- * No package verification is enabled, so immediately start
- * the remote call to initiate copy using temporary file.
- */
- ret = args.copyApk(mContainerService, true);
+ }
+
+ if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+ // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
+ final int enableRollbackToken = mPendingEnableRollbackToken++;
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ mPendingEnableRollback.append(enableRollbackToken, this);
+
+ final int[] installedUsers;
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
+ if (ps != null) {
+ installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
+ true);
+ } else {
+ installedUsers = new int[0];
+ }
+ }
+
+ Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
+ enableRollbackToken);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
+ installFlags);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
+ installedUsers);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
+ getRollbackUser().getIdentifier());
+ enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
+ PACKAGE_MIME_TYPE);
+ enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // Allow the broadcast to be sent before boot complete.
+ // This is needed when committing the apk part of a staged
+ // session in early boot. The rollback manager registers
+ // its receiver early enough during the boot process that
+ // it will not miss the broadcast.
+ enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
+ android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // the duration to wait for rollback to be enabled, in millis
+ long rollbackTimeout = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+ DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
+ if (rollbackTimeout < 0) {
+ rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
+ }
+ final Message msg = mHandler.obtainMessage(
+ ENABLE_ROLLBACK_TIMEOUT);
+ msg.arg1 = enableRollbackToken;
+ mHandler.sendMessageDelayed(msg, rollbackTimeout);
+ }
+ }, null, 0, null, null);
+
+ mEnableRollbackCompleted = false;
}
}
mRet = ret;
}
- @Override
- void handleReturnCode() {
- // If mArgs is null, then MCS couldn't be reached. When it
- // reconnects, it will try again to install. At that point, this
- // will succeed.
- if (mArgs != null) {
- processPendingInstall(mArgs, mRet);
+ void setReturnCode(int ret) {
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ // Only update mRet if it was previously INSTALL_SUCCEEDED to
+ // ensure we do not overwrite any previous failure results.
+ mRet = ret;
}
}
- @Override
- void handleServiceError() {
- mArgs = createInstallArgs(this);
- mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ void handleVerificationFinished() {
+ mVerificationCompleted = true;
+ handleReturnCode();
}
- public boolean isForwardLocked() {
- return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
+ void handleRollbackEnabled() {
+ // TODO(ruhler) b/112431924: Consider halting the install if we
+ // couldn't enable rollback.
+ mEnableRollbackCompleted = true;
+ handleReturnCode();
}
- }
- /**
- * Used during creation of InstallArgs
- *
- * @param installFlags package installation flags
- * @return true if should be installed on external storage
- */
- private static boolean installOnExternalAsec(int installFlags) {
- if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- return false;
- }
- if ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- return true;
+ @Override
+ void handleReturnCode() {
+ if (mVerificationCompleted && mEnableRollbackCompleted) {
+ if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
+ String packageName = "";
+ try {
+ PackageLite packageInfo =
+ new PackageParser().parsePackageLite(origin.file, 0);
+ packageName = packageInfo.packageName;
+ } catch (PackageParserException e) {
+ Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
+ }
+ try {
+ observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ return;
+ }
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ mRet = mArgs.copyApk();
+ }
+ processPendingInstall(mArgs, mRet);
+ }
}
- return false;
- }
-
- /**
- * Used during creation of InstallArgs
- *
- * @param installFlags package installation flags
- * @return true if should be installed as forward locked
- */
- private static boolean installForwardLocked(int installFlags) {
- return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
}
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
- } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
- return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
- private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
+ private InstallArgs createInstallArgsForExisting(String codePath,
String resourcePath, String[] instructionSets) {
- final boolean isInAsec;
- if (installOnExternalAsec(installFlags)) {
- /* Apps on SD card are always in ASEC containers. */
- isInAsec = true;
- } else if (installForwardLocked(installFlags)
- && !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
- /*
- * Forward-locked apps are only in ASEC containers if they're the
- * new style
- */
- isInAsec = true;
- } else {
- isInAsec = false;
- }
-
- if (isInAsec) {
- return new AsecInstallArgs(codePath, instructionSets,
- installOnExternalAsec(installFlags), installForwardLocked(installFlags));
- } else {
- return new FileInstallArgs(codePath, resourcePath, instructionSets);
- }
+ return new FileInstallArgs(codePath, resourcePath, instructionSets);
}
static abstract class InstallArgs {
final UserHandle user;
final String abiOverride;
final String[] installGrantPermissions;
+ final List<String> whitelistedRestrictedPermissions;
/** If non-null, drop an async trace when the install completes */
final String traceMethod;
final int traceCookie;
- final Certificate[][] certificates;
+ final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable final MultiPackageInstallParams mMultiPackageInstallParams;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
- String traceMethod, int traceCookie, Certificate[][] certificates,
- int installReason) {
+ List<String> whitelistedRestrictedPermissions,
+ String traceMethod, int traceCookie, SigningDetails signingDetails,
+ int installReason,
+ MultiPackageInstallParams multiPackageInstallParams) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
this.instructionSets = instructionSets;
this.abiOverride = abiOverride;
this.installGrantPermissions = installGrantPermissions;
+ this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
this.traceMethod = traceMethod;
this.traceCookie = traceCookie;
- this.certificates = certificates;
+ this.signingDetails = signingDetails;
this.installReason = installReason;
+ this.mMultiPackageInstallParams = multiPackageInstallParams;
}
- abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
+ abstract int copyApk();
abstract int doPreInstall(int status);
/**
* Rename package into final resting place. All paths on the given
* scanned package should be updated to reflect the rename.
*/
- abstract boolean doRename(int status, PackageParser.Package pkg, String oldCodePath);
+ abstract boolean doRename(int status, PackageParser.Package pkg);
abstract int doPostInstall(int status, int uid);
/** @see PackageSettingBase#codePathString */
return PackageManager.INSTALL_SUCCEEDED;
}
- protected boolean isFwdLocked() {
- return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
- }
-
- protected boolean isExternalAsec() {
- return (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
- }
-
protected boolean isEphemeral() {
return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
}
}
/**
- * Logic to handle installation of non-ASEC applications, including copying
+ * Logic to handle installation of new applications, including copying
* and renaming logic.
*/
class FileInstallArgs extends InstallArgs {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
- params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates,
- params.installReason);
- if (isFwdLocked()) {
- throw new IllegalArgumentException("Forward locking only supported in ASEC");
- }
+ params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
+ params.traceMethod, params.traceCookie, params.signingDetails,
+ params.installReason, params.mParentInstallParams);
}
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
- null, null, null, 0, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ null, null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
+ PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
- int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
- return doCopyApk(imcs, temp);
+ return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ private int doCopyApk() {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
- final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
- @Override
- public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
- if (!FileUtils.isValidExtFilename(name)) {
- throw new IllegalArgumentException("Invalid filename: " + name);
- }
- try {
- final File file = new File(codeFile, name);
- final FileDescriptor fd = Os.open(file.getAbsolutePath(),
- O_RDWR | O_CREAT, 0644);
- Os.chmod(file.getAbsolutePath(), 0644);
- return new ParcelFileDescriptor(fd);
- } catch (ErrnoException e) {
- throw new RemoteException("Failed to open: " + e.getMessage());
- }
- }
- };
-
- int ret = PackageManager.INSTALL_SUCCEEDED;
- ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
+ int ret = PackageManagerServiceUtils.copyPackage(
+ origin.file.getAbsolutePath(), codeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
return status;
}
- boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
+ boolean doRename(int status, PackageParser.Package pkg) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
resourceFile = afterCodeFile;
// Reflect the rename in scanned details
- pkg.setCodePath(afterCodeFile.getAbsolutePath());
+ try {
+ pkg.setCodePath(afterCodeFile.getCanonicalPath());
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
+ return false;
+ }
pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, pkg.baseCodePath));
pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
// XXX err, shouldn't we respect the delete flag?
cleanUpResourcesLI();
return true;
- }
- }
-
- private boolean isAsecExternal(String cid) {
- final String asecPath = PackageHelper.getSdFilesystem(cid);
- return !asecPath.startsWith(mAsecInternalPath);
- }
-
- private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
- PackageManagerException {
- if (copyRet < 0) {
- if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
- copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
- throw new PackageManagerException(copyRet, message);
- }
- }
- }
-
- /**
- * Extract the StorageManagerService "container ID" from the full code path of an
- * .apk.
- */
- static String cidFromCodePath(String fullCodePath) {
- int eidx = fullCodePath.lastIndexOf("/");
- String subStr1 = fullCodePath.substring(0, eidx);
- int sidx = subStr1.lastIndexOf("/");
- return subStr1.substring(sidx+1, eidx);
- }
-
- /**
- * Logic to handle installation of ASEC applications, including copying and
- * renaming logic.
- */
- class AsecInstallArgs extends InstallArgs {
- static final String RES_FILE_NAME = "pkg.apk";
- static final String PUBLIC_RES_FILE_NAME = "res.zip";
-
- String cid;
- String packagePath;
- String resourcePath;
-
- /** New install */
- AsecInstallArgs(InstallParams params) {
- super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid,
- params.getUser(), null /* instruction sets */, params.packageAbiOverride,
- params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates,
- params.installReason);
- }
-
- /** Existing install */
- AsecInstallArgs(String fullCodePath, String[] instructionSets,
- boolean isExternal, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
- // Hackily pretend we're still looking at a full code path
- if (!fullCodePath.endsWith(RES_FILE_NAME)) {
- fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
- }
-
- // Extract cid from fullCodePath
- int eidx = fullCodePath.lastIndexOf("/");
- String subStr1 = fullCodePath.substring(0, eidx);
- int sidx = subStr1.lastIndexOf("/");
- cid = subStr1.substring(sidx+1, eidx);
- setMountPath(subStr1);
- }
-
- AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
- instructionSets, null, null, null, 0, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
- this.cid = cid;
- setMountPath(PackageHelper.getSdDir(cid));
- }
-
- void createCopyFile() {
- cid = mInstallerService.allocateExternalStageCidLegacy();
- }
-
- int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
- if (origin.staged && origin.cid != null) {
- if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
- cid = origin.cid;
- setMountPath(PackageHelper.getSdDir(cid));
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- if (temp) {
- createCopyFile();
- } else {
- /*
- * Pre-emptively destroy the container since it's destroyed if
- * copying fails due to it existing anyway.
- */
- PackageHelper.destroySdDir(cid);
- }
-
- final String newMountPath = imcs.copyPackageToContainer(
- origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
- isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
-
- if (newMountPath != null) {
- setMountPath(newMountPath);
- return PackageManager.INSTALL_SUCCEEDED;
- } else {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
-
- @Override
- String getCodePath() {
- return packagePath;
- }
-
- @Override
- String getResourcePath() {
- return resourcePath;
- }
-
- int doPreInstall(int status) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- // Destroy container
- PackageHelper.destroySdDir(cid);
- } else {
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (!mounted) {
- String newMountPath = PackageHelper.mountSdDir(cid, getEncryptKey(),
- Process.SYSTEM_UID);
- if (newMountPath != null) {
- setMountPath(newMountPath);
- } else {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
- }
- return status;
- }
-
- boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
- String newCacheId = getNextCodePath(oldCodePath, pkg.packageName, "/" + RES_FILE_NAME);
- String newMountPath = null;
- if (PackageHelper.isContainerMounted(cid)) {
- // Unmount the container
- if (!PackageHelper.unMountSdDir(cid)) {
- Slog.i(TAG, "Failed to unmount " + cid + " before renaming");
- return false;
- }
- }
- if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId +
- " which might be stale. Will try to clean up.");
- // Clean up the stale container and proceed to recreate.
- if (!PackageHelper.destroySdDir(newCacheId)) {
- Slog.e(TAG, "Very strange. Cannot clean up stale container " + newCacheId);
- return false;
- }
- // Successfully cleaned up stale container. Try to rename again.
- if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId
- + " inspite of cleaning it up.");
- return false;
- }
- }
- if (!PackageHelper.isContainerMounted(newCacheId)) {
- Slog.w(TAG, "Mounting container " + newCacheId);
- newMountPath = PackageHelper.mountSdDir(newCacheId,
- getEncryptKey(), Process.SYSTEM_UID);
- } else {
- newMountPath = PackageHelper.getSdDir(newCacheId);
- }
- if (newMountPath == null) {
- Slog.w(TAG, "Failed to get cache path for " + newCacheId);
- return false;
- }
- Log.i(TAG, "Succesfully renamed " + cid +
- " to " + newCacheId +
- " at new path: " + newMountPath);
- cid = newCacheId;
-
- final File beforeCodeFile = new File(packagePath);
- setMountPath(newMountPath);
- final File afterCodeFile = new File(packagePath);
-
- // Reflect the rename in scanned details
- pkg.setCodePath(afterCodeFile.getAbsolutePath());
- pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.baseCodePath));
- pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
- afterCodeFile, pkg.splitCodePaths));
-
- // Reflect the rename in app info
- pkg.setApplicationVolumeUuid(pkg.volumeUuid);
- pkg.setApplicationInfoCodePath(pkg.codePath);
- pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
- pkg.setApplicationInfoResourcePath(pkg.codePath);
- pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
- pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
-
- return true;
- }
-
- private void setMountPath(String mountPath) {
- final File mountFile = new File(mountPath);
-
- final File monolithicFile = new File(mountFile, RES_FILE_NAME);
- if (monolithicFile.exists()) {
- packagePath = monolithicFile.getAbsolutePath();
- if (isFwdLocked()) {
- resourcePath = new File(mountFile, PUBLIC_RES_FILE_NAME).getAbsolutePath();
- } else {
- resourcePath = packagePath;
- }
- } else {
- packagePath = mountFile.getAbsolutePath();
- resourcePath = packagePath;
- }
- }
-
- int doPostInstall(int status, int uid) {
- if (status != PackageManager.INSTALL_SUCCEEDED) {
- cleanUp();
- } else {
- final int groupOwner;
- final String protectedFile;
- if (isFwdLocked()) {
- groupOwner = UserHandle.getSharedAppGid(uid);
- protectedFile = RES_FILE_NAME;
- } else {
- groupOwner = -1;
- protectedFile = null;
- }
-
- if (uid < Process.FIRST_APPLICATION_UID
- || !PackageHelper.fixSdPermissions(cid, groupOwner, protectedFile)) {
- Slog.e(TAG, "Failed to finalize " + cid);
- PackageHelper.destroySdDir(cid);
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
-
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (!mounted) {
- PackageHelper.mountSdDir(cid, getEncryptKey(), Process.myUid());
- }
- }
- return status;
- }
-
- private void cleanUp() {
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "cleanUp");
-
- // Destroy secure container
- PackageHelper.destroySdDir(cid);
- }
-
- private List<String> getAllCodePaths() {
- final File codeFile = new File(getCodePath());
- if (codeFile != null && codeFile.exists()) {
- try {
- final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
- return pkg.getAllCodePaths();
- } catch (PackageParserException e) {
- // Ignored; we tried our best
- }
- }
- return Collections.EMPTY_LIST;
- }
-
- void cleanUpResourcesLI() {
- // Enumerate all code paths before deleting
- cleanUpResourcesLI(getAllCodePaths());
- }
-
- private void cleanUpResourcesLI(List<String> allCodePaths) {
- cleanUp();
- removeDexFiles(allCodePaths, instructionSets);
- }
-
- String getPackageName() {
- return getAsecPackageName(cid);
- }
-
- boolean doPostDeleteLI(boolean delete) {
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);
- final List<String> allCodePaths = getAllCodePaths();
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (mounted) {
- // Unmount first
- if (PackageHelper.unMountSdDir(cid)) {
- mounted = false;
- }
- }
- if (!mounted && delete) {
- cleanUpResourcesLI(allCodePaths);
- }
- return !mounted;
- }
-
- @Override
- int doPreCopy() {
- if (isFwdLocked()) {
- if (!PackageHelper.fixSdPermissions(cid, getPackageUid(DEFAULT_CONTAINER_PACKAGE,
- MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM), RES_FILE_NAME)) {
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
-
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- @Override
- int doPostCopy(int uid) {
- if (isFwdLocked()) {
- if (uid < Process.FIRST_APPLICATION_UID
- || !PackageHelper.fixSdPermissions(cid, UserHandle.getSharedAppGid(uid),
- RES_FILE_NAME)) {
- Slog.e(TAG, "Failed to finalize " + cid);
- PackageHelper.destroySdDir(cid);
- return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- }
- }
+ }
+ }
- return PackageManager.INSTALL_SUCCEEDED;
+ private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+ PackageManagerException {
+ if (copyRet < 0) {
+ if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
+ copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ throw new PackageManagerException(copyRet, message);
+ }
}
}
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
- params.grantedRuntimePermissions,
- params.traceMethod, params.traceCookie, params.certificates,
- params.installReason);
+ params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
+ params.traceMethod, params.traceCookie, params.signingDetails,
+ params.installReason, params.mParentInstallParams);
}
- int copyApk(IMediaContainerService imcs, boolean temp) {
+ int copyApk() {
if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
+ move.fromUuid + " to " + move.toUuid);
synchronized (mInstaller) {
return status;
}
- boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
+ boolean doRename(int status, PackageParser.Package pkg) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp(move.toUuid);
return false;
synchronized (mInstallLock) {
// Clean up both app data and code
// All package moves are frozen until finished
+
+ // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
+ // this task was only focused on moving data on internal storage.
for (int userId : userIds) {
try {
mInstaller.destroyAppData(volumeUuid, move.packageName, userId,
}
}
- static String getAsecPackageName(String packageCid) {
- int idx = packageCid.lastIndexOf("-");
- if (idx == -1) {
- return packageCid;
- }
- return packageCid.substring(0, idx);
- }
-
- // Utility method used to create code paths based on package name and available index.
- private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
- String idxStr = "";
- int idx = 1;
- // Fall back to default value of idx=1 if prefix is not
- // part of oldCodePath
- if (oldCodePath != null) {
- String subStr = oldCodePath;
- // Drop the suffix right away
- if (suffix != null && subStr.endsWith(suffix)) {
- subStr = subStr.substring(0, subStr.length() - suffix.length());
- }
- // If oldCodePath already contains prefix find out the
- // ending index to either increment or decrement.
- int sidx = subStr.lastIndexOf(prefix);
- if (sidx != -1) {
- subStr = subStr.substring(sidx + prefix.length());
- if (subStr != null) {
- if (subStr.startsWith(INSTALL_PACKAGE_SUFFIX)) {
- subStr = subStr.substring(INSTALL_PACKAGE_SUFFIX.length());
- }
- try {
- idx = Integer.parseInt(subStr);
- if (idx <= 1) {
- idx++;
- } else {
- idx--;
- }
- } catch(NumberFormatException e) {
- }
- }
- }
- }
- idxStr = INSTALL_PACKAGE_SUFFIX + Integer.toString(idx);
- return prefix + idxStr;
- }
-
private File getNextCodePath(File targetDir, String packageName) {
File result;
SecureRandom random = new SecureRandom();
String installerPackageName;
PackageRemovedInfo removedInfo;
ArrayMap<String, PackageInstalledInfo> addedChildPackages;
+ // The set of packages consuming this shared library or null if no consumers exist.
+ ArrayList<PackageParser.Package> libraryConsumers;
public void setError(int code, String msg) {
setReturnCode(code);
String origPermission;
}
- /*
- * Install a non-existing package.
- */
- private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
- int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
- PackageInstalledInfo res, int installReason) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
-
- // Remember this for later, in case we need to rollback this install
- String pkgName = pkg.packageName;
-
- if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
-
- synchronized(mPackages) {
- final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
- if (renamedPackage != null) {
- // A package with the same name is already installed, though
- // it has been renamed to an older name. The package we
- // are trying to install should be installed as an update to
- // the existing one, but that has not been requested, so bail.
- res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
- + " without first uninstalling package running as "
- + renamedPackage);
- return;
- }
- if (mPackages.containsKey(pkgName)) {
- // Don't allow installation over an existing package with the same name.
- res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
- + " without first uninstalling.");
- return;
- }
- }
-
- try {
- PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
- System.currentTimeMillis(), user);
-
- updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- prepareAppDataAfterInstallLIF(newPackage);
-
- } else {
- // Remove package from internal structures, but keep around any
- // data that might have already existed
- deletePackageLIF(pkgName, UserHandle.ALL, false, null,
- PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
- }
- } catch (PackageManagerException e) {
- res.setError("Package couldn't be installed in " + pkg.codePath, e);
- }
-
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- private boolean shouldCheckUpgradeKeySetLP(PackageSetting oldPs, int scanFlags) {
- // Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.sharedUser != null
- || !oldPs.keySetData.isUsingUpgradeKeySets()) {
- return false;
- }
- // app is using upgradeKeySets; make sure all are valid
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
- for (int i = 0; i < upgradeKeySets.length; i++) {
- if (!ksms.isIdValidKeySetId(upgradeKeySets[i])) {
- Slog.wtf(TAG, "Package "
- + (oldPs.name != null ? oldPs.name : "<null>")
- + " contains upgrade-key-set reference to unknown key-set: "
- + upgradeKeySets[i]
- + " reverting to signatures check.");
- return false;
- }
- }
- return true;
- }
-
- private boolean checkUpgradeKeySetLP(PackageSetting oldPS, PackageParser.Package newPkg) {
- // Upgrade keysets are being used. Determine if new package has a superset of the
- // required keys.
- long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- for (int i = 0; i < upgradeKeySets.length; i++) {
- Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
- if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
- return true;
- }
- }
- return false;
- }
-
private static void updateDigest(MessageDigest digest, File file) throws IOException {
try (DigestInputStream digestStream =
new DigestInputStream(new FileInputStream(file), digest)) {
}
}
- private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
- UserHandle user, String installerPackageName, PackageInstalledInfo res,
- int installReason) {
- final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
-
- final PackageParser.Package oldPackage;
- final PackageSetting ps;
- final String pkgName = pkg.packageName;
- final int[] allUsers;
- final int[] installedUsers;
-
- synchronized(mPackages) {
- oldPackage = mPackages.get(pkgName);
- if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
-
- // don't allow upgrade to target a release SDK from a pre-release SDK
- final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
- == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
- final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
- == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
- if (oldTargetsPreRelease
- && !newTargetsPreRelease
- && ((policyFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
- Slog.w(TAG, "Can't install package targeting released sdk");
- res.setReturnCode(PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
- return;
- }
-
- ps = mSettings.mPackages.get(pkgName);
-
- // verify signatures are valid
- if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
- if (!checkUpgradeKeySetLP(ps, pkg)) {
- res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "New package not signed by keys specified by upgrade-keysets: "
- + pkgName);
- return;
- }
- } else {
- // default to original signature matching
- if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
- != PackageManager.SIGNATURE_MATCH) {
- res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "New package has a different signature: " + pkgName);
- return;
- }
- }
-
- // don't allow a system upgrade unless the upgrade hash matches
- if (oldPackage.restrictUpdateHash != null && oldPackage.isSystemApp()) {
- byte[] digestBytes = null;
- try {
- final MessageDigest digest = MessageDigest.getInstance("SHA-512");
- updateDigest(digest, new File(pkg.baseCodePath));
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (String path : pkg.splitCodePaths) {
- updateDigest(digest, new File(path));
- }
- }
- digestBytes = digest.digest();
- } catch (NoSuchAlgorithmException | IOException e) {
- res.setError(INSTALL_FAILED_INVALID_APK,
- "Could not compute hash: " + pkgName);
- return;
- }
- if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
- res.setError(INSTALL_FAILED_INVALID_APK,
- "New package fails restrict-update check: " + pkgName);
- return;
- }
- // retain upgrade restriction
- pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
- }
-
- // Check for shared user id changes
- String invalidPackageName =
- getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
- if (invalidPackageName != null) {
- res.setError(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + invalidPackageName + " tried to change user "
- + oldPackage.mSharedUserId);
- return;
- }
-
- // In case of rollback, remember per-user/profile install state
- allUsers = sUserManager.getUserIds();
- installedUsers = ps.queryInstalledUsers(allUsers, true);
-
- // don't allow an upgrade from full to ephemeral
- if (isInstantApp) {
- if (user == null || user.getIdentifier() == UserHandle.USER_ALL) {
- for (int currentUser : allUsers) {
- if (!ps.getInstantApp(currentUser)) {
- // can't downgrade from full to instant
- Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
- + " for user: " + currentUser);
- res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
- return;
- }
- }
- } else if (!ps.getInstantApp(user.getIdentifier())) {
- // can't downgrade from full to instant
- Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
- + " for user: " + user.getIdentifier());
- res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
- return;
- }
- }
- }
-
- // Update what is removed
- res.removedInfo = new PackageRemovedInfo(this);
- res.removedInfo.uid = oldPackage.applicationInfo.uid;
- res.removedInfo.removedPackage = oldPackage.packageName;
- res.removedInfo.installerPackageName = ps.installerPackageName;
- res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
- res.removedInfo.isUpdate = true;
- res.removedInfo.origUsers = installedUsers;
- res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
- for (int i = 0; i < installedUsers.length; i++) {
- final int userId = installedUsers[i];
- res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
- }
-
- final int childCount = (oldPackage.childPackages != null)
- ? oldPackage.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- boolean childPackageUpdated = false;
- PackageParser.Package childPkg = oldPackage.childPackages.get(i);
- final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
- if (res.addedChildPackages != null) {
- PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
- if (childRes != null) {
- childRes.removedInfo.uid = childPkg.applicationInfo.uid;
- childRes.removedInfo.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRes.removedInfo.installerPackageName = childPs.installerPackageName;
- }
- childRes.removedInfo.isUpdate = true;
- childRes.removedInfo.installReasons = res.removedInfo.installReasons;
- childPackageUpdated = true;
- }
- }
- if (!childPackageUpdated) {
- PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
- childRemovedRes.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRemovedRes.installerPackageName = childPs.installerPackageName;
- }
- childRemovedRes.isUpdate = false;
- childRemovedRes.dataRemoved = true;
- synchronized (mPackages) {
- if (childPs != null) {
- childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
- }
- }
- if (res.removedInfo.removedChildPackages == null) {
- res.removedInfo.removedChildPackages = new ArrayMap<>();
- }
- res.removedInfo.removedChildPackages.put(childPkg.packageName, childRemovedRes);
- }
- }
-
- boolean sysPkg = (isSystemApp(oldPackage));
- if (sysPkg) {
- // Set the system/privileged flags as needed
- final boolean privileged =
- (oldPackage.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- final int systemPolicyFlags = policyFlags
- | PackageParser.PARSE_IS_SYSTEM
- | (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);
-
- replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,
- user, allUsers, installerPackageName, res, installReason);
- } else {
- replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,
- user, allUsers, installerPackageName, res, installReason);
- }
- }
-
- @Override
- public List<String> getPreviousCodePaths(String packageName) {
- final int callingUid = Binder.getCallingUid();
- final List<String> result = new ArrayList<>();
- if (getInstantAppPackageName(callingUid) != null) {
- return result;
- }
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null
- && ps.oldCodePaths != null
- && !filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
- result.addAll(ps.oldCodePaths);
- }
- return result;
- }
-
- private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
- PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
- int[] allUsers, String installerPackageName, PackageInstalledInfo res,
- int installReason) {
- if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
- + deletedPackage);
-
- String pkgName = deletedPackage.packageName;
- boolean deletedPkg = true;
- boolean addedPkg = false;
- boolean updatedSettings = false;
- final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
- final int deleteFlags = PackageManager.DELETE_KEEP_DATA
- | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
-
- final long origUpdateTime = (pkg.mExtras != null)
- ? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
-
- // First delete the existing package while retaining the data directory
- if (!deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
- res.removedInfo, true, pkg)) {
- // If the existing package wasn't successfully deleted
- res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
- deletedPkg = false;
- } else {
- // Successfully deleted the old package; proceed with replace.
-
- // If deleted package lived in a container, give users a chance to
- // relinquish resources before killing.
- if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
- }
- final int[] uidArray = new int[] { deletedPackage.applicationInfo.uid };
- final ArrayList<String> pkgList = new ArrayList<String>(1);
- pkgList.add(deletedPackage.applicationInfo.packageName);
- sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
- }
-
- clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
-
- try {
- final PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags,
- scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
- installReason);
-
- // Update the in-memory copy of the previous code paths.
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (!killApp) {
- if (ps.oldCodePaths == null) {
- ps.oldCodePaths = new ArraySet<>();
- }
- Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
- if (deletedPackage.splitCodePaths != null) {
- Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
- }
- } else {
- ps.oldCodePaths = null;
- }
- if (ps.childPackageNames != null) {
- for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
- final String childPkgName = ps.childPackageNames.get(i);
- final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
- childPs.oldCodePaths = ps.oldCodePaths;
- }
- }
- // set instant app status, but, only if it's explicitly specified
- final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
- final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
- setInstantAppForUser(ps, user.getIdentifier(), instantApp, fullApp);
- prepareAppDataAfterInstallLIF(newPackage);
- addedPkg = true;
- mDexManager.notifyPackageUpdated(newPackage.packageName,
- newPackage.baseCodePath, newPackage.splitCodePaths);
- } catch (PackageManagerException e) {
- res.setError("Package couldn't be installed in " + pkg.codePath, e);
- }
- }
-
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName);
-
- // Revert all internal state mutations and added folders for the failed install
- if (addedPkg) {
- deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
- res.removedInfo, true, null);
- }
-
- // Restore the old package
- if (deletedPkg) {
- if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
- File restoreFile = new File(deletedPackage.codePath);
- // Parse old package
- boolean oldExternal = isExternal(deletedPackage);
- int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
- (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
- (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
- int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
- try {
- scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime,
- null);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
- + e.getMessage());
- return;
- }
-
- synchronized (mPackages) {
- // Ensure the installer package name up to date
- setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
- // Update permissions for restored package
- updatePermissionsLPw(deletedPackage, UPDATE_PERMISSIONS_ALL);
-
- mSettings.writeLPr();
- }
-
- Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
- }
- } else {
- synchronized (mPackages) {
- PackageSetting ps = mSettings.getPackageLPr(pkg.packageName);
- if (ps != null) {
- res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
- if (res.removedInfo.removedChildPackages != null) {
- final int childCount = res.removedInfo.removedChildPackages.size();
- // Iterate in reverse as we may modify the collection
- for (int i = childCount - 1; i >= 0; i--) {
- String childPackageName = res.removedInfo.removedChildPackages.keyAt(i);
- if (res.addedChildPackages.containsKey(childPackageName)) {
- res.removedInfo.removedChildPackages.removeAt(i);
- } else {
- PackageRemovedInfo childInfo = res.removedInfo
- .removedChildPackages.valueAt(i);
- childInfo.removedForAllUsers = mPackages.get(
- childInfo.removedPackage) == null;
- }
- }
- }
- }
- }
- }
- }
-
- private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
- PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
- int[] allUsers, String installerPackageName, PackageInstalledInfo res,
- int installReason) {
- if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
- + ", old=" + deletedPackage);
-
- final boolean disabledSystem;
-
- // Remove existing system package
- removePackageLI(deletedPackage, true);
-
- synchronized (mPackages) {
- disabledSystem = disableSystemPackageLPw(deletedPackage, pkg);
- }
- if (!disabledSystem) {
- // We didn't need to disable the .apk as a current system package,
- // which means we are replacing another update that is already
- // installed. We need to make sure to delete the older one's .apk.
- res.removedInfo.args = createInstallArgsForExisting(0,
- deletedPackage.applicationInfo.getCodePath(),
- deletedPackage.applicationInfo.getResourcePath(),
- getAppDexInstructionSets(deletedPackage.applicationInfo));
- } else {
- res.removedInfo.args = null;
- }
-
- // Successfully disabled the old package. Now proceed with re-installation
- clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
-
- res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
-
- PackageParser.Package newPackage = null;
- try {
- // Add the package to the internal data structures
- newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, 0, user);
-
- // Set the update and install times
- PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras;
- setInstallAndUpdateTime(newPackage, deletedPkgSetting.firstInstallTime,
- System.currentTimeMillis());
-
- // Update the package dynamic state if succeeded
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- // Now that the install succeeded make sure we remove data
- // directories for any child package the update removed.
- final int deletedChildCount = (deletedPackage.childPackages != null)
- ? deletedPackage.childPackages.size() : 0;
- final int newChildCount = (newPackage.childPackages != null)
- ? newPackage.childPackages.size() : 0;
- for (int i = 0; i < deletedChildCount; i++) {
- PackageParser.Package deletedChildPkg = deletedPackage.childPackages.get(i);
- boolean childPackageDeleted = true;
- for (int j = 0; j < newChildCount; j++) {
- PackageParser.Package newChildPkg = newPackage.childPackages.get(j);
- if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
- childPackageDeleted = false;
- break;
- }
- }
- if (childPackageDeleted) {
- PackageSetting ps = mSettings.getDisabledSystemPkgLPr(
- deletedChildPkg.packageName);
- if (ps != null && res.removedInfo.removedChildPackages != null) {
- PackageRemovedInfo removedChildRes = res.removedInfo
- .removedChildPackages.get(deletedChildPkg.packageName);
- removePackageDataLIF(ps, allUsers, removedChildRes, 0, false);
- removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
- }
- }
- }
-
- updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
- installReason);
- prepareAppDataAfterInstallLIF(newPackage);
-
- mDexManager.notifyPackageUpdated(newPackage.packageName,
- newPackage.baseCodePath, newPackage.splitCodePaths);
- }
- } catch (PackageManagerException e) {
- res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
- res.setError("Package couldn't be installed in " + pkg.codePath, e);
- }
-
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- // Re installation failed. Restore old information
- // Remove new pkg information
- if (newPackage != null) {
- removeInstalledPackageLI(newPackage, true);
- }
- // Add back the old system package
- try {
- scanPackageTracedLI(deletedPackage, policyFlags, SCAN_UPDATE_SIGNATURE, 0, user);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
- }
-
- synchronized (mPackages) {
- if (disabledSystem) {
- enableSystemPackageLPw(deletedPackage);
- }
-
- // Ensure the installer package name up to date
- setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
- // Update permissions for restored package
- updatePermissionsLPw(deletedPackage, UPDATE_PERMISSIONS_ALL);
-
- mSettings.writeLPr();
- }
-
- Slog.i(TAG, "Successfully restored package : " + deletedPackage.packageName
- + " after failed upgrade");
- }
- }
-
/**
* Checks whether the parent or any of the child packages have a change shared
* user. For a package to be a valid update the shred users of the parent and
}
}
+ @GuardedBy("mPackages")
private void enableSystemPackageLPw(PackageParser.Package pkg) {
// Enable the parent package
mSettings.enableSystemPackageLPw(pkg.packageName);
}
}
+ @GuardedBy("mPackages")
private boolean disableSystemPackageLPw(PackageParser.Package oldPkg,
PackageParser.Package newPkg) {
// Disable the parent package (parent always replaced)
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = oldPkg.childPackages.get(i);
final boolean replace = newPkg.hasChildPackage(childPkg.packageName);
- disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace);
- }
- return disabled;
- }
-
- private void setInstallerPackageNameLPw(PackageParser.Package pkg,
- String installerPackageName) {
- // Enable the parent package
- mSettings.setInstallerPackageName(pkg.packageName, installerPackageName);
- // Enable the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- mSettings.setInstallerPackageName(childPkg.packageName, installerPackageName);
- }
- }
-
- private int[] revokeUnusedSharedUserPermissionsLPw(SharedUserSetting su, int[] allUserIds) {
- // Collect all used permissions in the UID
- ArraySet<String> usedPermissions = new ArraySet<>();
- final int packageCount = su.packages.size();
- for (int i = 0; i < packageCount; i++) {
- PackageSetting ps = su.packages.valueAt(i);
- if (ps.pkg == null) {
- continue;
- }
- final int requestedPermCount = ps.pkg.requestedPermissions.size();
- for (int j = 0; j < requestedPermCount; j++) {
- String permission = ps.pkg.requestedPermissions.get(j);
- BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp != null) {
- usedPermissions.add(permission);
- }
- }
- }
-
- PermissionsState permissionsState = su.getPermissionsState();
- // Prune install permissions
- List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
- final int installPermCount = installPermStates.size();
- for (int i = installPermCount - 1; i >= 0; i--) {
- PermissionState permissionState = installPermStates.get(i);
- if (!usedPermissions.contains(permissionState.getName())) {
- BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeInstallPermission(bp);
- permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- }
- }
+ disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace);
}
+ return disabled;
+ }
- int[] runtimePermissionChangedUserIds = EmptyArray.INT;
-
- // Prune runtime permissions
- for (int userId : allUserIds) {
- List<PermissionState> runtimePermStates = permissionsState
- .getRuntimePermissionStates(userId);
- final int runtimePermCount = runtimePermStates.size();
- for (int i = runtimePermCount - 1; i >= 0; i--) {
- PermissionState permissionState = runtimePermStates.get(i);
- if (!usedPermissions.contains(permissionState.getName())) {
- BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- runtimePermissionChangedUserIds = ArrayUtils.appendInt(
- runtimePermissionChangedUserIds, userId);
- }
- }
- }
+ @GuardedBy("mPackages")
+ private void setInstallerPackageNameLPw(PackageParser.Package pkg,
+ String installerPackageName) {
+ // Enable the parent package
+ mSettings.setInstallerPackageName(pkg.packageName, installerPackageName);
+ // Enable the child packages
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ mSettings.setInstallerPackageName(childPkg.packageName, installerPackageName);
}
-
- return runtimePermissionChangedUserIds;
}
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
}
}
- private void updateSettingsInternalLI(PackageParser.Package newPackage,
+ private void updateSettingsInternalLI(PackageParser.Package pkg,
String installerPackageName, int[] allUsers, int[] installedForUsers,
PackageInstalledInfo res, UserHandle user, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- String pkgName = newPackage.packageName;
- synchronized (mPackages) {
- //write settings. the installStatus will be incomplete at this stage.
- //note that the new package setting would have already been
- //added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
- // TODO: Remove this write? It's also written at the end of this method
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
+ final String pkgName = pkg.packageName;
- if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
+ if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
synchronized (mPackages) {
- updatePermissionsLPw(newPackage.packageName, newPackage,
- UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
- ? UPDATE_PERMISSIONS_ALL : 0));
+// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
+ mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(),
+ mPermissionCallback);
// For system-bundled packages, we assume that installing an upgraded version
// of the package implies that the user actually wants to run that new code,
// so we enable the package.
PackageSetting ps = mSettings.mPackages.get(pkgName);
final int userId = user.getIdentifier();
if (ps != null) {
- if (isSystemApp(newPackage)) {
+ if (isSystemApp(pkg)) {
if (DEBUG_INSTALL) {
Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
}
// upcoming call to mSettings.writeLPr().
}
}
- // It's implied that when a user requests installation, they want the app to be
- // installed and enabled.
- if (userId != UserHandle.USER_ALL) {
- ps.setInstalled(true, userId);
- ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+ // It's implied that when a user requests installation, they want the app to be
+ // installed and enabled.
+ if (userId != UserHandle.USER_ALL) {
+ ps.setInstalled(true, userId);
+ ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+ }
+
+ // When replacing an existing package, preserve the original install reason for all
+ // users that had the package installed before.
+ final Set<Integer> previousUserIds = new ArraySet<>();
+ if (res.removedInfo != null && res.removedInfo.installReasons != null) {
+ final int installReasonCount = res.removedInfo.installReasons.size();
+ for (int i = 0; i < installReasonCount; i++) {
+ final int previousUserId = res.removedInfo.installReasons.keyAt(i);
+ final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);
+ ps.setInstallReason(previousInstallReason, previousUserId);
+ previousUserIds.add(previousUserId);
+ }
+ }
+
+ // Set install reason for users that are having the package newly installed.
+ if (userId == UserHandle.USER_ALL) {
+ for (int currentUserId : sUserManager.getUserIds()) {
+ if (!previousUserIds.contains(currentUserId)) {
+ ps.setInstallReason(installReason, currentUserId);
+ }
+ }
+ } else if (!previousUserIds.contains(userId)) {
+ ps.setInstallReason(installReason, userId);
+ }
+ mSettings.writeKernelMappingLPr(ps);
+ }
+ res.name = pkgName;
+ res.uid = pkg.applicationInfo.uid;
+ res.pkg = pkg;
+ mSettings.setInstallerPackageName(pkgName, installerPackageName);
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ //to update install status
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
+ mSettings.writeLPr();
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ private static class InstallRequest {
+ public final InstallArgs args;
+ public final PackageInstalledInfo installResult;
+
+ private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
+ this.args = args;
+ this.installResult = res;
+ }
+ }
+
+ @GuardedBy({"mInstallLock", "mPackages"})
+ private void installPackagesTracedLI(List<InstallRequest> requests) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+ installPackagesLI(requests);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Package state to commit to memory and disk after reconciliation has completed.
+ */
+ private static class CommitRequest {
+ final Map<String, ReconciledPackage> reconciledPackages;
+ final int[] mAllUsers;
+
+ private CommitRequest(Map<String, ReconciledPackage> reconciledPackages, int[] allUsers) {
+ this.reconciledPackages = reconciledPackages;
+ this.mAllUsers = allUsers;
+ }
+ }
+
+ /**
+ * Package scan results and related request details used to reconcile the potential addition of
+ * one or more packages to the system.
+ *
+ * Reconcile will take a set of package details that need to be committed to the system and make
+ * sure that they are valid in the context of the system and the other installing apps. Any
+ * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+ * as install) led to the request.
+ */
+ private static class ReconcileRequest {
+ public final Map<String, ScanResult> scannedPackages;
+
+ public final Map<String, PackageParser.Package> allPackages;
+ public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
+ public final Map<String, InstallArgs> installArgs;
+ public final Map<String, PackageInstalledInfo> installResults;
+ public final Map<String, PrepareResult> preparedPackages;
+ public final Map<String, VersionInfo> versionInfos;
+ public final Map<String, PackageSetting> lastStaticSharedLibSettings;
+
+ private ReconcileRequest(Map<String, ScanResult> scannedPackages,
+ Map<String, InstallArgs> installArgs,
+ Map<String, PackageInstalledInfo> installResults,
+ Map<String, PrepareResult> preparedPackages,
+ Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+ Map<String, PackageParser.Package> allPackages,
+ Map<String, VersionInfo> versionInfos,
+ Map<String, PackageSetting> lastStaticSharedLibSettings) {
+ this.scannedPackages = scannedPackages;
+ this.installArgs = installArgs;
+ this.installResults = installResults;
+ this.preparedPackages = preparedPackages;
+ this.sharedLibrarySource = sharedLibrarySource;
+ this.allPackages = allPackages;
+ this.versionInfos = versionInfos;
+ this.lastStaticSharedLibSettings = lastStaticSharedLibSettings;
+ }
+
+ private ReconcileRequest(Map<String, ScanResult> scannedPackages,
+ Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+ Map<String, PackageParser.Package> allPackages,
+ Map<String, VersionInfo> versionInfos,
+ Map<String, PackageSetting> lastStaticSharedLibSettings) {
+ this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
+ Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
+ lastStaticSharedLibSettings);
+ }
+ }
+ private static class ReconcileFailure extends PackageManagerException {
+ ReconcileFailure(String message) {
+ super("Reconcile failed: " + message);
+ }
+ ReconcileFailure(int reason, String message) {
+ super(reason, "Reconcile failed: " + message);
+ }
+ ReconcileFailure(PackageManagerException e) {
+ this(e.error, e.getMessage());
+ }
+ }
+
+ /**
+ * A container of all data needed to commit a package to in-memory data structures and to disk.
+ * TODO: move most of the data contained her into a PackageSetting for commit.
+ */
+ private static class ReconciledPackage {
+ public final ReconcileRequest request;
+ public final PackageSetting pkgSetting;
+ public final ScanResult scanResult;
+ // TODO: Remove install-specific details from the reconcile result
+ public final PackageInstalledInfo installResult;
+ @Nullable public final PrepareResult prepareResult;
+ @Nullable public final InstallArgs installArgs;
+ public final DeletePackageAction deletePackageAction;
+ public final List<SharedLibraryInfo> allowedSharedLibraryInfos;
+ public final SigningDetails signingDetails;
+ public final boolean sharedUserSignaturesChanged;
+ public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
+ public final boolean removeAppKeySetData;
+
+ private ReconciledPackage(ReconcileRequest request,
+ InstallArgs installArgs,
+ PackageSetting pkgSetting,
+ PackageInstalledInfo installResult,
+ PrepareResult prepareResult,
+ ScanResult scanResult,
+ DeletePackageAction deletePackageAction,
+ List<SharedLibraryInfo> allowedSharedLibraryInfos,
+ SigningDetails signingDetails,
+ boolean sharedUserSignaturesChanged,
+ boolean removeAppKeySetData) {
+ this.request = request;
+ this.installArgs = installArgs;
+ this.pkgSetting = pkgSetting;
+ this.installResult = installResult;
+ this.prepareResult = prepareResult;
+ this.scanResult = scanResult;
+ this.deletePackageAction = deletePackageAction;
+ this.allowedSharedLibraryInfos = allowedSharedLibraryInfos;
+ this.signingDetails = signingDetails;
+ this.sharedUserSignaturesChanged = sharedUserSignaturesChanged;
+ this.removeAppKeySetData = removeAppKeySetData;
+ }
+
+ /**
+ * Returns a combined set of packages containing the packages already installed combined
+ * with the package(s) currently being installed. The to-be installed packages take
+ * precedence and may shadow already installed packages.
+ */
+ private Map<String, PackageParser.Package> getCombinedPackages() {
+ final ArrayMap<String, PackageParser.Package> combinedPackages =
+ new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
+
+ combinedPackages.putAll(request.allPackages);
+ for (ScanResult scanResult : request.scannedPackages.values()) {
+ combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+ }
+ return combinedPackages;
+ }
+ }
+
+ @GuardedBy("mPackages")
+ private static Map<String, ReconciledPackage> reconcilePackagesLocked(
+ final ReconcileRequest request, KeySetManagerService ksms)
+ throws ReconcileFailure {
+ final Map<String, ScanResult> scannedPackages = request.scannedPackages;
+
+ final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
+
+ // make a copy of the existing set of packages so we can combine them with incoming packages
+ final ArrayMap<String, PackageParser.Package> combinedPackages =
+ new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+ combinedPackages.putAll(request.allPackages);
+
+ final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
+ new ArrayMap<>();
+
+ for (String installPackageName : scannedPackages.keySet()) {
+ final ScanResult scanResult = scannedPackages.get(installPackageName);
+
+ // add / replace existing with incoming packages
+ combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+
+ // in the first pass, we'll build up the set of incoming shared libraries
+ final List<SharedLibraryInfo> allowedSharedLibInfos =
+ getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource);
+ final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo;
+ if (allowedSharedLibInfos != null) {
+ for (SharedLibraryInfo info : allowedSharedLibInfos) {
+ if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) {
+ throw new ReconcileFailure("Static Shared Library " + staticLib.getName()
+ + " is being installed twice in this set!");
+ }
+ }
+ }
+
+ // the following may be null if we're just reconciling on boot (and not during install)
+ final InstallArgs installArgs = request.installArgs.get(installPackageName);
+ final PackageInstalledInfo res = request.installResults.get(installPackageName);
+ final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
+ final boolean isInstall = installArgs != null;
+ if (isInstall && (res == null || prepareResult == null)) {
+ throw new ReconcileFailure("Reconcile arguments are not balanced for "
+ + installPackageName + "!");
+ }
+
+ final DeletePackageAction deletePackageAction;
+ // we only want to try to delete for non system apps
+ if (isInstall && prepareResult.replace && !prepareResult.system) {
+ final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0;
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+ | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
+ deletePackageAction = mayDeletePackageLocked(res.removedInfo,
+ prepareResult.originalPs, prepareResult.disabledPs,
+ prepareResult.childPackageSettings, deleteFlags, null /* all users */);
+ if (deletePackageAction == null) {
+ throw new ReconcileFailure(
+ PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
+ "May not delete " + installPackageName + " to replace");
+ }
+ } else {
+ deletePackageAction = null;
+ }
+
+ final int scanFlags = scanResult.request.scanFlags;
+ final int parseFlags = scanResult.request.parseFlags;
+ final PackageParser.Package pkg = scanResult.request.pkg;
+
+ final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
+ final PackageSetting lastStaticSharedLibSetting =
+ request.lastStaticSharedLibSettings.get(installPackageName);
+ final PackageSetting signatureCheckPs =
+ (prepareResult != null && lastStaticSharedLibSetting != null)
+ ? lastStaticSharedLibSetting
+ : scanResult.pkgSetting;
+ boolean removeAppKeySetData = false;
+ boolean sharedUserSignaturesChanged = false;
+ SigningDetails signingDetails = null;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+ // We just determined the app is signed correctly, so bring
+ // over the latest parsed certs.
+ } else {
+ if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "Package " + pkg.packageName + " upgrade keys do not match the "
+ + "previously installed version");
+ } else {
+ String msg = "System package " + pkg.packageName
+ + " signature changed; retaining data.";
+ reportSettingsProblem(Log.WARN, msg);
+ }
+ }
+ signingDetails = pkg.mSigningDetails;
+ } else {
+ try {
+ final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
+ final boolean compatMatch = verifySignatures(signatureCheckPs,
+ disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ removeAppKeySetData = true;
+ }
+ // We just determined the app is signed correctly, so bring
+ // over the latest parsed certs.
+ signingDetails = pkg.mSigningDetails;
+
+
+ // if this is is a sharedUser, check to see if the new package is signed by a
+ // newer
+ // signing certificate than the existing one, and if so, copy over the new
+ // details
+ if (signatureCheckPs.sharedUser != null) {
+ if (pkg.mSigningDetails.hasAncestor(
+ signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
+ signatureCheckPs.sharedUser.signatures.mSigningDetails =
+ pkg.mSigningDetails;
+ }
+ if (signatureCheckPs.sharedUser.signaturesChanged == null) {
+ signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
+ }
+ }
+ } catch (PackageManagerException e) {
+ if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ throw new ReconcileFailure(e);
+ }
+ signingDetails = pkg.mSigningDetails;
+
+ // If the system app is part of a shared user we allow that shared user to
+ // change
+ // signatures as well as part of an OTA. We still need to verify that the
+ // signatures
+ // are consistent within the shared user for a given boot, so only allow
+ // updating
+ // the signatures on the first package scanned for the shared user (i.e. if the
+ // signaturesChanged state hasn't been initialized yet in SharedUserSetting).
+ if (signatureCheckPs.sharedUser != null) {
+ final Signature[] sharedUserSignatures =
+ signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
+ if (signatureCheckPs.sharedUser.signaturesChanged != null
+ && compareSignatures(sharedUserSignatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH) {
+ if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
+ // Mismatched signatures is an error and silently skipping system
+ // packages will likely break the device in unforeseen ways.
+ // However, we allow the device to boot anyway because, prior to Q,
+ // vendors were not expecting the platform to crash in this
+ // situation.
+ // This WILL be a hard failure on any new API levels after Q.
+ throw new ReconcileFailure(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Signature mismatch for shared user: "
+ + scanResult.pkgSetting.sharedUser);
+ } else {
+ // Treat mismatched signatures on system packages using a shared
+ // UID as
+ // fatal for the system overall, rather than just failing to install
+ // whichever package happened to be scanned later.
+ throw new IllegalStateException(
+ "Signature mismatch on system package "
+ + pkg.packageName + " for shared user "
+ + scanResult.pkgSetting.sharedUser);
+ }
+ }
+
+ sharedUserSignaturesChanged = true;
+ signatureCheckPs.sharedUser.signatures.mSigningDetails =
+ pkg.mSigningDetails;
+ signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE;
+ }
+ // File a report about this.
+ String msg = "System package " + pkg.packageName
+ + " signature changed; retaining data.";
+ reportSettingsProblem(Log.WARN, msg);
+ } catch (IllegalArgumentException e) {
+ // should never happen: certs matched when checking, but not when comparing
+ // old to new for sharedUser
+ throw new RuntimeException(
+ "Signing certificates comparison made on incomparable signing details"
+ + " but somehow passed verifySignatures!", e);
+ }
+ }
+
+ result.put(installPackageName,
+ new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
+ res, request.preparedPackages.get(installPackageName), scanResult,
+ deletePackageAction, allowedSharedLibInfos, signingDetails,
+ sharedUserSignaturesChanged, removeAppKeySetData));
+ }
+
+ for (String installPackageName : scannedPackages.keySet()) {
+ // Check all shared libraries and map to their actual file path.
+ // We only do this here for apps not on a system dir, because those
+ // are the only ones that can fail an install due to this. We
+ // will take care of the system apps by updating all of their
+ // library paths after the scan is done. Also during the initial
+ // scan don't update any libs as we do this wholesale after all
+ // apps are scanned to avoid dependency based scanning.
+ final ScanResult scanResult = scannedPackages.get(installPackageName);
+ if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0
+ || (scanResult.request.parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ continue;
+ }
+ try {
+ result.get(installPackageName).collectedSharedLibraryInfos =
+ collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
+ request.sharedLibrarySource, incomingSharedLibraries);
+
+ } catch (PackageManagerException e) {
+ throw new ReconcileFailure(e.error, e.getMessage());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Compare the newly scanned package with current system state to see which of its declared
+ * shared libraries should be allowed to be added to the system.
+ */
+ private static List<SharedLibraryInfo> getAllowedSharedLibInfos(
+ ScanResult scanResult,
+ Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
+ // Let's used the parsed package as scanResult.pkgSetting may be null
+ final PackageParser.Package pkg = scanResult.request.pkg;
+ if (scanResult.staticSharedLibraryInfo == null
+ && scanResult.dynamicSharedLibraryInfos == null) {
+ return null;
+ }
+
+ // Any app can add new static shared libraries
+ if (scanResult.staticSharedLibraryInfo != null) {
+ return Collections.singletonList(scanResult.staticSharedLibraryInfo);
+ }
+ final boolean hasDynamicLibraries =
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+ && scanResult.dynamicSharedLibraryInfos != null;
+ if (!hasDynamicLibraries) {
+ return null;
+ }
+ final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp();
+ // We may not yet have disabled the updated package yet, so be sure to grab the
+ // current setting if that's the case.
+ final PackageSetting updatedSystemPs = isUpdatedSystemApp
+ ? scanResult.request.disabledPkgSetting == null
+ ? scanResult.request.oldPkgSetting
+ : scanResult.request.disabledPkgSetting
+ : null;
+ if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
+ || updatedSystemPs.pkg.libraryNames == null)) {
+ Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not "
+ + "declared on the system image; skipping");
+ return null;
+ }
+ final ArrayList<SharedLibraryInfo> infos =
+ new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size());
+ for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) {
+ final String name = info.getName();
+ if (isUpdatedSystemApp) {
+ // New library entries can only be added through the
+ // system image. This is important to get rid of a lot
+ // of nasty edge cases: for example if we allowed a non-
+ // system update of the app to add a library, then uninstalling
+ // the update would make the library go away, and assumptions
+ // we made such as through app install filtering would now
+ // have allowed apps on the device which aren't compatible
+ // with it. Better to just have the restriction here, be
+ // conservative, and create many fewer cases that can negatively
+ // impact the user experience.
+ if (!updatedSystemPs.pkg.libraryNames.contains(name)) {
+ Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+ + " that is not declared on system image; skipping");
+ continue;
+ }
+ }
+ if (sharedLibExists(
+ name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
+ Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+ + " that already exists; skipping");
+ continue;
+ }
+ infos.add(info);
+ }
+ return infos;
+ }
+
+ /**
+ * Returns false if the adding shared library already exists in the map and so could not be
+ * added.
+ */
+ private static boolean addSharedLibraryToPackageVersionMap(
+ Map<String, LongSparseArray<SharedLibraryInfo>> target,
+ SharedLibraryInfo library) {
+ final String name = library.getName();
+ if (target.containsKey(name)) {
+ if (library.getType() != SharedLibraryInfo.TYPE_STATIC) {
+ // We've already added this non-version-specific library to the map.
+ return false;
+ } else if (target.get(name).indexOfKey(library.getLongVersion()) >= 0) {
+ // We've already added this version of a version-specific library to the map.
+ return false;
+ }
+ } else {
+ target.put(name, new LongSparseArray<>());
+ }
+ target.get(name).put(library.getLongVersion(), library);
+ return true;
+ }
+
+ @GuardedBy("mPackages")
+ private void commitPackagesLocked(final CommitRequest request) {
+ // TODO: remove any expected failures from this method; this should only be able to fail due
+ // to unavoidable errors (I/O, etc.)
+ for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
+ final ScanResult scanResult = reconciledPkg.scanResult;
+ final ScanRequest scanRequest = scanResult.request;
+ final PackageParser.Package pkg = scanRequest.pkg;
+ final String packageName = pkg.packageName;
+ final PackageInstalledInfo res = reconciledPkg.installResult;
+
+ if (reconciledPkg.prepareResult.replace) {
+ PackageParser.Package oldPackage = mPackages.get(packageName);
+
+ // Set the update and install times
+ PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+ setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+ System.currentTimeMillis());
+
+ if (reconciledPkg.prepareResult.system) {
+ // Remove existing system package
+ removePackageLI(oldPackage, true);
+ if (!disableSystemPackageLPw(oldPackage, pkg)) {
+ // We didn't need to disable the .apk as a current system package,
+ // which means we are replacing another update that is already
+ // installed. We need to make sure to delete the older one's .apk.
+ res.removedInfo.args = createInstallArgsForExisting(
+ oldPackage.applicationInfo.getCodePath(),
+ oldPackage.applicationInfo.getResourcePath(),
+ getAppDexInstructionSets(oldPackage.applicationInfo));
+ } else {
+ res.removedInfo.args = null;
+ }
+
+ // Update the package dynamic state if succeeded
+ // Now that the install succeeded make sure we remove data
+ // directories for any child package the update removed.
+ final int deletedChildCount = (oldPackage.childPackages != null)
+ ? oldPackage.childPackages.size() : 0;
+ final int newChildCount = (pkg.childPackages != null)
+ ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < deletedChildCount; i++) {
+ PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
+ boolean childPackageDeleted = true;
+ for (int j = 0; j < newChildCount; j++) {
+ PackageParser.Package newChildPkg = pkg.childPackages.get(j);
+ if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
+ childPackageDeleted = false;
+ break;
+ }
+ }
+ if (childPackageDeleted) {
+ PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
+ deletedChildPkg.packageName);
+ if (ps1 != null && res.removedInfo.removedChildPackages != null) {
+ PackageRemovedInfo removedChildRes = res.removedInfo
+ .removedChildPackages.get(deletedChildPkg.packageName);
+ removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
+ false);
+ removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
+ == null;
+ }
+ }
+ }
+ } else {
+ try {
+ executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
+ true, request.mAllUsers, true, pkg);
+ } catch (SystemDeleteException e) {
+ if (Build.IS_ENG) {
+ throw new RuntimeException("Unexpected failure", e);
+ // ignore; not possible for non-system app
+ }
+ }
+ // Successfully deleted the old package; proceed with replace.
+
+ // If deleted package lived in a container, give users a chance to
+ // relinquish resources before killing.
+ if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + oldPackage
+ + " is ASEC-hosted -> UNAVAILABLE");
+ }
+ final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+ final ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(oldPackage.applicationInfo.packageName);
+ sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+ }
+
+ // Update the in-memory copy of the previous code paths.
+ PackageSetting ps1 = mSettings.mPackages.get(
+ reconciledPkg.prepareResult.existingPackage.packageName);
+ if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
+ == 0) {
+ if (ps1.mOldCodePaths == null) {
+ ps1.mOldCodePaths = new ArraySet<>();
+ }
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
+ if (oldPackage.splitCodePaths != null) {
+ Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+ }
+ } else {
+ ps1.mOldCodePaths = null;
+ }
+ if (ps1.childPackageNames != null) {
+ for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
+ final String childPkgName = ps1.childPackageNames.get(i);
+ final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+ childPs.mOldCodePaths = ps1.mOldCodePaths;
+ }
+ }
+
+ if (reconciledPkg.installResult.returnCode
+ == PackageManager.INSTALL_SUCCEEDED) {
+ PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+ if (ps2 != null) {
+ res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
+ if (res.removedInfo.removedChildPackages != null) {
+ final int childCount1 = res.removedInfo.removedChildPackages.size();
+ // Iterate in reverse as we may modify the collection
+ for (int i = childCount1 - 1; i >= 0; i--) {
+ String childPackageName =
+ res.removedInfo.removedChildPackages.keyAt(i);
+ if (res.addedChildPackages.containsKey(childPackageName)) {
+ res.removedInfo.removedChildPackages.removeAt(i);
+ } else {
+ PackageRemovedInfo childInfo = res.removedInfo
+ .removedChildPackages.valueAt(i);
+ childInfo.removedForAllUsers = mPackages.get(
+ childInfo.removedPackage) == null;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ commitReconciledScanResultLocked(reconciledPkg);
+ updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
+ res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);
+
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+ ps.setUpdateAvailable(false /*updateAvailable*/);
+ }
+ final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ PackageInstalledInfo childRes = res.addedChildPackages.get(
+ childPkg.packageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
+ if (childPs != null) {
+ childRes.newUsers = childPs.queryInstalledUsers(
+ sUserManager.getUserIds(), true);
+ }
+ }
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ updateSequenceNumberLP(ps, res.newUsers);
+ updateInstantAppInstallerLocked(packageName);
+ }
+ }
+ }
+
+ /**
+ * Installs one or more packages atomically. This operation is broken up into four phases:
+ * <ul>
+ * <li><b>Prepare</b>
+ * <br/>Analyzes any current install state, parses the package and does initial
+ * validation on it.</li>
+ * <li><b>Scan</b>
+ * <br/>Interrogates the parsed packages given the context collected in prepare.</li>
+ * <li><b>Reconcile</b>
+ * <br/>Validates scanned packages in the context of each other and the current system
+ * state to ensure that the install will be successful.
+ * <li><b>Commit</b>
+ * <br/>Commits all scanned packages and updates system state. This is the only place
+ * that system state may be modified in the install flow and all predictable errors
+ * must be determined before this phase.</li>
+ * </ul>
+ *
+ * Failure at any phase will result in a full failure to install all packages.
+ */
+ @GuardedBy("mInstallLock")
+ private void installPackagesLI(List<InstallRequest> requests) {
+ final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
+ final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
+ final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
+ final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
+ final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
+ final Map<String, PackageSetting> lastStaticSharedLibSettings =
+ new ArrayMap<>(requests.size());
+ final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
+ boolean success = false;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
+ for (InstallRequest request : requests) {
+ // TODO(b/109941548): remove this once we've pulled everything from it and into
+ // scan, reconcile or commit.
+ final PrepareResult prepareResult;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
+ prepareResult = preparePackageLI(request.args, request.installResult);
+ } catch (PrepareFailure prepareFailure) {
+ request.installResult.setError(prepareFailure.error,
+ prepareFailure.getMessage());
+ request.installResult.origPackage = prepareFailure.conflictingPackage;
+ request.installResult.origPermission = prepareFailure.conflictingPermission;
+ return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ request.installResult.installerPackageName = request.args.installerPackageName;
+
+ final String packageName = prepareResult.packageToScan.packageName;
+ prepareResults.put(packageName, prepareResult);
+ installResults.put(packageName, request.installResult);
+ installArgs.put(packageName, request.args);
+ try {
+ final List<ScanResult> scanResults = scanPackageTracedLI(
+ prepareResult.packageToScan, prepareResult.parseFlags,
+ prepareResult.scanFlags, System.currentTimeMillis(),
+ request.args.user);
+ for (ScanResult result : scanResults) {
+ if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
+ request.installResult.setError(
+ PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Duplicate package " + result.pkgSetting.pkg.packageName
+ + " in multi-package install request.");
+ return;
+ }
+ createdAppId.put(packageName, optimisticallyRegisterAppId(result));
+ versionInfos.put(result.pkgSetting.pkg.packageName,
+ getSettingsVersionForPackage(result.pkgSetting.pkg));
+ if (result.staticSharedLibraryInfo != null) {
+ final PackageSetting sharedLibLatestVersionSetting =
+ getSharedLibLatestVersionSetting(result);
+ if (sharedLibLatestVersionSetting != null) {
+ lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
+ sharedLibLatestVersionSetting);
+ }
+ }
+ }
+ } catch (PackageManagerException e) {
+ request.installResult.setError("Scanning Failed.", e);
+ return;
+ }
+ }
+ ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
+ installResults,
+ prepareResults,
+ mSharedLibraries,
+ Collections.unmodifiableMap(mPackages), versionInfos,
+ lastStaticSharedLibSettings);
+ CommitRequest commitRequest = null;
+ synchronized (mPackages) {
+ Map<String, ReconciledPackage> reconciledPackages;
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
+ reconciledPackages = reconcilePackagesLocked(
+ reconcileRequest, mSettings.mKeySetManagerService);
+ } catch (ReconcileFailure e) {
+ for (InstallRequest request : requests) {
+ request.installResult.setError("Reconciliation failed...", e);
+ }
+ return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
+ commitRequest = new CommitRequest(reconciledPackages,
+ sUserManager.getUserIds());
+ commitPackagesLocked(commitRequest);
+ success = true;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
-
- // When replacing an existing package, preserve the original install reason for all
- // users that had the package installed before.
- final Set<Integer> previousUserIds = new ArraySet<>();
- if (res.removedInfo != null && res.removedInfo.installReasons != null) {
- final int installReasonCount = res.removedInfo.installReasons.size();
- for (int i = 0; i < installReasonCount; i++) {
- final int previousUserId = res.removedInfo.installReasons.keyAt(i);
- final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);
- ps.setInstallReason(previousInstallReason, previousUserId);
- previousUserIds.add(previousUserId);
+ }
+ executePostCommitSteps(commitRequest);
+ } finally {
+ if (!success) {
+ for (ScanResult result : preparedScans.values()) {
+ if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
+ cleanUpAppIdCreation(result);
}
}
-
- // Set install reason for users that are having the package newly installed.
- if (userId == UserHandle.USER_ALL) {
- for (int currentUserId : sUserManager.getUserIds()) {
- if (!previousUserIds.contains(currentUserId)) {
- ps.setInstallReason(installReason, currentUserId);
- }
+ // TODO(patb): create a more descriptive reason than unknown in future release
+ // mark all non-failure installs as UNKNOWN so we do not treat them as success
+ for (InstallRequest request : requests) {
+ if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
- } else if (!previousUserIds.contains(userId)) {
- ps.setInstallReason(installReason, userId);
}
- mSettings.writeKernelMappingLPr(ps);
}
- res.name = pkgName;
- res.uid = newPackage.applicationInfo.uid;
- res.pkg = newPackage;
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
- mSettings.setInstallerPackageName(pkgName, installerPackageName);
- res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- //to update install status
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
+ for (PrepareResult result : prepareResults.values()) {
+ if (result.freezer != null) {
+ result.freezer.close();
+ }
+ }
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ /**
+ * On successful install, executes remaining steps after commit completes and the package lock
+ * is released. These are typically more expensive or require calls to installd, which often
+ * locks on {@link #mPackages}.
+ */
+ private void executePostCommitSteps(CommitRequest commitRequest) {
+ for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
+ final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
+ & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
+ final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
+ final String packageName = pkg.packageName;
+ prepareAppDataAfterInstallLIF(pkg);
+ if (reconciledPkg.prepareResult.clearCodeCache) {
+ clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ }
+ if (reconciledPkg.prepareResult.replace) {
+ mDexManager.notifyPackageUpdated(pkg.packageName,
+ pkg.baseCodePath, pkg.splitCodePaths);
+ }
+
+ // Prepare the application profiles for the new code paths.
+ // This needs to be done before invoking dexopt so that any install-time profile
+ // can be used for optimizations.
+ mArtManagerService.prepareAppProfiles(
+ pkg,
+ resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
+ /* updateReferenceProfileContent= */ true);
+
+ // Check whether we need to dexopt the app.
+ //
+ // NOTE: it is IMPORTANT to call dexopt:
+ // - after doRename which will sync the package data from PackageParser.Package and
+ // its corresponding ApplicationInfo.
+ // - after installNewPackageLIF or replacePackageLIF which will update result with the
+ // uid of the application (pkg.applicationInfo.uid).
+ // This update happens in place!
+ //
+ // We only need to dexopt if the package meets ALL of the following conditions:
+ // 1) it is not an instant app or if it is then dexopt is enabled via gservices.
+ // 2) it is not debuggable.
+ //
+ // Note that we do not dexopt instant apps by default. dexopt can take some time to
+ // complete, so we skip this step during installation. Instead, we'll take extra time
+ // the first time the instant app starts. It's preferred to do it this way to provide
+ // continuous progress to the useur instead of mysteriously blocking somewhere in the
+ // middle of running an instant app. The default behaviour can be overridden
+ // via gservices.
+ final boolean performDexopt =
+ (!instantApp || Global.getInt(mContext.getContentResolver(),
+ Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
+ && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+
+ if (performDexopt) {
+ // Compile the layout resources.
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
+ mViewCompiler.compileLayouts(pkg);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ DexoptOptions dexoptOptions = new DexoptOptions(packageName,
+ REASON_INSTALL,
+ DexoptOptions.DEXOPT_BOOT_COMPLETE
+ | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
+ mPackageDexOptimizer.performDexOpt(pkg,
+ null /* instructionSets */,
+ getOrCreateCompilerPackageStats(pkg),
+ mDexManager.getPackageUseInfoOrDefault(packageName),
+ dexoptOptions);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Notify BackgroundDexOptService that the package has been changed.
+ // If this is an update of a package which used to fail to compile,
+ // BackgroundDexOptService will remove it from its blacklist.
+ // TODO: Layering violation
+ BackgroundDexOptService.notifyPackageChanged(packageName);
+ }
}
- private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
- installPackageLI(args, res);
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ /**
+ * The set of data needed to successfully install the prepared package. This includes data that
+ * will be used to scan and reconcile the package.
+ */
+ private static class PrepareResult {
+ public final int installReason;
+ public final String volumeUuid;
+ public final String installerPackageName;
+ public final UserHandle user;
+ public final boolean replace;
+ public final int scanFlags;
+ public final int parseFlags;
+ @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+ public final PackageParser.Package existingPackage;
+ public final PackageParser.Package packageToScan;
+ public final boolean clearCodeCache;
+ public final boolean system;
+ /* The original package name if it was changed during an update, otherwise {@code null}. */
+ @Nullable
+ public final String renamedPackage;
+ public final PackageFreezer freezer;
+ public final PackageSetting originalPs;
+ public final PackageSetting disabledPs;
+ public final PackageSetting[] childPackageSettings;
+
+ private PrepareResult(int installReason, String volumeUuid,
+ String installerPackageName, UserHandle user, boolean replace, int scanFlags,
+ int parseFlags, PackageParser.Package existingPackage,
+ PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
+ String renamedPackage, PackageFreezer freezer, PackageSetting originalPs,
+ PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
+ this.installReason = installReason;
+ this.volumeUuid = volumeUuid;
+ this.installerPackageName = installerPackageName;
+ this.user = user;
+ this.replace = replace;
+ this.scanFlags = scanFlags;
+ this.parseFlags = parseFlags;
+ this.existingPackage = existingPackage;
+ this.packageToScan = packageToScan;
+ this.clearCodeCache = clearCodeCache;
+ this.system = system;
+ this.renamedPackage = renamedPackage;
+ this.freezer = freezer;
+ this.originalPs = originalPs;
+ this.disabledPs = disabledPs;
+ this.childPackageSettings = childPackageSettings;
+ }
+ }
+
+ private static class PrepareFailure extends PackageManagerException {
+
+ public String conflictingPackage;
+ public String conflictingPermission;
+
+ PrepareFailure(int error) {
+ super(error, "Failed to prepare for install.");
+ }
+
+ PrepareFailure(int error, String detailMessage) {
+ super(error, detailMessage);
+ }
+
+ PrepareFailure(String message, Exception e) {
+ super(e instanceof PackageParserException
+ ? ((PackageParserException) e).error
+ : ((PackageManagerException) e).error,
+ ExceptionUtils.getCompleteMessage(message, e));
+ }
+
+ PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
+ String conflictingPackage) {
+ this.conflictingPermission = conflictingPermission;
+ this.conflictingPackage = conflictingPackage;
+ return this;
}
}
- private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
+ @GuardedBy("mInstallLock")
+ private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
+ throws PrepareFailure {
final int installFlags = args.installFlags;
final String installerPackageName = args.installerPackageName;
final String volumeUuid = args.volumeUuid;
final File tmpPackageFile = new File(args.getCodePath());
- final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
- final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
- || (args.volumeUuid != null));
+ final boolean onExternal = args.volumeUuid != null;
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
- final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
final boolean virtualPreload =
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
- boolean replace = false;
- int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
+ @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
// moving a complete application; perform an initial scan on the new install location
scanFlags |= SCAN_INITIAL;
scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
}
- // Result object to be returned
- res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
- res.installerPackageName = installerPackageName;
-
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
// Sanity check
- if (instantApp && (forwardLocked || onExternal)) {
- Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
- + " external=" + onExternal);
- res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
- return;
+ if (instantApp && onExternal) {
+ Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
}
// Retrieve PackageSettings and parse package
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+ @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
- | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
- | (instantApp ? PackageParser.PARSE_IS_EPHEMERAL : 0)
- | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
+ | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
+
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
+ DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
- res.setError("Failed parse during installPackageLI", e);
- return;
+ throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- // Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
- if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
- res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
- "Instant app package must target O");
- return;
- }
- if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target targetSandboxVersion 2");
- res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
- "Instant app package must use targetSanboxVersion 2");
- return;
+ // Instant apps have several additional install-time checks.
+ if (instantApp) {
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ Slog.w(TAG,
+ "Instant app package " + pkg.packageName + " does not target at least O");
+ throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
+ "Instant app package must target at least O");
+ }
+ if (pkg.mSharedUserId != null) {
+ Slog.w(TAG, "Instant app package " + pkg.packageName
+ + " may not declare sharedUserId.");
+ throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
+ "Instant app package may not declare a sharedUserId");
+ }
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// No static shared libs on external storage
if (onExternal) {
Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
- res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Packages declaring static-shared libs cannot be updated");
- return;
}
}
}
String pkgName = res.name = pkg.packageName;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
- res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
- return;
+ throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
}
}
try {
// either use what we've been given or parse directly from the APK
- if (args.certificates != null) {
- try {
- PackageParser.populateCertificates(pkg, args.certificates);
- } catch (PackageParserException e) {
- // there was something wrong with the certificates we were given;
- // try to pull them from the APK
- PackageParser.collectCertificates(pkg, parseFlags);
- }
+ if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+ pkg.setSigningDetails(args.signingDetails);
} else {
- PackageParser.collectCertificates(pkg, parseFlags);
+ PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
- res.setError("Failed collect during installPackageLI", e);
- return;
+ throw new PrepareFailure("Failed collect during installPackageLI", e);
+ }
+
+ if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
+ < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+ Slog.w(TAG, "Instant app package " + pkg.packageName
+ + " is not signed with at least APK Signature Scheme v2");
+ throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
+ "Instant app package must be signed with APK Signature Scheme v2 or greater");
}
// Get rid of all references to package scan path via parser.
pp = null;
- String oldCodePath = null;
boolean systemApp = false;
+ boolean replace = false;
synchronized (mPackages) {
// Check if installing already existing package
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
- + oldName + " pkgName=" + pkgName);
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "Replacing existing renamed package: oldName="
+ + oldName + " pkgName=" + pkgName);
+ }
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
// Child packages are installed through the parent package
if (pkg.parentPackage != null) {
- res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ throw new PrepareFailure(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ pkg.parentPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
- return;
}
if (replace) {
final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
"Package " + pkg.packageName + " new target SDK " + newTargetSdk
+ " doesn't support runtime permissions but the old"
+ " target SDK " + oldTargetSdk + " does.");
- return;
}
- // Prevent apps from downgrading their targetSandbox.
- final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
- final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
- if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
- res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
- "Package " + pkg.packageName + " new target sandbox "
- + newTargetSandbox + " is incompatible with the previous value of"
- + oldTargetSandbox + ".");
- return;
+ // Prevent persistent apps from being updated
+ if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
+ && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
+ "Package " + oldPackage.packageName + " is a persistent app. "
+ + "Persistent apps are not updateable.");
}
-
// Prevent installing of child packages
if (oldPackage.parentPackage != null) {
- res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ throw new PrepareFailure(
+ PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Package " + pkg.packageName + " is child of package "
+ oldPackage.parentPackage + ". Child packages "
+ "can be updated only through the parent package.");
- return;
}
}
}
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
- SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
- if (libraryEntry != null) {
- signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
+ SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
+ if (libraryInfo != null) {
+ signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
}
}
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
- res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
- return;
}
} else {
try {
- verifySignaturesLP(signatureCheckPs, pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ // We don't care about disabledPkgSetting on install for now.
+ final boolean compatMatch = verifySignatures(
+ signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
+ compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPackages) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ }
} catch (PackageManagerException e) {
- res.setError(e.error, e.getMessage());
- return;
+ throw new PrepareFailure(e.error, e.getMessage());
}
}
- oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
+
int N = pkg.permissions.size();
- for (int i = N-1; i >= 0; i--) {
- PackageParser.Permission perm = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(perm.info.name);
+ for (int i = N - 1; i >= 0; i--) {
+ final PackageParser.Permission perm = pkg.permissions.get(i);
+ final BasePermission bp =
+ (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+ perm.info.name + "; Removing ephemeral.");
perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
}
+
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
- if (bp.sourcePackage.equals(pkg.packageName)
- && (bp.packageSetting instanceof PackageSetting)
- && (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,
- scanFlags))) {
- sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
+ final String sourcePackageName = bp.getSourcePackageName();
+ final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (sourcePackageName.equals(pkg.packageName)
+ && (ksms.shouldCheckUpgradeKeySetLocked(
+ sourcePackageSetting, scanFlags))) {
+ sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
- sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
+
+ // in the event of signing certificate rotation, we need to see if the
+ // package's certificate has rotated from the current one, or if it is an
+ // older certificate with which the current is ok with sharing permissions
+ if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
+ pkg.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+ sigsOk = true;
+ } else if (pkg.mSigningDetails.checkCapability(
+ sourcePackageSetting.signatures.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+
+ // the scanned package checks out, has signing certificate rotation
+ // history, and is newer; bring it over
+ sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
+ sigsOk = true;
+ } else {
+ sigsOk = false;
+ }
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
- if (!bp.sourcePackage.equals("android")) {
- res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
- + pkg.packageName + " attempting to redeclare permission "
- + perm.info.name + " already owned by " + bp.sourcePackage);
- res.origPermission = perm.info.name;
- res.origPackage = bp.sourcePackage;
- return;
+ if (!sourcePackageName.equals("android")) {
+ throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+ + pkg.packageName
+ + " attempting to redeclare permission "
+ + perm.info.name + " already owned by "
+ + sourcePackageName)
+ .conflictsWithExistingPermission(perm.info.name,
+ sourcePackageName);
} else {
Slog.w(TAG, "Package " + pkg.packageName
+ " attempting to redeclare system permission "
Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
+ "non-runtime permission " + perm.info.name
+ " to runtime; keeping old protection level");
- perm.info.protectionLevel = bp.protectionLevel;
+ perm.info.protectionLevel = bp.getProtectionLevel();
}
}
}
if (systemApp) {
if (onExternal) {
// Abort update; system app can't be replaced with app on sdcard
- res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
- return;
} else if (instantApp) {
// Abort update; system app can't be replaced with an instant app
- res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+ throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
"Cannot update a system app with an instant app");
- return;
}
}
pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
}
- } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
+ } else {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
try {
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
- args.abiOverride : pkg.cpuAbiOverride);
+ args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
- extractNativeLibs, mAppLib32InstallDir);
+ derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
- res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
- return;
- }
-
- // Shared libraries for the package need to be updated.
- synchronized (mPackages) {
- try {
- updateSharedLibrariesLPr(pkg, null);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
- }
+ throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+ "Error deriving application ABI");
}
}
- if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
- res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
- return;
+ if (!args.doRename(res.returnCode, pkg)) {
+ throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
}
- // Verify if we need to dexopt the app.
- //
- // NOTE: it is *important* to call dexopt after doRename which will sync the
- // package data from PackageParser.Package and its corresponding ApplicationInfo.
- //
- // We only need to dexopt if the package meets ALL of the following conditions:
- // 1) it is not forward locked.
- // 2) it is not on on an external ASEC container.
- // 3) it is not an instant app or if it is then dexopt is enabled via gservices.
- //
- // Note that we do not dexopt instant apps by default. dexopt can take some time to
- // complete, so we skip this step during installation. Instead, we'll take extra time
- // the first time the instant app starts. It's preferred to do it this way to provide
- // continuous progress to the useur instead of mysteriously blocking somewhere in the
- // middle of running an instant app. The default behaviour can be overridden
- // via gservices.
- final boolean performDexopt = !forwardLocked
- && !pkg.applicationInfo.isExternalAsec()
- && (!instantApp || Global.getInt(mContext.getContentResolver(),
- Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
-
- if (performDexopt) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
- REASON_INSTALL,
- DexoptOptions.DEXOPT_BOOT_COMPLETE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
- null /* instructionSets */,
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
- dexoptOptions);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ try {
+ setUpFsVerityIfPossible(pkg);
+ } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
+ throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to set up verity: " + e);
}
- // Notify BackgroundDexOptService that the package has been changed.
- // If this is an update of a package which used to fail to compile,
- // BackgroundDexOptService will remove it from its blacklist.
- // TODO: Layering violation
- BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
-
- startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
-
- try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
- "installPackageLI")) {
+ if (!instantApp) {
+ startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+ } else {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
+ }
+ }
+ final PackageFreezer freezer =
+ freezePackageForInstall(pkgName, installFlags, "installPackageLI");
+ boolean shouldCloseFreezerBeforeReturn = true;
+ try {
+ final PackageParser.Package existingPackage;
+ String renamedPackage = null;
+ boolean sysPkg = false;
+ String targetVolumeUuid = volumeUuid;
+ int targetScanFlags = scanFlags;
+ int targetParseFlags = parseFlags;
+ final PackageSetting ps;
+ final PackageSetting disabledPs;
+ final PackageSetting[] childPackages;
if (replace) {
+ targetVolumeUuid = null;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// Static libs have a synthetic package name containing the version
// and cannot be updated as an update would get a new package name,
// unless this is the exact same version code which is useful for
// development.
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
- if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
- res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
- + "static-shared libs cannot be updated");
- return;
+ if (existingPkg != null
+ && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+ throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Packages declaring "
+ + "static-shared libs cannot be updated");
}
}
- replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, res, args.installReason);
- } else {
- installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, volumeUuid, res, args.installReason);
+
+ final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+
+ final PackageParser.Package oldPackage;
+ final String pkgName11 = pkg.packageName;
+ final int[] allUsers;
+ final int[] installedUsers;
+
+ synchronized (mPackages) {
+ oldPackage = mPackages.get(pkgName11);
+ existingPackage = oldPackage;
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG,
+ "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+ }
+
+ ps = mSettings.mPackages.get(pkgName11);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
+
+ // verify signatures are valid
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "New package not signed by keys specified by upgrade-keysets: "
+ + pkgName11);
+ }
+ } else {
+ // default to original signature matching
+ if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+ SigningDetails.CertCapabilities.INSTALLED_DATA)
+ && !oldPackage.mSigningDetails.checkCapability(
+ pkg.mSigningDetails,
+ SigningDetails.CertCapabilities.ROLLBACK)) {
+ throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "New package has a different signature: " + pkgName11);
+ }
+ }
+
+ // don't allow a system upgrade unless the upgrade hash matches
+ if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+ final byte[] digestBytes;
+ try {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+ updateDigest(digest, new File(pkg.baseCodePath));
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (String path : pkg.splitCodePaths) {
+ updateDigest(digest, new File(path));
+ }
+ }
+ digestBytes = digest.digest();
+ } catch (NoSuchAlgorithmException | IOException e) {
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+ "Could not compute hash: " + pkgName11);
+ }
+ if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+ throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+ "New package fails restrict-update check: " + pkgName11);
+ }
+ // retain upgrade restriction
+ pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+ }
+
+ // Check for shared user id changes
+ String invalidPackageName =
+ getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+ if (invalidPackageName != null) {
+ throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + invalidPackageName + " tried to change user "
+ + oldPackage.mSharedUserId);
+ }
+
+ // In case of rollback, remember per-user/profile install state
+ allUsers = sUserManager.getUserIds();
+ installedUsers = ps.queryInstalledUsers(allUsers, true);
+
+
+ // don't allow an upgrade from full to ephemeral
+ if (isInstantApp) {
+ if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
+ for (int currentUser : allUsers) {
+ if (!ps.getInstantApp(currentUser)) {
+ // can't downgrade from full to instant
+ Slog.w(TAG,
+ "Can't replace full app with instant app: " + pkgName11
+ + " for user: " + currentUser);
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+ }
+ }
+ } else if (!ps.getInstantApp(args.user.getIdentifier())) {
+ // can't downgrade from full to instant
+ Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
+ + " for user: " + args.user.getIdentifier());
+ throw new PrepareFailure(
+ PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+ }
+ }
+ }
+
+ // Update what is removed
+ res.removedInfo = new PackageRemovedInfo(this);
+ res.removedInfo.uid = oldPackage.applicationInfo.uid;
+ res.removedInfo.removedPackage = oldPackage.packageName;
+ res.removedInfo.installerPackageName = ps.installerPackageName;
+ res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+ res.removedInfo.isUpdate = true;
+ res.removedInfo.origUsers = installedUsers;
+ res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
+ for (int i = 0; i < installedUsers.length; i++) {
+ final int userId = installedUsers[i];
+ res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
+ }
+
+ childPackages = mSettings.getChildSettingsLPr(ps);
+ if (childPackages != null) {
+ for (PackageSetting childPs : childPackages) {
+ boolean childPackageUpdated = false;
+ PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
+ if (res.addedChildPackages != null) {
+ PackageInstalledInfo childRes = res.addedChildPackages.get(
+ childPkg.packageName);
+ if (childRes != null) {
+ childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ if (childPs != null) {
+ childRes.removedInfo.installerPackageName =
+ childPs.installerPackageName;
+ }
+ childRes.removedInfo.isUpdate = true;
+ childRes.removedInfo.installReasons =
+ res.removedInfo.installReasons;
+ childPackageUpdated = true;
+ }
+ }
+ if (!childPackageUpdated) {
+ PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
+ childRemovedRes.removedPackage = childPkg.packageName;
+ if (childPs != null) {
+ childRemovedRes.installerPackageName = childPs.installerPackageName;
+ }
+ childRemovedRes.isUpdate = false;
+ childRemovedRes.dataRemoved = true;
+ synchronized (mPackages) {
+ if (childPs != null) {
+ childRemovedRes.origUsers = childPs.queryInstalledUsers(
+ allUsers,
+ true);
+ }
+ }
+ if (res.removedInfo.removedChildPackages == null) {
+ res.removedInfo.removedChildPackages = new ArrayMap<>();
+ }
+ res.removedInfo.removedChildPackages.put(childPkg.packageName,
+ childRemovedRes);
+ }
+ }
+ }
+
+
+ sysPkg = (isSystemApp(oldPackage));
+ if (sysPkg) {
+ // Set the system/privileged/oem/vendor/product flags as needed
+ final boolean privileged = isPrivilegedApp(oldPackage);
+ final boolean oem = isOemApp(oldPackage);
+ final boolean vendor = isVendorApp(oldPackage);
+ final boolean product = isProductApp(oldPackage);
+ final boolean odm = isOdmApp(oldPackage);
+ final @ParseFlags int systemParseFlags = parseFlags;
+ final @ScanFlags int systemScanFlags = scanFlags
+ | SCAN_AS_SYSTEM
+ | (privileged ? SCAN_AS_PRIVILEGED : 0)
+ | (oem ? SCAN_AS_OEM : 0)
+ | (vendor ? SCAN_AS_VENDOR : 0)
+ | (product ? SCAN_AS_PRODUCT : 0)
+ | (odm ? SCAN_AS_ODM : 0);
+
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ + ", old=" + oldPackage);
+ }
+ res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+ pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ targetParseFlags = systemParseFlags;
+ targetScanFlags = systemScanFlags;
+ } else { // non system replace
+ replace = true;
+ if (DEBUG_INSTALL) {
+ Slog.d(TAG,
+ "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ + oldPackage);
+ }
+
+ String pkgName1 = oldPackage.packageName;
+ boolean deletedPkg = true;
+ boolean addedPkg = false;
+ boolean updatedSettings = false;
+
+ final long origUpdateTime = (pkg.mExtras != null)
+ ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
+
+ }
+ } else { // new package install
+ ps = null;
+ childPackages = null;
+ disabledPs = null;
+ replace = false;
+ existingPackage = null;
+ // Remember this for later, in case we need to rollback this install
+ String pkgName1 = pkg.packageName;
+
+ if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+
+ // TODO(patb): MOVE TO RECONCILE
+ synchronized (mPackages) {
+ renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
+ if (renamedPackage != null) {
+ // A package with the same name is already installed, though
+ // it has been renamed to an older name. The package we
+ // are trying to install should be installed as an update to
+ // the existing one, but that has not been requested, so bail.
+ throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+ "Attempt to re-install " + pkgName1
+ + " without first uninstalling package running as "
+ + renamedPackage);
+ }
+ if (mPackages.containsKey(pkgName1)) {
+ // Don't allow installation over an existing package with the same name.
+ throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+ "Attempt to re-install " + pkgName1
+ + " without first uninstalling.");
+ }
+ }
+ }
+ // we're passing the freezer back to be closed in a later phase of install
+ shouldCloseFreezerBeforeReturn = false;
+
+ return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
+ args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
+ replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
+ ps, disabledPs, childPackages);
+ } finally {
+ if (shouldCloseFreezerBeforeReturn) {
+ freezer.close();
}
}
+ }
+
+ /**
+ * Set up fs-verity for the given package if possible. This requires a feature flag of system
+ * property to be enabled only if the kernel supports fs-verity.
+ *
+ * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
+ * kernel patches). In normal mode, all file format can be supported.
+ */
+ private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+ PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
+ final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+ final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+ if (!standardMode && !legacyMode) {
+ return;
+ }
- synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
- ps.setUpdateAvailable(false /*updateAvailable*/);
+ // Collect files we care for fs-verity setup.
+ ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
+ if (legacyMode) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ if (ps != null && ps.isPrivileged()) {
+ fsverityCandidates.put(pkg.baseCodePath, null);
+ if (pkg.splitCodePaths != null) {
+ for (String splitPath : pkg.splitCodePaths) {
+ fsverityCandidates.put(splitPath, null);
+ }
+ }
+ }
+ }
+ } else {
+ // NB: These files will become only accessible if the signing key is loaded in kernel's
+ // .fs-verity keyring.
+ fsverityCandidates.put(pkg.baseCodePath,
+ VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+
+ final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+ if (new File(dmPath).exists()) {
+ fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
}
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
- PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
- if (childPs != null) {
- childRes.newUsers = childPs.queryInstalledUsers(
- sUserManager.getUserIds(), true);
+ if (pkg.splitCodePaths != null) {
+ for (String path : pkg.splitCodePaths) {
+ fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
+
+ final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
+ if (new File(splitDmPath).exists()) {
+ fsverityCandidates.put(splitDmPath,
+ VerityUtils.getFsveritySignatureFilePath(splitDmPath));
+ }
}
}
+ }
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- updateSequenceNumberLP(ps, res.newUsers);
- updateInstantAppInstallerLocked(pkgName);
+ for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
+ final String filePath = entry.getKey();
+ final String signaturePath = entry.getValue();
+
+ if (!legacyMode) {
+ // fs-verity is optional for now. Only set up if signature is provided.
+ if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
+ try {
+ VerityUtils.setUpFsverity(filePath, signaturePath);
+ } catch (IOException | DigestException | NoSuchAlgorithmException
+ | SecurityException e) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to enable fs-verity: " + e);
+ }
+ }
+ continue;
+ }
+
+ // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+ final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
+ if (result.isOk()) {
+ if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
+ final FileDescriptor fd = result.getUnownedFileDescriptor();
+ try {
+ final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+ try {
+ // A file may already have fs-verity, e.g. when reused during a split
+ // install. If the measurement succeeds, no need to attempt to set up.
+ mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+ } catch (InstallerException e) {
+ mInstaller.installApkVerity(filePath, fd, result.getContentSize());
+ mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+ }
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else if (result.isFailed()) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to generate verity");
}
}
}
int count = 0;
final String packageName = pkg.packageName;
+ boolean handlesWebUris = false;
+ final boolean alreadyVerified;
synchronized (mPackages) {
// If this is a new install and we see that we've already run verification for this
// package, we have nothing to do: it means the state was restored from backup.
- if (!replacing) {
- IntentFilterVerificationInfo ivi =
- mSettings.getIntentFilterVerificationLPr(packageName);
- if (ivi != null) {
- if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.i(TAG, "Package " + packageName+ " already verified: status="
- + ivi.getStatusString());
- }
- return;
+ final IntentFilterVerificationInfo ivi =
+ mSettings.getIntentFilterVerificationLPr(packageName);
+ alreadyVerified = (ivi != null);
+ if (!replacing && alreadyVerified) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Package " + packageName + " already verified: status="
+ + ivi.getStatusString());
}
+ return;
}
- // If any filters need to be verified, then all need to be.
+ // If any filters need to be verified, then all need to be. In addition, we need to
+ // know whether an updating app has any web navigation intent filters, to re-
+ // examine handling policy even if not re-verifying.
boolean needToVerify = false;
for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) {
+ if (filter.handlesWebUris(true)) {
+ handlesWebUris = true;
+ }
if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "Intent filter needs verification, so processing all filters");
+ Slog.d(TAG,
+ "Intent filter needs verification, so processing all filters");
}
needToVerify = true;
+ // It's safe to break out here because filter.needsVerification()
+ // can only be true if filter.handlesWebUris(true) returns true, so
+ // we've already noted that.
break;
}
}
}
+ // Note whether this app publishes any web navigation handling support at all,
+ // and whether there are any web-nav filters that fit the profile for running
+ // a verification pass now.
if (needToVerify) {
final int verificationId = mIntentFilterVerificationToken++;
for (PackageParser.Activity a : pkg.activities) {
}
if (count > 0) {
+ // count > 0 means that we're running a full verification pass
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
+ " IntentFilter verification" + (count > 1 ? "s" : "")
+ " for userId:" + userId);
mIntentFilterVerifier.startVerifications(userId);
+ } else if (alreadyVerified && handlesWebUris) {
+ // App used autoVerify in the past, no longer does, but still handles web
+ // navigation starts.
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
+ }
+ synchronized (mPackages) {
+ clearIntentFilterVerificationsLPw(packageName, userId);
+ }
} else {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "No filters or not all autoVerify for " + packageName);
+ Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
}
}
}
+ @GuardedBy("mPackages")
private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
final ComponentName cn = filter.activity.getComponentName();
final String packageName = cn.getPackageName();
int status = ivi.getStatus();
switch (status) {
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
return true;
return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
+ private static boolean isOemApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+ }
+
+ private static boolean isVendorApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+ }
+
+ private static boolean isProductApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+ }
+
+ private static boolean isProductServicesApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+ }
+
+ private static boolean isOdmApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+ }
+
private static boolean hasDomainURLs(PackageParser.Package pkg) {
return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
}
return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- private int packageFlagsToInstallFlags(PackageSetting ps) {
- int installFlags = 0;
- if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) {
- // This existing package was an external ASEC install when we have
- // the external flag without a UUID
- installFlags |= PackageManager.INSTALL_EXTERNAL;
- }
- if (ps.isForwardLocked()) {
- installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
- }
- return installFlags;
- }
-
- private String getVolumeUuidForPackage(PackageParser.Package pkg) {
- if (isExternal(pkg)) {
- if (TextUtils.isEmpty(pkg.volumeUuid)) {
- return StorageManager.UUID_PRIMARY_PHYSICAL;
- } else {
- return pkg.volumeUuid;
- }
- } else {
- return StorageManager.UUID_PRIVATE_INTERNAL;
- }
- }
-
private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
if (isExternal(pkg)) {
if (TextUtils.isEmpty(pkg.volumeUuid)) {
}
private void deleteTempPackageFiles() {
- final FilenameFilter filter = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.startsWith("vmdl") && name.endsWith(".tmp");
- }
- };
- for (File file : mDrmAppPrivateInstallDir.listFiles(filter)) {
- file.delete();
- }
+ final FilenameFilter filter =
+ (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
}
@Override
final boolean canViewInstantApps = canViewInstantApps(callingUid, userId);
Preconditions.checkNotNull(versionedPackage);
Preconditions.checkNotNull(observer);
- Preconditions.checkArgumentInRange(versionedPackage.getVersionCode(),
+ Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
PackageManager.VERSION_CODE_HIGHEST,
- Integer.MAX_VALUE, "versionCode must be >= -1");
+ Long.MAX_VALUE, "versionCode must be >= -1");
final String packageName = versionedPackage.getPackageName();
- final int versionCode = versionedPackage.getVersionCode();
+ final long versionCode = versionedPackage.getLongVersionCode();
final String internalPackageName;
synchronized (mPackages) {
// Normalize package name to handle renamed packages and static libs
- internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode());
+ internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode);
}
final int uid = Binder.getCallingUid();
if (!isOrphaned(internalPackageName)
&& !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
- try {
- final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
- intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
- intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
- observer.onUserActionRequired(intent);
- } catch (RemoteException re) {
- }
+ mHandler.post(() -> {
+ try {
+ final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+ intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
+ intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
+ observer.onUserActionRequired(intent);
+ } catch (RemoteException re) {
+ }
+ });
return;
}
final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
- final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
+ final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{userId};
if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
}
if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
- try {
- observer.onPackageDeleted(packageName,
- PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
- } catch (RemoteException re) {
- }
+ mHandler.post(() -> {
+ try {
+ observer.onPackageDeleted(packageName,
+ PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
+ } catch (RemoteException re) {
+ }
+ });
return;
}
if (!deleteAllUsers && getBlockUninstallForUser(internalPackageName, userId)) {
- try {
- observer.onPackageDeleted(packageName,
- PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
- } catch (RemoteException re) {
- }
+ mHandler.post(() -> {
+ try {
+ observer.onPackageDeleted(packageName,
+ PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
+ } catch (RemoteException re) {
+ }
+ });
return;
}
? "VERSION_CODE_HIGHEST" : versionCode));
}
// Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- int returnCode;
- final PackageSetting ps = mSettings.mPackages.get(internalPackageName);
- boolean doDeletePackage = true;
- if (ps != null) {
- final boolean targetIsInstantApp =
- ps.getInstantApp(UserHandle.getUserId(callingUid));
- doDeletePackage = !targetIsInstantApp
- || canViewInstantApps;
- }
- if (doDeletePackage) {
- if (!deleteAllUsers) {
+ mHandler.post(() -> {
+ int returnCode;
+ final PackageSetting ps = mSettings.mPackages.get(internalPackageName);
+ boolean doDeletePackage = true;
+ if (ps != null) {
+ final boolean targetIsInstantApp =
+ ps.getInstantApp(UserHandle.getUserId(callingUid));
+ doDeletePackage = !targetIsInstantApp
+ || canViewInstantApps;
+ }
+ if (doDeletePackage) {
+ if (!deleteAllUsers) {
+ returnCode = deletePackageX(internalPackageName, versionCode,
+ userId, deleteFlags);
+ } else {
+ int[] blockUninstallUserIds = getBlockUninstallForUsers(
+ internalPackageName, users);
+ // If nobody is blocking uninstall, proceed with delete for all users
+ if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
returnCode = deletePackageX(internalPackageName, versionCode,
userId, deleteFlags);
} else {
- int[] blockUninstallUserIds = getBlockUninstallForUsers(
- internalPackageName, users);
- // If nobody is blocking uninstall, proceed with delete for all users
- if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
- returnCode = deletePackageX(internalPackageName, versionCode,
- userId, deleteFlags);
- } else {
- // Otherwise uninstall individually for users with blockUninstalls=false
- final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS;
- for (int userId : users) {
- if (!ArrayUtils.contains(blockUninstallUserIds, userId)) {
- returnCode = deletePackageX(internalPackageName, versionCode,
- userId, userFlags);
- if (returnCode != PackageManager.DELETE_SUCCEEDED) {
- Slog.w(TAG, "Package delete failed for user " + userId
- + ", returnCode " + returnCode);
- }
+ // Otherwise uninstall individually for users with blockUninstalls=false
+ final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS;
+ for (int userId1 : users) {
+ if (!ArrayUtils.contains(blockUninstallUserIds, userId1)) {
+ returnCode = deletePackageX(internalPackageName, versionCode,
+ userId1, userFlags);
+ if (returnCode != PackageManager.DELETE_SUCCEEDED) {
+ Slog.w(TAG, "Package delete failed for user " + userId1
+ + ", returnCode " + returnCode);
}
}
- // The app has only been marked uninstalled for certain users.
- // We still need to report that delete was blocked
- returnCode = PackageManager.DELETE_FAILED_OWNER_BLOCKED;
}
+ // The app has only been marked uninstalled for certain users.
+ // We still need to report that delete was blocked
+ returnCode = PackageManager.DELETE_FAILED_OWNER_BLOCKED;
}
- } else {
- returnCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
- try {
- observer.onPackageDeleted(packageName, returnCode, null);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- } //end catch
- } //end run
+ } else {
+ returnCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
+ }
+ try {
+ observer.onPackageDeleted(packageName, returnCode, null);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ } //end catch
});
}
return pkg.packageName;
}
- private String resolveInternalPackageNameLPr(String packageName, int versionCode) {
+ @GuardedBy("mPackages")
+ private String resolveInternalPackageNameLPr(String packageName, long versionCode) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
// Is this a static library?
- SparseArray<SharedLibraryEntry> versionedLib =
+ LongSparseArray<SharedLibraryInfo> versionedLib =
mStaticLibsByDeclaringPackage.get(packageName);
if (versionedLib == null || versionedLib.size() <= 0) {
return packageName;
}
// Figure out which lib versions the caller can see
- SparseIntArray versionsCallerCanSee = null;
+ LongSparseLongArray versionsCallerCanSee = null;
final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
&& callingAppId != Process.ROOT_UID) {
- versionsCallerCanSee = new SparseIntArray();
- String libName = versionedLib.valueAt(0).info.getName();
+ versionsCallerCanSee = new LongSparseLongArray();
+ String libName = versionedLib.valueAt(0).getName();
String[] uidPackages = getPackagesForUid(Binder.getCallingUid());
if (uidPackages != null) {
for (String uidPackage : uidPackages) {
PackageSetting ps = mSettings.getPackageLPr(uidPackage);
final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
if (libIdx >= 0) {
- final int libVersion = ps.usesStaticLibrariesVersions[libIdx];
+ final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
versionsCallerCanSee.append(libVersion, libVersion);
}
}
}
// Find the version the caller can see and the app version code
- SharedLibraryEntry highestVersion = null;
+ SharedLibraryInfo highestVersion = null;
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- SharedLibraryEntry libEntry = versionedLib.valueAt(i);
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
- libEntry.info.getVersion()) < 0) {
+ libraryInfo.getLongVersion()) < 0) {
continue;
}
- final int libVersionCode = libEntry.info.getDeclaringPackage().getVersionCode();
+ final long libVersionCode = libraryInfo.getDeclaringPackage().getLongVersionCode();
if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (libVersionCode == versionCode) {
- return libEntry.apk;
+ return libraryInfo.getPackageName();
}
} else if (highestVersion == null) {
- highestVersion = libEntry;
- } else if (libVersionCode > highestVersion.info
- .getDeclaringPackage().getVersionCode()) {
- highestVersion = libEntry;
+ highestVersion = libraryInfo;
+ } else if (libVersionCode > highestVersion
+ .getDeclaringPackage().getLongVersionCode()) {
+ highestVersion = libraryInfo;
}
}
if (highestVersion != null) {
- return highestVersion.apk;
+ return highestVersion.getPackageName();
}
return packageName;
* persisting settings for later use
* sending a broadcast if necessary
*/
- int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) {
+ int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
final boolean res;
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
- PackageSetting uninstalledPs = null;
- PackageParser.Package pkg = null;
+ final PackageSetting uninstalledPs;
+ final PackageSetting disabledSystemPs;
+ final PackageParser.Package pkg;
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
int[] allUsers;
+ /** enabled state of the uninstalled application */
+ final int origEnabledState;
synchronized (mPackages) {
uninstalledPs = mSettings.mPackages.get(packageName);
if (uninstalledPs == null) {
return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName);
+ // Save the enabled state before we delete the package. When deleting a stub
+ // application we always set the enabled state to 'disabled'.
+ origEnabledState = uninstalledPs == null
+ ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId);
// Static shared libs can be declared by any package, so let us not
// allow removing a package if it provides a lib others depend on.
pkg = mPackages.get(packageName);
allUsers = sUserManager.getUserIds();
if (pkg != null && pkg.staticSharedLibName != null) {
- SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(pkg.staticSharedLibName,
+ SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
pkg.staticSharedLibVersion);
- if (libEntry != null) {
+ if (libraryInfo != null) {
for (int currUserId : allUsers) {
if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) {
continue;
}
List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
- libEntry.info, 0, currUserId);
+ libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
- + " hosting lib " + libEntry.info.getName() + " version "
- + libEntry.info.getVersion() + " used by " + libClientPackages
+ + " hosting lib " + libraryInfo.getName() + " version "
+ + libraryInfo.getLongVersion() + " used by " + libClientPackages
+ " for user " + currUserId);
return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
}
try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
deleteFlags, "deletePackageX")) {
res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
- deleteFlags | FLAGS_REMOVE_CHATTY, info, true, null);
+ deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
}
synchronized (mPackages) {
if (res) {
Runtime.getRuntime().gc();
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
- if (info.args != null) {
- synchronized (mInstallLock) {
+ synchronized (mInstallLock) {
+ if (info.args != null) {
info.args.doPostDeleteLI(true);
}
+ final PackageParser.Package stubPkg =
+ (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
+ if (stubPkg != null && stubPkg.isStub) {
+ synchronized (mPackages) {
+ // restore the enabled state of the stub; the state is overwritten when
+ // the stub is uninstalled
+ final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(origEnabledState, userId, "android");
+ }
+ }
+ if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT
+ || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ + stubPkg.packageName);
+ }
+ enableCompressedPackage(stubPkg);
+ }
+ }
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
int[] origUsers;
int[] removedUsers = null;
int[] broadcastUsers = null;
+ int[] instantUserIds = null;
SparseArray<Integer> installReasons;
boolean isRemovedPackageSystemUpdate = false;
boolean isUpdate;
PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
packageSender.sendPackageAddedForNewUsers(installedInfo.name,
true /*sendBootCompleted*/, false /*startReceiver*/,
- UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers);
+ UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers, null);
}
}
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- removedPackage, extras, 0, null /*targetPackage*/, null, null);
+ removedPackage, extras, 0, null /*targetPackage*/, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- removedPackage, extras, 0, null /*targetPackage*/, null, null);
+ removedPackage, extras, 0, null /*targetPackage*/, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
- null, null, 0, removedPackage, null, null);
+ null, null, 0, removedPackage, null, null, null);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null);
+ installerPackageName, null, null, null);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null);
+ installerPackageName, null, null, null);
}
}
return;
}
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ final int removedUid = removedAppId >= 0 ? removedAppId : uid;
+ extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
if (isUpdate || isRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
- removedPackage, extras, 0, null /*targetPackage*/, null, broadcastUsers);
+ removedPackage, extras, 0, null /*targetPackage*/, null,
+ broadcastUsers, instantUserIds);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, broadcastUsers);
+ installerPackageName, null, broadcastUsers, instantUserIds);
}
if (dataRemoved && !isRemovedPackageSystemUpdate) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras,
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers);
+ null, null, broadcastUsers, instantUserIds);
+ packageSender.notifyPackageRemoved(removedPackage, removedUid);
}
}
if (removedAppId >= 0) {
+ // If a system app's updates are uninstalled the UID is not actually removed. Some
+ // services need to know the package name affected.
+ if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage);
+ }
+
packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
- null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers);
+ null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
+ null, null, broadcastUsers, instantUserIds);
}
}
}
broadcastUsers = EMPTY_INT_ARRAY;
+ instantUserIds = EMPTY_INT_ARRAY;
for (int i = userIds.length - 1; i >= 0; --i) {
final int userId = userIds[i];
if (deletedPackageSetting.getInstantApp(userId)) {
- continue;
+ instantUserIds = ArrayUtils.appendInt(instantUserIds, userId);
+ } else {
+ broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
}
- broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
}
}
}
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLIF(PackageSetting ps, int[] allUserHandles,
+ private void removePackageDataLIF(final PackageSetting deletedPs, int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
- String packageName = ps.name;
- if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
+ String packageName = deletedPs.name;
+ if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
// Retrieve object to delete permissions for shared user later on
- final PackageParser.Package deletedPkg;
- final PackageSetting deletedPs;
- // reader
- synchronized (mPackages) {
- deletedPkg = mPackages.get(packageName);
- deletedPs = mSettings.mPackages.get(packageName);
- if (outInfo != null) {
- outInfo.removedPackage = packageName;
- outInfo.installerPackageName = ps.installerPackageName;
- outInfo.isStaticSharedLib = deletedPkg != null
- && deletedPkg.staticSharedLibName != null;
- outInfo.populateUsers(deletedPs == null ? null
- : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
- }
+ final PackageParser.Package deletedPkg = deletedPs.pkg;
+ if (outInfo != null) {
+ outInfo.removedPackage = packageName;
+ outInfo.installerPackageName = deletedPs.installerPackageName;
+ outInfo.isStaticSharedLib = deletedPkg != null
+ && deletedPkg.staticSharedLibName != null;
+ outInfo.populateUsers(deletedPs == null ? null
+ : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
}
- removePackageLI(ps, (flags & FLAGS_REMOVE_CHATTY) != 0);
+ removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
final PackageParser.Package resolvedPkg;
} else {
// We don't have a parsed package when it lives on an ejected
// adopted storage device, so fake something together
- resolvedPkg = new PackageParser.Package(ps.name);
- resolvedPkg.setVolumeUuid(ps.volumeUuid);
+ resolvedPkg = new PackageParser.Package(deletedPs.name);
+ resolvedPkg.setVolumeUuid(deletedPs.volumeUuid);
}
destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- destroyAppProfilesLIF(resolvedPkg, UserHandle.USER_ALL);
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ destroyAppProfilesLIF(resolvedPkg);
if (outInfo != null) {
outInfo.dataRemoved = true;
}
- schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
int removedAppId = -1;
// writer
- synchronized (mPackages) {
- boolean installedStateChanged = false;
- if (deletedPs != null) {
- if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
+ boolean installedStateChanged = false;
+ if (deletedPs != null) {
+ if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ synchronized (mPackages) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
clearDefaultBrowserIfNeeded(packageName);
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
if (outInfo != null) {
outInfo.removedAppId = removedAppId;
}
- updatePermissionsLPw(deletedPs.name, null, 0);
+ mPermissionManager.updatePermissions(
+ deletedPs.name, null, false, mPackages.values(), mPermissionCallback);
if (deletedPs.sharedUser != null) {
// Remove permissions associated with package. Since runtime
// permissions are per user we have to kill the removed package
// or packages running under the shared user of the removed
// package if revoking the permissions requested only by the removed
// package is successful and this causes a change in gids.
+ boolean shouldKill = false;
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
userId);
- if (userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_SYSTEM) {
- // If gids changed for this user, kill all affected packages.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // This has to happen with no lock held.
- killApplication(deletedPs.name, deletedPs.appId,
- KILL_APP_REASON_GIDS_CHANGED);
- }
- });
- break;
- }
+ shouldKill |= userIdToKill == UserHandle.USER_ALL
+ || userIdToKill >= UserHandle.USER_SYSTEM;
+ }
+ // If gids changed, kill all affected packages.
+ if (shouldKill) {
+ mHandler.post(() -> {
+ // This has to happen with no lock held.
+ killApplication(deletedPs.name, deletedPs.appId,
+ KILL_APP_REASON_GIDS_CHANGED);
+ });
}
}
- clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
+ clearPackagePreferredActivitiesLPw(
+ deletedPs.name, changedUsers, UserHandle.USER_ALL);
}
- // make sure to preserve per-user disabled state if this removal was just
- // a downgrade of a system app to the factory package
- if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
+ if (changedUsers.size() > 0) {
+ updateDefaultHomeNotLocked(changedUsers);
+ postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
+ }
+ }
+ // make sure to preserve per-user disabled state if this removal was just
+ // a downgrade of a system app to the factory package
+ if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Propagating install state across downgrade");
+ }
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
if (DEBUG_REMOVE) {
- Slog.d(TAG, "Propagating install state across downgrade");
+ Slog.d(TAG, " user " + userId + " => " + installed);
}
- for (int userId : allUserHandles) {
- final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
- if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + userId + " => " + installed);
- }
- if (installed != ps.getInstalled(userId)) {
- installedStateChanged = true;
- }
- ps.setInstalled(installed, userId);
+ if (installed != deletedPs.getInstalled(userId)) {
+ installedStateChanged = true;
}
+ deletedPs.setInstalled(installed, userId);
}
}
+ }
+ synchronized (mPackages) {
// can downgrade to reader
if (writeSettings) {
// Save settings now
mSettings.writeLPr();
}
if (installedStateChanged) {
- mSettings.writeKernelMappingLPr(ps);
+ mSettings.writeKernelMappingLPr(deletedPs);
}
}
if (removedAppId != -1) {
}
}
- static boolean locationIsPrivileged(File path) {
+ static boolean locationIsPrivileged(String path) {
+ try {
+ final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
+ final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+ final File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app");
+ final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
+ final File privilegedProductServicesAppDir =
+ new File(Environment.getProductServicesDirectory(), "priv-app");
+ return path.startsWith(privilegedAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedVendorAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedOdmAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedProductAppDir.getCanonicalPath() + "/")
+ || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsOem(String path) {
+ try {
+ return path.startsWith(Environment.getOemDirectory().getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsVendor(String path) {
+ try {
+ return path.startsWith(Environment.getVendorDirectory().getCanonicalPath() + "/")
+ || path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsProduct(String path) {
+ try {
+ return path.startsWith(Environment.getProductDirectory().getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsProductServices(String path) {
+ try {
+ return path.startsWith(
+ Environment.getProductServicesDirectory().getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
+ static boolean locationIsOdm(String path) {
try {
- final String privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app")
- .getCanonicalPath();
- return path.getCanonicalPath().startsWith(privilegedAppDir);
+ return path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/");
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
/*
* Tries to delete system package.
*/
- private boolean deleteSystemPackageLIF(PackageParser.Package deletedPkg,
- PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
- boolean writeSettings) {
- if (deletedPs.parentPackageName != null) {
- Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
- return false;
- }
-
- final boolean applyUserRestrictions
- = (allUserHandles != null) && (outInfo.origUsers != null);
- final PackageSetting disabledPs;
+ private void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
+ int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
+ boolean writeSettings)
+ throws SystemDeleteException {
+ final boolean applyUserRestrictions =
+ (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
+ final PackageParser.Package deletedPkg = deletedPs.pkg;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
- synchronized (mPackages) {
- disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
- }
-
+ final PackageSetting disabledPs = action.disabledPs;
if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
+ " disabledPs=" + disabledPs);
-
- if (disabledPs == null) {
- Slog.w(TAG, "Attempt to delete unknown system package "+ deletedPkg.packageName);
- return false;
- } else if (DEBUG_REMOVE) {
- Slog.d(TAG, "Deleting system pkg from data partition");
- }
+ Slog.d(TAG, "Deleting system pkg from data partition");
if (DEBUG_REMOVE) {
if (applyUserRestrictions) {
}
}
- // Delete the updated package
- outInfo.isRemovedPackageSystemUpdate = true;
- if (outInfo.removedChildPackages != null) {
- final int childCount = (deletedPs.childPackageNames != null)
- ? deletedPs.childPackageNames.size() : 0;
- for (int i = 0; i < childCount; i++) {
- String childPackageName = deletedPs.childPackageNames.get(i);
- if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
- .contains(childPackageName)) {
- PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
- childPackageName);
- if (childInfo != null) {
- childInfo.isRemovedPackageSystemUpdate = true;
+ if (outInfo != null) {
+ // Delete the updated package
+ outInfo.isRemovedPackageSystemUpdate = true;
+ if (outInfo.removedChildPackages != null) {
+ final int childCount = (deletedPs.childPackageNames != null)
+ ? deletedPs.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = deletedPs.childPackageNames.get(i);
+ if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
+ .contains(childPackageName)) {
+ PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
+ childPackageName);
+ if (childInfo != null) {
+ childInfo.isRemovedPackageSystemUpdate = true;
+ }
}
}
}
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
+ deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
outInfo, writeSettings, disabledPs.pkg);
- if (!ret) {
- return false;
- }
// writer
synchronized (mPackages) {
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
- installPackageFromSystemLIF(disabledPs.codePath, false /*isPrivileged*/, allUserHandles,
- outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings);
+ installPackageFromSystemLIF(disabledPs.codePathString, allUserHandles,
+ outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
+ writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
+ e.getMessage());
- return false;
+ // TODO(patb): can we avoid this; throw would come from scan...
+ throw new SystemDeleteException(e);
} finally {
if (disabledPs.pkg.isStub) {
- mSettings.disableSystemPackageLPw(disabledPs.name, true /*replaced*/);
+ // We've re-installed the stub; make sure it's disabled here. If package was
+ // originally enabled, we'll install the compressed version of the application
+ // and re-enable it afterward.
+ final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(
+ COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
+ }
}
}
- return true;
}
/**
* Installs a package that's already on the system partition.
*/
- private PackageParser.Package installPackageFromSystemLIF(@NonNull File codePath,
- boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
+ private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
+ @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
@Nullable PermissionsState origPermissionState, boolean writeSettings)
throws PackageManagerException {
- int parseFlags = mDefParseFlags
+ @ParseFlags int parseFlags =
+ mDefParseFlags
| PackageParser.PARSE_MUST_BE_APK
- | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
- if (isPrivileged || locationIsPrivileged(codePath)) {
- parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
+ @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
+ if (locationIsPrivileged(codePathString)) {
+ scanFlags |= SCAN_AS_PRIVILEGED;
+ }
+ if (locationIsOem(codePathString)) {
+ scanFlags |= SCAN_AS_OEM;
+ }
+ if (locationIsVendor(codePathString)) {
+ scanFlags |= SCAN_AS_VENDOR;
+ }
+ if (locationIsProduct(codePathString)) {
+ scanFlags |= SCAN_AS_PRODUCT;
+ }
+ if (locationIsProductServices(codePathString)) {
+ scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+ }
+ if (locationIsOdm(codePathString)) {
+ scanFlags |= SCAN_AS_ODM;
}
- final PackageParser.Package newPkg =
- scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, 0 /*currentTime*/, null);
+ final File codePath = new File(codePathString);
+ final PackageParser.Package pkg =
+ scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
try {
// update shared libraries for the newly re-installed system package
- updateSharedLibrariesLPr(newPkg, null);
+ updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages));
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
- prepareAppDataAfterInstallLIF(newPkg);
+ prepareAppDataAfterInstallLIF(pkg);
// writer
synchronized (mPackages) {
- PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
+ PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
// Propagate the permissions state as we do not want to drop on the floor
// runtime permissions. The update permissions method below will take
if (origPermissionState != null) {
ps.getPermissionsState().copyFrom(origPermissionState);
}
- updatePermissionsLPw(newPkg.packageName, newPkg,
- UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
+ mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(),
+ mPermissionCallback);
final boolean applyUserRestrictions
= (allUserHandles != null) && (origUserHandles != null);
mSettings.writeLPr();
}
}
- return newPkg;
+ return pkg;
}
- private boolean deleteInstalledPackageLIF(PackageSetting ps,
+ private void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
for (int i = 0; i < childCount; i++) {
String childPackageName = ps.childPackageNames.get(i);
PackageSetting childPs = mSettings.mPackages.get(childPackageName);
- if (childPs == null) {
- return false;
- }
PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
childPackageName);
if (childInfo != null) {
// Delete application code and resources only for parent packages
if (ps.parentPackageName == null) {
if (deleteCodeAndResources && (outInfo != null)) {
- outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
+ outInfo.args = createInstallArgsForExisting(
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
}
-
- return true;
}
@Override
return true;
}
+ private static class DeletePackageAction {
+ public final PackageSetting deletingPs;
+ public final PackageSetting disabledPs;
+ public final PackageRemovedInfo outInfo;
+ public final int flags;
+ public final UserHandle user;
+
+ private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
+ PackageRemovedInfo outInfo, int flags, UserHandle user) {
+ this.deletingPs = deletingPs;
+ this.disabledPs = disabledPs;
+ this.outInfo = outInfo;
+ this.flags = flags;
+ this.user = user;
+ }
+ }
+
+ /**
+ * @return a {@link DeletePackageAction} if the provided package and related state may be
+ * deleted, {@code null} otherwise.
+ */
+ @Nullable
+ @GuardedBy("mPackages")
+ private static DeletePackageAction mayDeletePackageLocked(
+ PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
+ @Nullable PackageSetting[] children, int flags, UserHandle user) {
+ if (ps == null) {
+ return null;
+ }
+ if (isSystemApp(ps)) {
+ if (ps.parentPackageName != null) {
+ Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName);
+ return null;
+ }
+
+ final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0;
+ final boolean deleteAllUsers =
+ user == null || user.getIdentifier() == UserHandle.USER_ALL;
+ if ((!deleteSystem || deleteAllUsers) && disabledPs == null) {
+ Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName);
+ return null;
+ }
+ // Confirmed if the system package has been updated
+ // An updated system app can be deleted. This will also have to restore
+ // the system pkg from system partition reader
+ }
+ final int parentReferenceCount =
+ (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+ final int childCount = children != null ? children.length : 0;
+ if (childCount != parentReferenceCount) {
+ return null;
+ }
+ if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) {
+ for (PackageSetting child : children) {
+ if (child == null || !ps.childPackageNames.contains(child.name)) {
+ return null;
+ }
+ }
+ }
+ return new DeletePackageAction(ps, disabledPs, outInfo, flags, user);
+ }
+
/*
* This method handles package deletion in general
*/
- private boolean deletePackageLIF(String packageName, UserHandle user,
+ private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
- if (packageName == null) {
- Slog.w(TAG, "Attempt to delete null packageName.");
+ final DeletePackageAction action;
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
+ PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
+ action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user);
+ }
+ if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
+ if (null == action) {
+ if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: action was null");
return false;
}
- if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
- PackageSetting ps;
- synchronized (mPackages) {
- ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
- return false;
+ try {
+ executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
+ allUserHandles, writeSettings, replacingPackage);
+ } catch (SystemDeleteException e) {
+ if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e);
+ return false;
+ }
+ return true;
+ }
+
+ private static class SystemDeleteException extends Exception {
+ public final PackageManagerException reason;
+
+ private SystemDeleteException(PackageManagerException reason) {
+ this.reason = reason;
+ }
+ }
+
+ /** Deletes a package. Only throws when install of a disabled package fails. */
+ private void executeDeletePackageLIF(DeletePackageAction action,
+ String packageName, boolean deleteCodeAndResources,
+ int[] allUserHandles, boolean writeSettings,
+ PackageParser.Package replacingPackage) throws SystemDeleteException {
+ final PackageSetting ps = action.deletingPs;
+ final PackageRemovedInfo outInfo = action.outInfo;
+ final UserHandle user = action.user;
+ final int flags = action.flags;
+ final boolean systemApp = isSystemApp(ps);
+
+ if (ps.parentPackageName != null
+ && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
+ + ((user == null) ? UserHandle.USER_ALL : user));
}
+ final int removedUserId = (user != null) ? user.getIdentifier()
+ : UserHandle.USER_ALL;
- if (ps.parentPackageName != null && (!isSystemApp(ps)
- || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
- + ((user == null) ? UserHandle.USER_ALL : user));
- }
- final int removedUserId = (user != null) ? user.getIdentifier()
- : UserHandle.USER_ALL;
- if (!clearPackageStateForUserLIF(ps, removedUserId, outInfo)) {
- return false;
- }
+ clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags);
+ synchronized (mPackages) {
markPackageUninstalledForUserLPw(ps, user);
scheduleWritePackageRestrictionsLocked(user);
- return true;
}
+ return;
}
- if (((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
- && user.getIdentifier() != UserHandle.USER_ALL)) {
+ final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
+ if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) {
+ unsuspendForSuspendingPackage(packageName, userId);
+ }
+ if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
+ && userId != UserHandle.USER_ALL) {
// The caller is asking that the package only be deleted for a single
// user. To do this, we just mark its uninstalled state and delete
// its data. If this is a system app, we only allow this to happen if
// they have set the special DELETE_SYSTEM_APP which requests different
// semantics than normal for uninstalling system apps.
- markPackageUninstalledForUserLPw(ps, user);
-
- if (!isSystemApp(ps)) {
- // Do not uninstall the APK if an app should be cached
- boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);
- if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
- // Other user still have this package installed, so all
- // we need to do is clear this user's data and save that
- // it is uninstalled.
- if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
- if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {
- return false;
+ final boolean clearPackageStateAndReturn;
+ synchronized (mPackages) {
+ markPackageUninstalledForUserLPw(ps, user);
+ if (!systemApp) {
+ // Do not uninstall the APK if an app should be cached
+ boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);
+ if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {
+ // Other users still have this package installed, so all
+ // we need to do is clear this user's data and save that
+ // it is uninstalled.
+ if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
+ clearPackageStateAndReturn = true;
+ } else {
+ // We need to set it back to 'installed' so the uninstall
+ // broadcasts will be sent correctly.
+ if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
+ ps.setInstalled(true, userId);
+ mSettings.writeKernelMappingLPr(ps);
+ clearPackageStateAndReturn = false;
}
- scheduleWritePackageRestrictionsLocked(user);
- return true;
} else {
- // We need to set it back to 'installed' so the uninstall
- // broadcasts will be sent correctly.
- if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
- ps.setInstalled(true, user.getIdentifier());
- mSettings.writeKernelMappingLPr(ps);
+ // This is a system app, so we assume that the
+ // other users still have this package installed, so all
+ // we need to do is clear this user's data and save that
+ // it is uninstalled.
+ if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
+ clearPackageStateAndReturn = true;
}
- } else {
- // This is a system app, so we assume that the
- // other users still have this package installed, so all
- // we need to do is clear this user's data and save that
- // it is uninstalled.
- if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
- if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {
- return false;
+ }
+ if (clearPackageStateAndReturn) {
+ clearPackageStateForUserLIF(ps, userId, outInfo, flags);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(user);
}
- scheduleWritePackageRestrictionsLocked(user);
- return true;
+ return;
}
}
}
}
- boolean ret = false;
- if (isSystemApp(ps)) {
+ // TODO(b/109941548): break reasons for ret = false out into mayDelete method
+ if (systemApp) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources
// as well and fall back to existing code in system partition
- ret = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
+ deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
- ret = deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
+ deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
// If we uninstalled an update to a system app there may be some
// child packages that appeared as they are declared in the system
// app but were not declared in the update.
- if (isSystemApp(ps)) {
+ if (systemApp) {
synchronized (mPackages) {
PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
final int childCount = (updatedPs.childPackageNames != null)
}
}
}
-
- return ret;
}
+ @GuardedBy("mPackages")
private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
? sUserManager.getUserIds() : new int[] {user.getIdentifier()};
true /*stopped*/,
true /*notLaunched*/,
false /*hidden*/,
+ 0 /*distractionFlags*/,
false /*suspended*/,
+ null /*suspendingPackage*/,
+ null /*dialogInfo*/,
+ null /*suspendedAppExtras*/,
+ null /*suspendedLauncherExtras*/,
false /*instantApp*/,
false /*virtualPreload*/,
null /*lastDisableAppCaller*/,
null /*enabledComponents*/,
null /*disabledComponents*/,
ps.readUserState(nextUserId).domainVerificationStatus,
- 0, PackageManager.INSTALL_REASON_UNKNOWN);
+ 0, PackageManager.INSTALL_REASON_UNKNOWN,
+ null /*harmfulAppWarning*/);
}
mSettings.writeKernelMappingLPr(ps);
}
- private boolean clearPackageStateForUserLIF(PackageSetting ps, int userId,
- PackageRemovedInfo outInfo) {
+ private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
+ PackageRemovedInfo outInfo, int flags) {
final PackageParser.Package pkg;
synchronized (mPackages) {
pkg = mPackages.get(ps.name);
}
+ destroyAppProfilesLIF(pkg);
+
final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
: new int[] {userId};
for (int nextUserId : userIds) {
+ nextUserId);
}
- destroyAppDataLIF(pkg, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- destroyAppProfilesLIF(pkg, userId);
- clearDefaultBrowserIfNeededForUser(ps.name, userId);
+ destroyAppDataLIF(pkg, nextUserId,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
removeKeystoreDataIfNeeded(nextUserId, ps.appId);
- schedulePackageCleaning(ps.name, nextUserId, false);
- synchronized (mPackages) {
- if (clearPackagePreferredActivitiesLPw(ps.name, nextUserId)) {
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ clearPackagePreferredActivitiesLPw(ps.name, changedUsers, nextUserId);
+ if (changedUsers.size() > 0) {
+ updateDefaultHomeNotLocked(changedUsers);
+ postPreferredActivityChangedBroadcast(nextUserId);
+ synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(nextUserId);
}
+ }
+ synchronized (mPackages) {
resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, nextUserId);
}
+ // Also delete contributed media, when requested
+ if ((flags & PackageManager.DELETE_CONTRIBUTED_MEDIA) != 0) {
+ try {
+ MediaStore.deleteContributedMedia(mContext, ps.name, UserHandle.of(nextUserId));
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to delete contributed media for " + ps.name, e);
+ }
+ }
}
if (outInfo != null) {
outInfo.removedUsers = userIds;
outInfo.broadcastUsers = userIds;
}
-
- return true;
- }
-
- private final class ClearStorageConnection implements ServiceConnection {
- IMediaContainerService mContainerService;
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (this) {
- mContainerService = IMediaContainerService.Stub
- .asInterface(Binder.allowBlocking(service));
- notifyAll();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- }
-
- private void clearExternalStorageDataSync(String packageName, int userId, boolean allData) {
- if (DEFAULT_CONTAINER_PACKAGE.equals(packageName)) return;
-
- final boolean mounted;
- if (Environment.isExternalStorageEmulated()) {
- mounted = true;
- } else {
- final String status = Environment.getExternalStorageState();
-
- mounted = status.equals(Environment.MEDIA_MOUNTED)
- || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
- }
-
- if (!mounted) {
- return;
- }
-
- final Intent containerIntent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- int[] users;
- if (userId == UserHandle.USER_ALL) {
- users = sUserManager.getUserIds();
- } else {
- users = new int[] { userId };
- }
- final ClearStorageConnection conn = new ClearStorageConnection();
- if (mContext.bindServiceAsUser(
- containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
- try {
- for (int curUser : users) {
- long timeout = SystemClock.uptimeMillis() + 5000;
- synchronized (conn) {
- long now;
- while (conn.mContainerService == null &&
- (now = SystemClock.uptimeMillis()) < timeout) {
- try {
- conn.wait(timeout - now);
- } catch (InterruptedException e) {
- }
- }
- }
- if (conn.mContainerService == null) {
- return;
- }
-
- final UserEnvironment userEnv = new UserEnvironment(curUser);
- clearDirectory(conn.mContainerService,
- userEnv.buildExternalStorageAppCacheDirs(packageName));
- if (allData) {
- clearDirectory(conn.mContainerService,
- userEnv.buildExternalStorageAppDataDirs(packageName));
- clearDirectory(conn.mContainerService,
- userEnv.buildExternalStorageAppMediaDirs(packageName));
- }
- }
- } finally {
- mContext.unbindService(conn);
- }
- }
}
@Override
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
final PackageSetting ps = mSettings.getPackageLPr(packageName);
synchronized (mInstallLock) {
succeeded = clearApplicationUserDataLIF(packageName, userId);
}
- clearExternalStorageDataSync(packageName, userId, true);
synchronized (mPackages) {
mInstantAppRegistry.deleteInstantApplicationMetadataLPw(
packageName, userId);
if (dsm != null) {
dsm.checkMemory();
}
+ if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
+ unsuspendForSuspendingPackage(packageName, userId);
+ }
}
} else {
succeeded = false;
}
clearAppDataLIF(pkg, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
removeKeystoreDataIfNeeded(userId, appId);
*
* @param userId The device user for which to do a reset.
*/
+ @GuardedBy("mPackages")
private void resetUserChangesToRuntimePermissionsAndFlagsLPw(int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
* @param ps The package for which to reset.
* @param userId The device user for which to do a reset.
*/
+ @GuardedBy("mPackages")
private void resetUserChangesToRuntimePermissionsAndFlagsLPw(
final PackageSetting ps, final int userId) {
if (ps.pkg == null) {
return;
}
+ final String packageName = ps.pkg.packageName;
+
// These are flags that can change base on user actions.
final int userSettableMask = FLAG_PERMISSION_USER_SET
| FLAG_PERMISSION_USER_FIXED
final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED;
- boolean writeInstallPermissions = false;
- boolean writeRuntimePermissions = false;
+ // Delay and combine non-async permission callbacks
+ final boolean[] permissionRemoved = new boolean[1];
+ final ArraySet<Long> revokedPermissions = new ArraySet<>();
+ final SparseBooleanArray updatedUsers = new SparseBooleanArray();
+
+ PermissionCallback delayingPermCallback = new PermissionCallback() {
+ public void onGidsChanged(int appId, int userId) {
+ mPermissionCallback.onGidsChanged(appId, userId);
+ }
+
+ public void onPermissionChanged() {
+ mPermissionCallback.onPermissionChanged();
+ }
+
+ public void onPermissionGranted(int uid, int userId) {
+ mPermissionCallback.onPermissionGranted(uid, userId);
+ }
+
+ public void onInstallPermissionGranted() {
+ mPermissionCallback.onInstallPermissionGranted();
+ }
+
+ public void onPermissionRevoked(int uid, int userId) {
+ revokedPermissions.add(IntPair.of(uid, userId));
+
+ updatedUsers.put(userId, true);
+ }
+
+ public void onInstallPermissionRevoked() {
+ mPermissionCallback.onInstallPermissionRevoked();
+ }
+
+ public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+ for (int userId : updatedUserIds) {
+ if (sync) {
+ updatedUsers.put(userId, true);
+ } else {
+ // Don't override sync=true by sync=false
+ if (!updatedUsers.get(userId)) {
+ updatedUsers.put(userId, false);
+ }
+ }
+ }
+ }
+
+ public void onPermissionRemoved() {
+ permissionRemoved[0] = true;
+ }
+
+ public void onInstallPermissionUpdated() {
+ mPermissionCallback.onInstallPermissionUpdated();
+ }
+ };
+
+ final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ final int uid = UserHandle.getUid(userId, ps.pkg.applicationInfo.uid);
final int permissionCount = ps.pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
- String permission = ps.pkg.requestedPermissions.get(i);
-
- BasePermission bp = mSettings.mPermissions.get(permission);
+ final String permName = ps.pkg.requestedPermissions.get(i);
+ final BasePermission bp =
+ (BasePermission) mPermissionManager.getPermissionTEMP(permName);
if (bp == null) {
continue;
}
+ if (bp.isRemoved()) {
+ continue;
+ }
+
// If shared user we just reset the state to which only this app contributed.
if (ps.sharedUser != null) {
boolean used = false;
for (int j = 0; j < packageCount; j++) {
PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
- && pkg.pkg.requestedPermissions.contains(permission)) {
+ && pkg.pkg.requestedPermissions.contains(permName)) {
used = true;
break;
}
}
}
- PermissionsState permissionsState = ps.getPermissionsState();
-
- final int oldFlags = permissionsState.getPermissionFlags(bp.name, userId);
+ final int oldFlags = mPermissionManager.getPermissionFlags(permName, packageName,
+ Process.SYSTEM_UID, userId);
// Always clear the user settable flags.
- final boolean hasInstallState = permissionsState.getInstallPermissionState(
- bp.name) != null;
// If permission review is enabled and this is a legacy app, mark the
// permission as requiring a review as this is the initial state.
int flags = 0;
- if (mPermissionReviewRequired
- && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
- }
- if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
- if (hasInstallState) {
- writeInstallPermissions = true;
- } else {
- writeRuntimePermissions = true;
- }
+ if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
+ mPermissionManager.updatePermissionFlags(permName, packageName,
+ userSettableMask, flags, Process.SYSTEM_UID, userId, false,
+ delayingPermCallback);
+
// Below is only runtime permission handling.
if (!bp.isRuntime()) {
continue;
// If this permission was granted by default, make sure it is.
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
- if (permissionsState.grantRuntimePermission(bp, userId)
- != PERMISSION_OPERATION_FAILURE) {
- writeRuntimePermissions = true;
+ mPermissionManager.grantRuntimePermission(permName, packageName, false,
+ Process.SYSTEM_UID, userId, delayingPermCallback);
+ // Allow app op later as we are holding mPackages
+ // PermissionPolicyService will handle the app op for foreground/background
+ // permissions.
+ String appOp = AppOpsManager.permissionToOp(permName);
+ if (appOp != null) {
+ mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
+ AppOpsManager.MODE_ALLOWED));
}
// If permission review is enabled the permissions for a legacy apps
// are represented as constantly granted runtime ones, so don't revoke.
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
// Otherwise, reset the permission.
- final int revokeResult = permissionsState.revokeRuntimePermission(bp, userId);
- switch (revokeResult) {
- case PERMISSION_OPERATION_SUCCESS:
- case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
- writeRuntimePermissions = true;
- final int appId = ps.appId;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
- }
- });
- } break;
- }
+ mPermissionManager.revokeRuntimePermission(permName, packageName, false, userId,
+ delayingPermCallback);
}
}
- // Synchronously write as we are taking permissions away.
- if (writeRuntimePermissions) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+ // Execute delayed callbacks
+ if (permissionRemoved[0]) {
+ mPermissionCallback.onPermissionRemoved();
}
- // Synchronously write as we are taking permissions away.
- if (writeInstallPermissions) {
- mSettings.writeLPr();
+ // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
+ // kill uid while holding mPackages-lock
+ if (!revokedPermissions.isEmpty()) {
+ int numRevokedPermissions = revokedPermissions.size();
+ for (int i = 0; i < numRevokedPermissions; i++) {
+ int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
+ int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
+
+ mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
+
+ // Kill app later as we are holding mPackages
+ mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
+ KILL_APP_REASON_PERMISSIONS_REVOKED));
+ }
+ }
+
+ int numUpdatedUsers = updatedUsers.size();
+ for (int i = 0; i < numUpdatedUsers; i++) {
+ mSettings.writeRuntimePermissionsForUserLPr(updatedUsers.keyAt(i),
+ updatedUsers.valueAt(i));
}
}
public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
final IPackageDataObserver observer) {
final int callingUid = Binder.getCallingUid();
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.DELETE_CACHE_FILES, null);
- enforceCrossUserPermission(callingUid, userId,
+ 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);
+ }
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
/* requireFullPermission= */ true, /* checkShell= */ false,
"delete application cache files");
final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
}
// Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
- 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 = StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE;
- // We're only clearing cache files, so we don't care if the
- // app is unfrozen and still able to run
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- }
- clearExternalStorageDataSync(packageName, userId, false);
+ mHandler.post(() -> {
+ final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
+ boolean doClearData = true;
+ if (ps != null) {
+ final boolean targetIsInstantApp =
+ ps.getInstantApp(UserHandle.getUserId(callingUid));
+ doClearData = !targetIsInstantApp
+ || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED;
+ }
+ if (doClearData) {
+ synchronized (mInstallLock) {
+ final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
+ // We're only clearing cache files, so we don't care if the
+ // app is unfrozen and still able to run
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
- if (observer != null) {
- try {
- observer.onRemoveCompleted(packageName, true);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
+ }
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(packageName, true);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
}
}
});
"Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
}
+ @GuardedBy("mInstallLock")
private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
final PackageSetting ps;
synchronized (mPackages) {
return true;
}
+ @GuardedBy("mPackages")
private int getUidTargetSdkVersionLockedLPr(int uid) {
- Object obj = mSettings.getUserIdLPr(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;
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ @GuardedBy("mPackages")
+ private int getPackageTargetSdkVersionLockedLPr(String packageName) {
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ return p.applicationInfo.targetSdkVersion;
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
@Override
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
String opname) {
// writer
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "add preferred activity");
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (getUidTargetSdkVersionLockedLPr(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ }
if (filter.countActions() == 0) {
Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
return;
}
- synchronized (mPackages) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
- != PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLPr(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
- }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
- }
-
- PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
+ if (DEBUG_PREFERRED) {
Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user "
+ userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
+ synchronized (mPackages) {
+ final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
+ }
+ if (!updateDefaultHomeNotLocked(userId)) {
postPreferredActivityChangedBroadcast(userId);
}
}
final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntent(null, intent, null, null,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
}
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"replace preferred activity");
- synchronized (mPackages) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
- != PackageManager.PERMISSION_GRANTED) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ synchronized (mPackages) {
if (getUidTargetSdkVersionLockedLPr(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ Binder.getCallingUid());
return;
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ }
- PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ synchronized (mPackages) {
+ final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
if (pir != null) {
// Get all of the existing entries that exactly match this filter.
- ArrayList<PreferredActivity> existing = pir.findFilters(filter);
+ final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
if (existing != null && existing.size() == 1) {
- PreferredActivity cur = existing.get(0);
+ final PreferredActivity cur = existing.get(0);
if (DEBUG_PREFERRED) {
Slog.i(TAG, "Checking replace of preferred:");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
return;
}
}
-
if (existing != null) {
if (DEBUG_PREFERRED) {
Slog.i(TAG, existing.size() + " existing preferred matches for:");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- for (int i = 0; i < existing.size(); i++) {
- PreferredActivity pa = existing.get(i);
+ for (int i = existing.size() - 1; i >= 0; --i) {
+ final PreferredActivity pa = existing.get(i);
if (DEBUG_PREFERRED) {
Slog.i(TAG, "Removing existing preferred activity "
+ pa.mPref.mComponent + ":");
}
}
}
- addPreferredActivityInternal(filter, match, set, activity, true, userId,
- "Replacing preferred");
}
+ addPreferredActivityInternal(filter, match, set, activity, true, userId,
+ "Replacing preferred");
}
@Override
// writer
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null || pkg.applicationInfo.uid != callingUid) {
+ if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
&& filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
return;
}
- int user = UserHandle.getCallingUserId();
- if (clearPackagePreferredActivitiesLPw(packageName, user)) {
- scheduleWritePackageRestrictionsLocked(user);
+ }
+ int callingUserId = UserHandle.getCallingUserId();
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ clearPackagePreferredActivitiesLPw(packageName, changedUsers, callingUserId);
+ if (changedUsers.size() > 0) {
+ updateDefaultHomeNotLocked(changedUsers);
+ postPreferredActivityChangedBroadcast(callingUserId);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(callingUserId);
}
}
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
- boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
+ @GuardedBy("mPackages")
+ private void clearPackagePreferredActivitiesLPw(String packageName,
+ @NonNull SparseBooleanArray outUserChanged, int userId) {
ArrayList<PreferredActivity> removed = null;
- boolean changed = false;
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
(pa.mPref.mComponent.getPackageName().equals(packageName)
&& pa.mPref.mAlways)) {
if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ removed = new ArrayList<>();
}
removed.add(pa);
}
PreferredActivity pa = removed.get(j);
pir.removeFilter(pa);
}
- changed = true;
+ outUserChanged.put(thisUserId, true);
}
}
- if (changed) {
- postPreferredActivityChangedBroadcast(userId);
- }
- return changed;
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ @GuardedBy("mPackages")
private void clearIntentFilterVerificationsLPw(int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ @GuardedBy("mPackages")
void clearIntentFilterVerificationsLPw(String packageName, int userId) {
if (userId == UserHandle.USER_ALL) {
if (mSettings.removeIntentFilterVerificationLPw(packageName,
final long identity = Binder.clearCallingIdentity();
// writer
try {
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
+ clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ if (changedUsers.size() > 0) {
+ postPreferredActivityChangedBroadcast(userId);
+ }
synchronized (mPackages) {
- clearPackagePreferredActivitiesLPw(null, userId);
- mSettings.applyDefaultPreferredAppsLPw(this, userId);
- // TODO: We have to reset the default SMS and Phone. This requires
- // significant refactoring to keep all default apps in the package
- // manager (cleaner but more work) or have the services provide
- // callbacks to the package manager to request a default app reset.
- applyFactoryDefaultBrowserLPw(userId);
+ mSettings.applyDefaultPreferredAppsLPw(userId);
clearIntentFilterVerificationsLPw(userId);
primeDomainVerificationsLPw(userId);
resetUserChangesToRuntimePermissionsAndFlagsLPw(userId);
- scheduleWritePackageRestrictionsLocked(userId);
}
+ updateDefaultHomeNotLocked(userId);
+ // TODO: We have to reset the default SMS and Phone. This requires
+ // significant refactoring to keep all default apps in the package
+ // manager (cleaner but more work) or have the services provide
+ // callbacks to the package manager to request a default app reset.
+ setDefaultBrowserPackageName(null, userId);
resetNetworkPolicies(userId);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
return;
}
- synchronized (mPackages) {
- Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
- ":");
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Adding persistent preferred activity " + activity
+ + " for user " + userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
+ synchronized (mPackages) {
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
scheduleWritePackageRestrictionsLocked(userId);
- postPreferredActivityChangedBroadcast(userId);
}
+ updateDefaultHomeNotLocked(userId);
+ postPreferredActivityChangedBroadcast(userId);
}
@Override
// Mark entry for removal only if it matches the package name.
if (ppa.mComponent.getPackageName().equals(packageName)) {
if (removed == null) {
- removed = new ArrayList<PersistentPreferredActivity>();
+ removed = new ArrayList<>();
}
removed.add(ppa);
}
changed = true;
}
}
-
- if (changed) {
+ }
+ if (changed) {
+ updateDefaultHomeNotLocked(userId);
+ postPreferredActivityChangedBroadcast(userId);
+ synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(userId);
- postPreferredActivityChangedBroadcast(userId);
}
}
}
}
return;
}
-Slog.v(TAG, ":: restoreFromXml() : got to tag " + parser.getName());
// this is supposed to be TAG_PREFERRED_BACKUP
if (!expectedStartTag.equals(parser.getName())) {
if (DEBUG_BACKUP) {
// skip interfering stuff, then we're aligned with the backing implementation
while ((type = parser.next()) == XmlPullParser.TEXT) { }
-Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
functor.apply(parser, userId);
}
private interface BlobXmlRestorer {
- public void apply(XmlPullParser parser, int userId) throws IOException, XmlPullParserException;
+ void apply(XmlPullParser parser, int userId) throws IOException, XmlPullParserException;
}
/**
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_PREFERRED_BACKUP,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- mSettings.readPreferredActivitiesLPw(parser, userId);
- }
- }
- } );
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
- }
- }
- }
-
- /**
- * Non-Binder method, support for the backup/restore mechanism: write the
- * default browser (etc) settings in its canonical XML format. Returns the default
- * browser XML representation as a byte array, or null if there is none.
- */
- @Override
- public byte[] getDefaultAppsBackup(int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getDefaultAppsBackup()");
- }
-
- ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
- try {
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.startTag(null, TAG_DEFAULT_APPS);
-
- synchronized (mPackages) {
- mSettings.writeDefaultAppsLPr(serializer, userId);
- }
-
- serializer.endTag(null, TAG_DEFAULT_APPS);
- serializer.endDocument();
- serializer.flush();
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Unable to write default apps for backup", e);
- }
- return null;
- }
-
- return dataStream.toByteArray();
- }
-
- @Override
- public void restoreDefaultApps(byte[] backup, int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restoreDefaultApps()");
- }
-
- try {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
- restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- mSettings.readDefaultAppsLPw(parser, userId);
- }
+ (readParser, readUserId) -> {
+ synchronized (mPackages) {
+ mSettings.readPreferredActivitiesLPw(readParser, readUserId);
}
- } );
+ updateDefaultHomeNotLocked(readUserId);
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring default apps: " + e.getMessage());
+ Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
}
}
}
+ /**
+ * Non-Binder method, support for the backup/restore mechanism: write the
+ * default browser (etc) settings in its canonical XML format. Returns the default
+ * browser XML representation as a byte array, or null if there is none.
+ */
@Override
- public byte[] getIntentFilterVerificationBackup(int userId) {
+ public byte[] getDefaultAppsBackup(int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getIntentFilterVerificationBackup()");
+ throw new SecurityException("Only the system may call getDefaultAppsBackup()");
}
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
final XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
- serializer.startTag(null, TAG_INTENT_FILTER_VERIFICATION);
+ serializer.startTag(null, TAG_DEFAULT_APPS);
synchronized (mPackages) {
- mSettings.writeAllDomainVerificationsLPr(serializer, userId);
+ mSettings.writeDefaultAppsLPr(serializer, userId);
}
- serializer.endTag(null, TAG_INTENT_FILTER_VERIFICATION);
+ serializer.endTag(null, TAG_DEFAULT_APPS);
serializer.endDocument();
serializer.flush();
} catch (Exception e) {
}
@Override
- public void restoreIntentFilterVerification(byte[] backup, int userId) {
+ public void restoreDefaultApps(byte[] backup, int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restorePreferredActivities()");
+ throw new SecurityException("Only the system may call restoreDefaultApps()");
}
try {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
- restoreFromXml(parser, userId, TAG_INTENT_FILTER_VERIFICATION,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
+ restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
+ (parser1, userId1) -> {
+ String defaultBrowser;
+ synchronized (mPackages) {
+ mSettings.readDefaultAppsLPw(parser1, userId1);
+ defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
+ }
+ if (defaultBrowser != null) {
+ PackageManagerInternal.DefaultBrowserProvider provider;
synchronized (mPackages) {
- mSettings.readAllDomainVerificationsLPr(parser, userId);
- mSettings.writeLPr();
+ provider = mDefaultBrowserProvider;
}
+ provider.setDefaultBrowser(defaultBrowser, userId1);
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
+ Slog.e(TAG, "Exception restoring default apps: " + e.getMessage());
}
}
}
@Override
- public byte[] getPermissionGrantBackup(int userId) {
+ public byte[] getIntentFilterVerificationBackup(int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getPermissionGrantBackup()");
+ throw new SecurityException("Only the system may call getIntentFilterVerificationBackup()");
}
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
final XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
- serializer.startTag(null, TAG_PERMISSION_BACKUP);
+ serializer.startTag(null, TAG_INTENT_FILTER_VERIFICATION);
synchronized (mPackages) {
- serializeRuntimePermissionGrantsLPr(serializer, userId);
+ mSettings.writeAllDomainVerificationsLPr(serializer, userId);
}
- serializer.endTag(null, TAG_PERMISSION_BACKUP);
+ serializer.endTag(null, TAG_INTENT_FILTER_VERIFICATION);
serializer.endDocument();
serializer.flush();
} catch (Exception e) {
}
@Override
- public void restorePermissionGrants(byte[] backup, int userId) {
+ public void restoreIntentFilterVerification(byte[] backup, int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restorePermissionGrants()");
+ throw new SecurityException("Only the system may call restorePreferredActivities()");
}
try {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
- restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
- new BlobXmlRestorer() {
- @Override
- public void apply(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- synchronized (mPackages) {
- processRestoredPermissionGrantsLPr(parser, userId);
- }
+ restoreFromXml(parser, userId, TAG_INTENT_FILTER_VERIFICATION,
+ (parser1, userId1) -> {
+ synchronized (mPackages) {
+ mSettings.readAllDomainVerificationsLPr(parser1, userId1);
+ mSettings.writeLPr();
}
- } );
+ });
} catch (Exception e) {
if (DEBUG_BACKUP) {
Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
}
}
- private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId)
- throws IOException {
- serializer.startTag(null, TAG_ALL_GRANTS);
-
- final int N = mSettings.mPackages.size();
- for (int i = 0; i < N; i++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(i);
- boolean pkgGrantsKnown = false;
-
- PermissionsState packagePerms = ps.getPermissionsState();
-
- for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) {
- final int grantFlags = state.getFlags();
- // only look at grants that are not system/policy fixed
- if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) {
- final boolean isGranted = state.isGranted();
- // And only back up the user-twiddled state bits
- if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) {
- final String packageName = mSettings.mPackages.keyAt(i);
- if (!pkgGrantsKnown) {
- serializer.startTag(null, TAG_GRANT);
- serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
- pkgGrantsKnown = true;
- }
-
- final boolean userSet =
- (grantFlags & FLAG_PERMISSION_USER_SET) != 0;
- final boolean userFixed =
- (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0;
- final boolean revoke =
- (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
-
- serializer.startTag(null, TAG_PERMISSION);
- serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName());
- if (isGranted) {
- serializer.attribute(null, ATTR_IS_GRANTED, "true");
- }
- if (userSet) {
- serializer.attribute(null, ATTR_USER_SET, "true");
- }
- if (userFixed) {
- serializer.attribute(null, ATTR_USER_FIXED, "true");
- }
- if (revoke) {
- serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
- }
- serializer.endTag(null, TAG_PERMISSION);
- }
- }
- }
-
- if (pkgGrantsKnown) {
- serializer.endTag(null, TAG_GRANT);
- }
- }
-
- serializer.endTag(null, TAG_ALL_GRANTS);
- }
-
- private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- String pkgName = null;
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- final String tagName = parser.getName();
- if (tagName.equals(TAG_GRANT)) {
- pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- if (DEBUG_BACKUP) {
- Slog.v(TAG, "+++ Restoring grants for package " + pkgName);
- }
- } else if (tagName.equals(TAG_PERMISSION)) {
-
- final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED));
- final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
-
- int newFlagSet = 0;
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
- newFlagSet |= FLAG_PERMISSION_USER_SET;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
- newFlagSet |= FLAG_PERMISSION_USER_FIXED;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
- newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- }
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " + Restoring grant: pkg=" + pkgName + " perm=" + permName
- + " granted=" + isGranted + " bits=0x" + Integer.toHexString(newFlagSet));
- }
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- // Already installed so we apply the grant immediately
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " + already installed; applying");
- }
- PermissionsState perms = ps.getPermissionsState();
- BasePermission bp = mSettings.mPermissions.get(permName);
- if (bp != null) {
- if (isGranted) {
- perms.grantRuntimePermission(bp, userId);
- }
- if (newFlagSet != 0) {
- perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
- }
- }
- } else {
- // Need to wait for post-restore install to apply the grant
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " - not yet installed; saving for later");
- }
- mSettings.processRestoredPermissionGrantLPr(pkgName, permName,
- isGranted, newFlagSet, userId);
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName);
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- scheduleWriteSettingsLocked();
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
- }
-
@Override
public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
int sourceUserId, int targetUserId, int flags) {
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
int callingUid = Binder.getCallingUid();
enforceOwnerRights(ownerPackage, callingUid);
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+ PackageManagerServiceUtils.enforceShellRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
if (intentFilter.countActions() == 0) {
Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
return;
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
final int callingUid = Binder.getCallingUid();
enforceOwnerRights(ownerPackage, callingUid);
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+ PackageManagerServiceUtils.enforceShellRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
synchronized (mPackages) {
CrossProfileIntentResolver resolver =
mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
ArraySet<CrossProfileIntentFilter> set =
- new ArraySet<CrossProfileIntentFilter>(resolver.filterSet());
+ new ArraySet<>(resolver.filterSet());
for (CrossProfileIntentFilter filter : set) {
if (filter.getOwnerPackage().equals(ownerPackage)) {
resolver.removeFilter(filter);
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Send a {@code PackageInstaller.ACTION_SESSION_UPDATED} broadcast intent, containing
+ * the {@code sessionInfo} in the extra field {@code PackageInstaller.EXTRA_SESSION}.
+ */
+ public void sendSessionUpdatedBroadcast(PackageInstaller.SessionInfo sessionInfo,
+ int userId) {
+ if (TextUtils.isEmpty(sessionInfo.installerPackageName)) {
+ return;
+ }
+ Intent sessionUpdatedIntent = new Intent(PackageInstaller.ACTION_SESSION_UPDATED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+ .setPackage(sessionInfo.installerPackageName);
+ mContext.sendBroadcastAsUser(sessionUpdatedIntent, UserHandle.of(userId));
+ }
+
public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
UserManagerService ums = UserManagerService.getInstance();
- if (ums != null) {
+ if (ums != null && !sessionInfo.isStaged()) {
final UserInfo parent = ums.getProfileParent(userId);
final int launcherUid = (parent != null) ? parent.id : userId;
final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
.setPackage(launcherComponent.getPackageName());
mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
}
+ // TODO(b/122900055) Change/Remove this and replace with new permission role.
+ if (mAppPredictionServicePackage != null) {
+ Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(mAppPredictionServicePackage);
+ mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid));
+ }
}
}
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
Intent intent = getHomeIntent();
- List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
+ List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, userId);
- ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
- true, false, false, userId);
-
allHomeCandidates.clear();
- if (list != null) {
- for (ResolveInfo ri : list) {
- allHomeCandidates.add(ri);
+ if (resolveInfos == null) {
+ return null;
+ }
+ allHomeCandidates.addAll(resolveInfos);
+
+ PackageManagerInternal.DefaultHomeProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultHomeProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultHomeProvider is null");
+ return null;
+ }
+ String packageName = provider.getDefaultHome(userId);
+ if (packageName == null) {
+ return null;
+ }
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+
+ if (resolveInfo.activityInfo != null && TextUtils.equals(
+ resolveInfo.activityInfo.packageName, packageName)) {
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
}
}
- return (preferred == null || preferred.activityInfo == null)
- ? null
- : new ComponentName(preferred.activityInfo.packageName,
- preferred.activityInfo.name);
+ return null;
+ }
+
+ /** <b>must not hold {@link #mPackages}</b> */
+ private void updateDefaultHomeNotLocked(SparseBooleanArray userIds) {
+ if (Thread.holdsLock(mPackages)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ + " is holding mPackages", new Throwable());
+ }
+ for (int i = userIds.size() - 1; i >= 0; --i) {
+ final int userId = userIds.keyAt(i);
+ updateDefaultHomeNotLocked(userId);
+ }
+ }
+
+ /**
+ * <b>must not hold {@link #mPackages}</b>
+ *
+ * @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
+ */
+ private boolean updateDefaultHomeNotLocked(int userId) {
+ if (Thread.holdsLock(mPackages)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ + " is holding mPackages", new Throwable());
+ }
+ if (!mSystemReady) {
+ // We might get called before system is ready because of package changes etc, but
+ // finding preferred activity depends on settings provider, so we ignore the update
+ // before that.
+ return false;
+ }
+ final Intent intent = getHomeIntent();
+ final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
+ PackageManager.GET_META_DATA, userId);
+ final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
+ intent, null, 0, resolveInfos, 0, true, false, false, userId);
+ final String packageName = preferredResolveInfo != null
+ && preferredResolveInfo.activityInfo != null
+ ? preferredResolveInfo.activityInfo.packageName : null;
+ final PackageManagerInternal.DefaultHomeProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultHomeProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "Default home provider has not been set");
+ return false;
+ }
+ final String currentPackageName = provider.getDefaultHome(userId);
+ if (TextUtils.equals(currentPackageName, packageName)) {
+ return false;
+ }
+ final String[] callingPackages = getPackagesForUid(Binder.getCallingUid());
+ if (callingPackages != null && ArrayUtils.contains(callingPackages,
+ mRequiredPermissionControllerPackage)) {
+ // PermissionController manages default home directly.
+ return false;
+ }
+ provider.setDefaultHomeAsync(packageName, userId, (successful) -> {
+ if (successful) {
+ postPreferredActivityChangedBroadcast(userId);
+ }
+ });
+ return true;
}
@Override
}
@Override
+ public String getSystemTextClassifierPackageName() {
+ return mContext.getString(R.string.config_defaultTextClassifierPackage);
+ }
+
+ @Override
+ public @Nullable String getAttentionServicePackageName() {
+ final String flattenedComponentName =
+ mContext.getString(R.string.config_defaultAttentionService);
+ if (flattenedComponentName != null) {
+ ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName);
+ if (componentName != null && componentName.getPackageName() != null) {
+ return componentName.getPackageName();
+ }
+ }
+ return null;
+ }
+
+ private @Nullable String getDocumenterPackageName() {
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, resolvedType,
+ MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+ | MATCH_DISABLED_COMPONENTS,
+ UserHandle.myUserId());
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ Slog.e(TAG, "There should probably be exactly one documenter; found "
+ + matches.size() + ": matches=" + matches);
+ return null;
+ }
+ }
+
+ @Override
+ public String getWellbeingPackageName() {
+ return mContext.getString(R.string.config_defaultWellbeingPackage);
+ }
+
+ @Override
+ public String getAppPredictionServicePackageName() {
+ String flattenedAppPredictionServiceComponentName =
+ mContext.getString(R.string.config_defaultAppPredictionService);
+ if (flattenedAppPredictionServiceComponentName == null) {
+ return null;
+ }
+ ComponentName appPredictionServiceComponentName =
+ ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
+ if (appPredictionServiceComponentName == null) {
+ return null;
+ }
+ return appPredictionServiceComponentName.getPackageName();
+ }
+
+ @Override
+ public String getSystemCaptionsServicePackageName() {
+ String flattenedSystemCaptionsServiceComponentName =
+ mContext.getString(R.string.config_defaultSystemCaptionsService);
+
+ if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
+ return null;
+ }
+
+ ComponentName systemCaptionsServiceComponentName =
+ ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
+ if (systemCaptionsServiceComponentName == null) {
+ return null;
+ }
+ return systemCaptionsServiceComponentName.getPackageName();
+ }
+
+ public String getIncidentReportApproverPackageName() {
+ return mContext.getString(R.string.config_incidentReportApproverPackage);
+ }
+
+ @Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!sUserManager.exists(userId)) return;
permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
}
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, true /* checkShell */, "set enabled");
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);
final boolean isCallerInstantApp = (getInstantAppPackageName(callingUid) != null);
String componentName = isApp ? packageName : className;
- int packageUid = -1;
ArrayList<String> components;
// reader
throw new SecurityException("Cannot disable a protected package: " + packageName);
}
}
+ // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
+ // app details activity
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)
+ && !allowedByPermission) {
+ throw new SecurityException("Cannot disable a system-generated component");
+ }
synchronized (mPackages) {
if (callingUid == Process.SHELL_UID
// data partition and then replace the version on the system partition.
final PackageParser.Package deletedPkg = pkgSetting.pkg;
final boolean isSystemStub = deletedPkg.isStub
- && deletedPkg.isSystemApp();
+ && deletedPkg.isSystem();
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
- final File codePath = decompressPackage(deletedPkg);
- if (codePath == null) {
- Slog.e(TAG, "couldn't decompress pkg: " + pkgSetting.name);
- return;
- }
- // TODO remove direct parsing of the package object during internal cleanup
- // of scan package
- // We need to call parse directly here for no other reason than we need
- // the new package in order to disable the old one [we use the information
- // for some internal optimization to optionally create a new package setting
- // object on replace]. However, we can't get the package from the scan
- // because the scan modifies live structures and we need to remove the
- // old [system] package from the system before a scan can be attempted.
- // Once scan is indempotent we can remove this parse and use the package
- // object we scanned, prior to adding it to package settings.
- final PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
- pp.setCallback(mPackageParserCallback);
- final PackageParser.Package tmpPkg;
- try {
- final int parseFlags = mDefParseFlags
- | PackageParser.PARSE_MUST_BE_APK
- | PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR;
- tmpPkg = pp.parsePackage(codePath, parseFlags);
- } catch (PackageParserException e) {
- Slog.w(TAG, "Failed to parse compressed system package:" + pkgSetting.name, e);
+ if (!enableCompressedPackage(deletedPkg)) {
return;
}
- synchronized (mInstallLock) {
- // Disable the stub and remove any package entries
- removePackageLI(deletedPkg, true);
- synchronized (mPackages) {
- disableSystemPackageLPw(deletedPkg, tmpPkg);
- }
- final PackageParser.Package newPkg;
- try (PackageFreezer freezer =
- freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
- | PackageParser.PARSE_ENFORCE_CODE;
- newPkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/,
- 0 /*currentTime*/, null /*user*/);
- prepareAppDataAfterInstallLIF(newPkg);
- synchronized (mPackages) {
- try {
- updateSharedLibrariesLPr(newPkg, null);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
- }
- updatePermissionsLPw(newPkg.packageName, newPkg,
- UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
- mSettings.writeLPr();
- }
- } catch (PackageManagerException e) {
- // Whoops! Something went wrong; try to roll back to the stub
- Slog.w(TAG, "Failed to install compressed system package:"
- + pkgSetting.name, e);
- // Remove the failed install
- removeCodePathLI(codePath);
-
- // Install the system package
- try (PackageFreezer freezer =
- freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
- synchronized (mPackages) {
- // NOTE: The system package always needs to be enabled; even
- // if it's for a compressed stub. If we don't, installing the
- // system package fails during scan [scanning checks the disabled
- // packages]. We will reverse this later, after we've "installed"
- // the stub.
- // This leaves us in a fragile state; the stub should never be
- // enabled, so, cross your fingers and hope nothing goes wrong
- // until we can disable the package later.
- enableSystemPackageLPw(deletedPkg);
- }
- installPackageFromSystemLIF(new File(deletedPkg.codePath),
- false /*isPrivileged*/, null /*allUserHandles*/,
- null /*origUserHandles*/, null /*origPermissionsState*/,
- true /*writeSettings*/);
- } catch (PackageManagerException pme) {
- Slog.w(TAG, "Failed to restore system package:"
- + deletedPkg.packageName, pme);
- } finally {
- synchronized (mPackages) {
- mSettings.disableSystemPackageLPw(
- deletedPkg.packageName, true /*replaced*/);
- mSettings.writeLPr();
- }
- }
- return;
- }
- clearAppDataLIF(newPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
- | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(newPkg, UserHandle.USER_ALL);
- mDexManager.notifyPackageUpdated(newPkg.packageName,
- newPkg.baseCodePath, newPkg.splitCodePaths);
- }
}
if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
components = mPendingBroadcasts.get(userId, packageName);
final boolean newPackage = components == null;
if (newPackage) {
- components = new ArrayList<String>();
+ components = new ArrayList<>();
}
if (!components.contains(componentName)) {
components.add(componentName);
mPendingBroadcasts.put(userId, packageName, components);
}
if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
- // Schedule a message
- mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
+ // 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);
}
}
}
long callingId = Binder.clearCallingIdentity();
try {
if (sendNow) {
- packageUid = UserHandle.getUid(userId, pkgSetting.appId);
+ int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
sendPackageChangedBroadcast(packageName,
(flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);
}
if (!sUserManager.exists(userId)) {
return;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
false /* checkShell */, "flushPackageRestrictions");
synchronized (mPackages) {
mSettings.writePackageRestrictionsLPr(userId);
// little component state change.
final int flags = !componentNames.contains(packageName)
? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0;
+ final int userId = UserHandle.getUserId(packageUid);
+ final boolean isInstantApp = isInstantApp(packageName, userId);
+ final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
+ final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
- new int[] {UserHandle.getUserId(packageUid)});
+ userIds, instantUserIds);
}
@Override
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "stop package");
// writer
synchronized (mPackages) {
@Override
public String getInstallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
return null;
}
+ // InstallerPackageName for Apex is not stored in PackageManager
+ if (ps == null && mApexManager.isApexPackage(packageName)) {
+ return null;
+ }
return mSettings.getInstallerPackageNameLPr(packageName);
}
}
public boolean isOrphaned(String packageName) {
// reader
synchronized (mPackages) {
+ if (!mPackages.containsKey(packageName)) {
+ return false;
+ }
return mSettings.isOrphaned(packageName);
}
}
public int getApplicationEnabledSetting(String packageName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get enabled");
// reader
synchronized (mPackages) {
}
@Override
- public int getComponentEnabledSetting(ComponentName component, int userId) {
+ public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
+ if (component == null) return COMPONENT_ENABLED_STATE_DEFAULT;
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
synchronized (mPackages) {
if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
ContentObserver co = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- mEphemeralAppsDisabled =
- (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
- (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
+ 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_SYSTEM);
- mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
- .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
+ 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);
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
mContext.getContentResolver(), UserHandle.USER_SYSTEM);
+ disableSkuSpecificApps();
+
// Read the compatibilty setting when the system is ready.
boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
mContext.getContentResolver(),
android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
+
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
// possible for the user flow to never be able to return to that
// situation so here we do a sanity check to make sure we haven't
// left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ ArrayList<PreferredActivity> removed = new ArrayList<>();
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
removed.clear();
for (PreferredActivity pa : pir.filterSet()) {
- if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
+ if (!mComponentResolver.isActivityDefined(pa.mPref.mComponent)) {
removed.add(pa);
}
}
}
}
}
- sUserManager.systemReady();
+ sUserManager.systemReady();
// If we upgraded grant all default permissions before kicking off.
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
- // 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.
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.
mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
}
- // Kick off any messages waiting for system ready
- if (mPostSystemReadyMessages != null) {
- for (Message msg : mPostSystemReadyMessages) {
- msg.sendToTarget();
- }
- mPostSystemReadyMessages = null;
+ // Now that we've scanned all packages, and granted any default
+ // permissions, ensure permissions are updated. Beware of dragons if you
+ // try optimizing this.
+ synchronized (mPackages) {
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
+ mPermissionCallback);
+
+ final PermissionPolicyInternal permissionPolicyInternal =
+ LocalServices.getService(PermissionPolicyInternal.class);
+ permissionPolicyInternal.setOnInitializedCallback(userId -> {
+ // The SDK updated case is already handled when we run during the ctor.
+ synchronized (mPackages) {
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, false /*sdkUpdated*/,
+ mPackages.values(), mPermissionCallback);
+ }
+ });
}
// Watch for external volumes that come and go over time
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
+ mApexManager.systemReady();
mPackageDexOptimizer.systemReady();
- StorageManagerInternal StorageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- StorageManagerInternal.addExternalStoragePolicy(
+ getStorageManagerInternal().addExternalStoragePolicy(
new StorageManagerInternal.ExternalStorageMountPolicy() {
@Override
public int getMountMode(int uid, String packageName) {
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
- if (mPrivappPermissionsViolations != null) {
- Slog.wtf(TAG,"Signature|privileged permissions not in "
- + "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
- mPrivappPermissionsViolations = null;
+ mPermissionManager.systemReady();
+
+ 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));
}
+
+ 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();
}
public void waitForAppDataPrepared() {
@Override
public boolean isSafeMode() {
- // allow instant applications
- return mSafeMode;
- }
-
- @Override
- public boolean hasSystemUidErrors() {
- // allow instant applications
- return mHasSystemUidErrors;
- }
-
- static String arrayToString(int[] array) {
- StringBuffer buf = new StringBuffer(128);
- buf.append('[');
- if (array != null) {
- for (int i=0; i<array.length; i++) {
- if (i > 0) buf.append(", ");
- buf.append(array[i]);
- }
- }
- buf.append(']');
- return buf.toString();
- }
-
- static class DumpState {
- public static final int DUMP_LIBS = 1 << 0;
- public static final int DUMP_FEATURES = 1 << 1;
- public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
- public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
- public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
- public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
- public static final int DUMP_PERMISSIONS = 1 << 6;
- public static final int DUMP_PACKAGES = 1 << 7;
- public static final int DUMP_SHARED_USERS = 1 << 8;
- public static final int DUMP_MESSAGES = 1 << 9;
- public static final int DUMP_PROVIDERS = 1 << 10;
- public static final int DUMP_VERIFIERS = 1 << 11;
- public static final int DUMP_PREFERRED = 1 << 12;
- public static final int DUMP_PREFERRED_XML = 1 << 13;
- public static final int DUMP_KEYSETS = 1 << 14;
- public static final int DUMP_VERSION = 1 << 15;
- public static final int DUMP_INSTALLS = 1 << 16;
- public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
- public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
- public static final int DUMP_FROZEN = 1 << 19;
- public static final int DUMP_DEXOPT = 1 << 20;
- public static final int DUMP_COMPILER_STATS = 1 << 21;
- public static final int DUMP_CHANGES = 1 << 22;
- public static final int DUMP_VOLUMES = 1 << 23;
-
- public static final int OPTION_SHOW_FILTERS = 1 << 0;
-
- private int mTypes;
-
- private int mOptions;
-
- private boolean mTitlePrinted;
-
- private SharedUserSetting mSharedUser;
-
- public boolean isDumping(int type) {
- if (mTypes == 0 && type != DUMP_PREFERRED_XML) {
- return true;
- }
-
- return (mTypes & type) != 0;
- }
-
- public void setDump(int type) {
- mTypes |= type;
- }
-
- public boolean isOptionEnabled(int option) {
- return (mOptions & option) != 0;
- }
-
- public void setOptionEnabled(int option) {
- mOptions |= option;
- }
-
- public boolean onTitlePrinted() {
- final boolean printed = mTitlePrinted;
- mTitlePrinted = true;
- return printed;
- }
-
- public boolean getTitlePrinted() {
- return mTitlePrinted;
- }
-
- public void setTitlePrinted(boolean enabled) {
- mTitlePrinted = enabled;
- }
+ // allow instant applications
+ return mSafeMode;
+ }
- public SharedUserSetting getSharedUser() {
- return mSharedUser;
- }
+ @Override
+ public boolean hasSystemUidErrors() {
+ // allow instant applications
+ return mHasSystemUidErrors;
+ }
- public void setSharedUser(SharedUserSetting user) {
- mSharedUser = user;
+ static String arrayToString(int[] array) {
+ StringBuilder stringBuilder = new StringBuilder(128);
+ stringBuilder.append('[');
+ if (array != null) {
+ for (int i=0; i<array.length; i++) {
+ if (i > 0) stringBuilder.append(", ");
+ stringBuilder.append(array[i]);
+ }
}
+ stringBuilder.append(']');
+ return stringBuilder.toString();
}
@Override
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;
// Right now we only know how to print all.
} else if ("-h".equals(opt)) {
pw.println("Package manager dump options:");
- pw.println(" [-h] [-f] [--checkin] [cmd] ...");
+ pw.println(" [-h] [-f] [--checkin] [--all-components] [cmd] ...");
pw.println(" --checkin: dump for a checkin");
pw.println(" -f: print details of intent filters");
pw.println(" -h: print this help");
+ pw.println(" --all-components: include all component names in package dump");
pw.println(" cmd may be one of:");
+ pw.println(" apex: list active APEXes and APEX session state");
pw.println(" l[ibraries]: list known shared libraries");
pw.println(" f[eatures]: list device features");
pw.println(" k[eysets]: print known keysets");
pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?");
pw.println(" dexopt: dump dexopt state");
pw.println(" compiler-stats: dump compiler statistics");
- pw.println(" enabled-overlays: dump list of enabled overlay packages");
+ pw.println(" service-permissions: dump permissions required by services");
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
checkin = true;
+ } else if ("--all-components".equals(opt)) {
+ dumpState.setOptionEnabled(DumpState.OPTION_DUMP_ALL_COMPONENTS);
} else if ("-f".equals(opt)) {
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
} else if ("--proto".equals(opt)) {
dumpState.setDump(DumpState.DUMP_PACKAGES);
} else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_SHARED_USERS);
+ if (opti < args.length && "noperm".equals(args[opti])) {
+ dumpState.setOptionEnabled(DumpState.OPTION_SKIP_PERMISSIONS);
+ }
} else if ("prov".equals(cmd) || "providers".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PROVIDERS);
} else if ("m".equals(cmd) || "messages".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
} else if ("changes".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_CHANGES);
+ } else if ("service-permissions".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
} else if ("write".equals(cmd)) {
synchronized (mPackages) {
mSettings.writeLPr();
final Iterator<String> it = mSharedLibraries.keySet().iterator();
while (it.hasNext()) {
String libName = it.next();
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryInfo> versionedLib
+ = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- SharedLibraryEntry libEntry = versionedLib.valueAt(i);
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
if (!checkin) {
if (!printedHeader) {
if (dumpState.onTitlePrinted())
} else {
pw.print("lib,");
}
- pw.print(libEntry.info.getName());
- if (libEntry.info.isStatic()) {
- pw.print(" version=" + libEntry.info.getVersion());
+ pw.print(libraryInfo.getName());
+ if (libraryInfo.isStatic()) {
+ pw.print(" version=" + libraryInfo.getLongVersion());
}
if (!checkin) {
pw.print(" -> ");
}
- if (libEntry.path != null) {
+ if (libraryInfo.getPath() != null) {
pw.print(" (jar) ");
- pw.print(libEntry.path);
+ pw.print(libraryInfo.getPath());
} else {
pw.print(" (apk) ");
- pw.print(libEntry.apk);
+ pw.print(libraryInfo.getPackageName());
}
pw.println();
}
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
- if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
- : "Activity Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
+ mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
- if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
- : "Receiver Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
+ mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
- if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
- : "Service Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
+ mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
- if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:"
- : "Provider Resolver Table:", " ", packageName,
- dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
- dumpState.setTitlePrinted(true);
- }
+ mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
mSettings.dumpPermissionsLPr(pw, packageName, permissionNames, dumpState);
- if (packageName == null && permissionNames == null) {
- for (int iperm=0; iperm<mAppOpPermissionPackages.size(); iperm++) {
- if (iperm == 0) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("AppOp Permissions:");
- }
- pw.print(" AppOp Permission ");
- pw.print(mAppOpPermissionPackages.keyAt(iperm));
- pw.println(":");
- ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm);
- for (int ipkg=0; ipkg<pkgs.size(); ipkg++) {
- pw.print(" "); pw.println(pkgs.valueAt(ipkg));
- }
- }
- }
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
- boolean printedSomething = false;
- for (PackageParser.Provider p : mProviders.mProviders.values()) {
- if (packageName != null && !packageName.equals(p.info.packageName)) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Registered ContentProviders:");
- printedSomething = true;
- }
- pw.print(" "); p.printComponentShortName(pw); pw.println(":");
- pw.print(" "); pw.println(p.toString());
- }
- printedSomething = false;
- for (Map.Entry<String, PackageParser.Provider> entry :
- mProvidersByAuthority.entrySet()) {
- PackageParser.Provider p = entry.getValue();
- if (packageName != null && !packageName.equals(p.info.packageName)) {
- continue;
- }
- if (!printedSomething) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("ContentProvider Authorities:");
- printedSomething = true;
- }
- pw.print(" ["); pw.print(entry.getKey()); pw.println("]:");
- pw.print(" "); pw.println(p.toString());
- if (p.info != null && p.info.applicationInfo != null) {
- final String appInfo = p.info.applicationInfo.toString();
- pw.print(" applicationInfo="); pw.println(appInfo);
- }
- }
+ mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
- mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
- }
-
if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
ipw.decreaseIndent();
}
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+ && packageName == null) {
+ mComponentResolver.dumpServicePermissions(pw, dumpState, packageName);
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
if (dumpState.onTitlePrinted()) pw.println();
dumpDexoptStateLPr(pw, packageName);
pw.println();
pw.println("Package warning messages:");
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, null);
}
if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.print("msg,");
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, "msg,");
}
}
if (dumpState.onTitlePrinted()) pw.println();
mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
+
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
+ mApexManager.dump(pw, packageName);
+ }
+ }
+
+ //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 : sUserManager.getUsers(false)) {
+ setSystemAppInstallState(packageName, false, user.id);
+ }
+ }
}
private void dumpProto(FileDescriptor fd) {
dumpFeaturesProto(proto);
mSettings.dumpPackagesProto(proto);
mSettings.dumpSharedUsersProto(proto);
- dumpMessagesProto(proto);
+ dumpCriticalInfo(proto);
}
proto.flush();
}
- private void dumpMessagesProto(ProtoOutputStream proto) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- proto.write(PackageServiceDumpProto.MESSAGES, line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
private void dumpFeaturesProto(ProtoOutputStream proto) {
synchronized (mAvailableFeatures) {
final int count = mAvailableFeatures.size();
for (int i = 0; i < count; i++) {
- final FeatureInfo feat = mAvailableFeatures.valueAt(i);
- final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
- proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
- proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
- proto.end(featureToken);
+ mAvailableFeatures.valueAt(i).writeToProto(proto, PackageServiceDumpProto.FEATURES);
}
}
}
final int count = mSharedLibraries.size();
for (int i = 0; i < count; i++) {
final String libName = mSharedLibraries.keyAt(i);
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
final int versionCount = versionedLib.size();
for (int j = 0; j < versionCount; j++) {
- final SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+ final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
final long sharedLibraryToken =
proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
- proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libEntry.info.getName());
- final boolean isJar = (libEntry.path != null);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
+ final boolean isJar = (libraryInfo.getPath() != null);
proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
if (isJar) {
- proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH, libEntry.path);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
+ libraryInfo.getPath());
} else {
- proto.write(PackageServiceDumpProto.SharedLibraryProto.APK, libEntry.apk);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
+ libraryInfo.getPackageName());
}
proto.end(sharedLibraryToken);
}
}
}
+ @GuardedBy("mPackages")
+ @SuppressWarnings("resource")
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println();
ipw.println("Dexopt state:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
+ Collection<PackageParser.Package> packages;
if (packageName != null) {
PackageParser.Package targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
}
}
+ @GuardedBy("mPackages")
+ @SuppressWarnings("resource")
private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.println();
ipw.println("Compiler stats:");
ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
+ Collection<PackageParser.Package> packages;
if (packageName != null) {
PackageParser.Package targetPackage = mPackages.get(packageName);
if (targetPackage != null) {
ArraySet<String> result = new ArraySet<>();
if (iviList.size() > 0) {
for (IntentFilterVerificationInfo ivi : iviList) {
- for (String host : ivi.getDomains()) {
- result.add(host);
- }
+ result.addAll(ivi.getDomains());
}
}
if (filters != null && filters.size() > 0) {
}
}
- /*
- * Update media status on PackageManager.
- */
- @Override
- public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- enforceSystemOrRoot("Media status can only be updated by the system");
- // reader; this apparently protects mMediaMounted, but should probably
- // be a different lock in that case.
- synchronized (mPackages) {
- Log.i(TAG, "Updating external media status from "
- + (mMediaMounted ? "mounted" : "unmounted") + " to "
- + (mediaStatus ? "mounted" : "unmounted"));
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus
- + ", mMediaMounted=" + mMediaMounted);
- if (mediaStatus == mMediaMounted) {
- final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1
- : 0, -1);
- mHandler.sendMessage(msg);
- return;
- }
- mMediaMounted = mediaStatus;
- }
- // Queue up an async operation since the package installation may take a
- // little while.
- mHandler.post(new Runnable() {
- public void run() {
- updateExternalMediaStatusInner(mediaStatus, reportStatus, true);
- }
- });
- }
-
- /**
- * Called by StorageManagerService when the initial ASECs to scan are available.
- * Should block until all the ASEC containers are finished being scanned.
- */
- public void scanAvailableAsecs() {
- updateExternalMediaStatusInner(true, false, false);
- }
-
- /*
- * Collect information of applications on external media, map them against
- * existing containers and update information based on current mount status.
- * Please note that we always have to report status if reportStatus has been
- * set to true especially when unloading packages.
- */
- private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus,
- boolean externalStorage) {
- ArrayMap<AsecInstallArgs, String> processCids = new ArrayMap<>();
- int[] uidArr = EmptyArray.INT;
-
- final String[] list = PackageHelper.getSecureContainerList();
- if (ArrayUtils.isEmpty(list)) {
- Log.i(TAG, "No secure containers found");
- } else {
- // Process list of secure containers and categorize them
- // as active or stale based on their package internal state.
-
- // reader
- synchronized (mPackages) {
- for (String cid : list) {
- // Leave stages untouched for now; installer service owns them
- if (PackageInstallerService.isStageName(cid)) continue;
-
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Processing container " + cid);
- String pkgName = getAsecPackageName(cid);
- if (pkgName == null) {
- Slog.i(TAG, "Found stale container " + cid + " with no package name");
- continue;
- }
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Looking for pkg : " + pkgName);
-
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps == null) {
- Slog.i(TAG, "Found stale container " + cid + " with no matching settings");
- continue;
- }
-
- /*
- * Skip packages that are not external if we're unmounting
- * external storage.
- */
- if (externalStorage && !isMounted && !isExternal(ps)) {
- continue;
- }
-
- final AsecInstallArgs args = new AsecInstallArgs(cid,
- getAppDexInstructionSets(ps), ps.isForwardLocked());
- // The package status is changed only if the code path
- // matches between settings and the container id.
- if (ps.codePathString != null
- && ps.codePathString.startsWith(args.getCodePath())) {
- if (DEBUG_SD_INSTALL) {
- Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
- + " at code path: " + ps.codePathString);
- }
-
- // We do have a valid package installed on sdcard
- processCids.put(args, ps.codePathString);
- final int uid = ps.appId;
- if (uid != -1) {
- uidArr = ArrayUtils.appendInt(uidArr, uid);
- }
- } else {
- Slog.i(TAG, "Found stale container " + cid + ": expected codePath="
- + ps.codePathString);
- }
- }
- }
-
- Arrays.sort(uidArr);
- }
-
- // Process packages with valid entries.
- if (isMounted) {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, externalStorage);
- startCleaningPackages();
- mInstallerService.onSecureContainersAvailable();
- } else {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, reportStatus);
- }
- }
-
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
final int size = infos.size();
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, null);
- }
- }
-
- /*
- * Look at potentially valid container ids from processCids If package
- * information doesn't match the one on record or package scanning fails,
- * the cid is added to list of removeCids. We currently don't delete stale
- * containers.
- */
- private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr,
- boolean externalStorage) {
- ArrayList<String> pkgList = new ArrayList<String>();
- Set<AsecInstallArgs> keys = processCids.keySet();
-
- for (AsecInstallArgs args : keys) {
- String codePath = processCids.get(args);
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Loading container : " + args.cid);
- int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- try {
- // Make sure there are no container errors first.
- if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to mount cid : " + args.cid
- + " when installing from sdcard");
- continue;
- }
- // Check code path here.
- if (codePath == null || !codePath.startsWith(args.getCodePath())) {
- Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
- + " does not match one in settings " + codePath);
- continue;
- }
- // Parse package
- int parseFlags = mDefParseFlags;
- if (args.isExternalAsec()) {
- parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE;
- }
- if (args.isFwdLocked()) {
- parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
- }
-
- synchronized (mInstallLock) {
- PackageParser.Package pkg = null;
- try {
- // Sadly we don't know the package name yet to freeze it
- pkg = scanPackageTracedLI(new File(codePath), parseFlags,
- SCAN_IGNORE_FROZEN, 0, null);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
- }
- // Scan the package
- if (pkg != null) {
- /*
- * TODO why is the lock being held? doPostInstall is
- * called in other places without the lock. This needs
- * to be straightened out.
- */
- // writer
- synchronized (mPackages) {
- retCode = PackageManager.INSTALL_SUCCEEDED;
- pkgList.add(pkg.packageName);
- // Post process args
- args.doPostInstall(PackageManager.INSTALL_SUCCEEDED,
- pkg.applicationInfo.uid);
- }
- } else {
- Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard");
- }
- }
-
- } finally {
- if (retCode != PackageManager.INSTALL_SUCCEEDED) {
- Log.w(TAG, "Container " + args.cid + " is stale, retCode=" + retCode);
- }
- }
- }
- // writer
- synchronized (mPackages) {
- // If the platform SDK 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.
- final VersionInfo ver = externalStorage ? mSettings.getExternalVersion()
- : mSettings.getInternalVersion();
- final String volumeUuid = externalStorage ? StorageManager.UUID_PRIMARY_PHYSICAL
- : StorageManager.UUID_PRIVATE_INTERNAL;
-
- int updateFlags = UPDATE_PERMISSIONS_ALL;
- if (ver.sdkVersion != mSdkVersion) {
- logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
- + mSdkVersion + "; regranting permissions for external");
- updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
- }
- updatePermissionsLPw(null, null, volumeUuid, updateFlags);
-
- // Yay, everything is now upgraded
- ver.forceCurrent();
-
- // can downgrade to reader
- // Persist settings
- mSettings.writeLPr();
- }
- // Send a broadcast to let everyone know we are done processing
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(true, false, pkgList, uidArr, null);
- }
- }
-
- /*
- * Utility method to unload a list of specified containers
- */
- private void unloadAllContainers(Set<AsecInstallArgs> cidArgs) {
- // Just unmount all valid containers.
- for (AsecInstallArgs arg : cidArgs) {
- synchronized (mInstallLock) {
- arg.doPostDeleteLI(false);
- }
- }
- }
-
- /*
- * Unload packages mounted on external media. This involves deleting package
- * data from internal structures, sending broadcasts about disabled packages,
- * gc'ing to free up references, unmounting all secure containers
- * corresponding to packages on external media, and posting a
- * UPDATED_MEDIA_STATUS message if status has been requested. Please note
- * that we always have to post this message if status has been requested no
- * matter what.
- */
- private void unloadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int uidArr[],
- final boolean reportStatus) {
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "unloading media packages");
- ArrayList<String> pkgList = new ArrayList<String>();
- ArrayList<AsecInstallArgs> failedList = new ArrayList<AsecInstallArgs>();
- final Set<AsecInstallArgs> keys = processCids.keySet();
- for (AsecInstallArgs args : keys) {
- String pkgName = args.getPackageName();
- if (DEBUG_SD_INSTALL)
- Log.i(TAG, "Trying to unload pkg : " + pkgName);
- // Delete package internally
- PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
- synchronized (mInstallLock) {
- final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final boolean res;
- try (PackageFreezer freezer = freezePackageForDelete(pkgName, deleteFlags,
- "unloadMediaPackages")) {
- res = deletePackageLIF(pkgName, null, false, null, deleteFlags, outInfo, false,
- null);
- }
- if (res) {
- pkgList.add(pkgName);
- } else {
- Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
- failedList.add(args);
- }
- }
- }
-
- // reader
- synchronized (mPackages) {
- // We didn't update the settings after removing each package;
- // write them now for all packages.
- mSettings.writeLPr();
- }
-
- // We have to absolutely send UPDATED_MEDIA_STATUS only
- // after confirming that all the receivers processed the ordered
- // broadcast when packages get disabled, force a gc to clean things up.
- // and unload all the containers.
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(false, false, pkgList, uidArr,
- new IIntentReceiver.Stub() {
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky,
- int sendingUser) throws RemoteException {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, 1, keys);
- mHandler.sendMessage(msg);
- }
- });
- } else {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1,
- keys);
- mHandler.sendMessage(msg);
+ sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, null, null);
}
}
private void loadPrivatePackages(final VolumeInfo vol) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- loadPrivatePackagesInner(vol);
- }
- });
+ mHandler.post(() -> loadPrivatePackagesInner(vol));
}
private void loadPrivatePackagesInner(VolumeInfo vol) {
}
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
- clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
- | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+ | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
}
}
synchronized (mPackages) {
- int updateFlags = UPDATE_PERMISSIONS_ALL;
- if (ver.sdkVersion != mSdkVersion) {
+ final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
+ if (sdkUpdated) {
logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for " + volumeUuid);
- updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, volumeUuid, updateFlags);
+ mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(),
+ mPermissionCallback);
// Yay, everything is now upgraded
ver.forceCurrent();
}
private void unloadPrivatePackages(final VolumeInfo vol) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- unloadPrivatePackagesInner(vol);
- }
- });
+ mHandler.post(() -> unloadPrivatePackagesInner(vol));
}
private void unloadPrivatePackagesInner(VolumeInfo vol) {
}
}
- private void assertPackageKnown(String volumeUuid, String packageName)
- throws PackageManagerException {
- synchronized (mPackages) {
- // Normalize package name to handle renamed packages
- packageName = normalizePackageNameLPr(packageName);
-
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- throw new PackageManagerException("Package " + packageName + " is unknown");
- } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
- throw new PackageManagerException(
- "Package " + packageName + " found on unknown volume " + volumeUuid
- + "; expected volume " + ps.volumeUuid);
- }
- }
- }
-
private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
throws PackageManagerException {
synchronized (mPackages) {
}
}
+ @GuardedBy("mInstallLock")
private void reconcileAppsDataLI(String volumeUuid, int userId, int flags,
boolean migrateAppData) {
reconcileAppsDataLI(volumeUuid, userId, flags, migrateAppData, false /* onlyCoreApps */);
* <p>
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps.
- * @returns list of skipped non-core packages (if {@code onlyCoreApps} is true)
+ * @return list of skipped non-core packages (if {@code onlyCoreApps} is true)
*/
+ @GuardedBy("mInstallLock")
private List<String> reconcileAppsDataLI(String volumeUuid, int userId, int flags,
boolean migrateAppData, boolean onlyCoreApps) {
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
mSettings.writeKernelMappingLPr(ps);
}
- final UserManager um = mContext.getSystemService(UserManager.class);
+ final UserManagerService um = sUserManager;
UserManagerInternal umInternal = getUserManagerInternal();
- for (UserInfo user : um.getUsers()) {
+ for (UserInfo user : um.getUsers(false /* excludeDying */)) {
final int flags;
if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
+ Integer.toHexString(flags));
}
+ final PackageSetting ps;
+ synchronized (mPackages) {
+ ps = mSettings.mPackages.get(pkg.packageName);
+ }
final String volumeUuid = pkg.volumeUuid;
final String packageName = pkg.packageName;
- final ApplicationInfo app = pkg.applicationInfo;
+
+ ApplicationInfo app = (ps == null)
+ ? pkg.applicationInfo
+ : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
+ if (app == null) {
+ app = pkg.applicationInfo;
+ }
+
final int appId = UserHandle.getAppId(app.uid);
Preconditions.checkNotNull(app.seInfo);
+ final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : "");
long ceDataInode = -1;
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, app.seInfo, app.targetSdkVersion);
+ appId, seInfo, app.targetSdkVersion);
} catch (InstallerException e) {
if (app.isSystemApp()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
destroyAppDataLeafLIF(pkg, userId, flags);
try {
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
- appId, app.seInfo, app.targetSdkVersion);
+ appId, seInfo, app.targetSdkVersion);
logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
} catch (InstallerException e2) {
logCriticalInfo(Log.DEBUG, "Recovery failed!");
Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
}
}
+ // Prepare the application profiles only for upgrades and first boot (so that we don't
+ // repeat the same operation at each boot).
+ // We only have to cover the upgrade and first boot here because for app installs we
+ // prepare the profiles before invoking dexopt (in installPackageLI).
+ //
+ // We also have to cover non system users because we do not call the usual install package
+ // methods for them.
+ //
+ // NOTE: in order to speed up first boot time we only create the current profile and do not
+ // update the content of the reference profile. A system image should already be configured
+ // with the right profile keys and the profiles for the speed-profile prebuilds should
+ // already be copied. That's done in #performDexOptUpgrade.
+ //
+ // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of
+ // manually copying them in #performDexOptUpgrade. When we do that we should have a more
+ // granular check here and only update the existing profiles.
+ if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
+ mArtManagerService.prepareAppProfiles(pkg, userId,
+ /* updateReferenceProfileContent= */ false);
+ }
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
// TODO: mark this structure as dirty so we persist it!
synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
ps.setCeDataInode(ceDataInode, userId);
}
* requested by the app.
*/
private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) {
- if (pkg.isSystemApp() && !StorageManager.isFileEncryptedNativeOrEmulated()
+ if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
&& PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage()
? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
+ mCloseGuard.warnIfOpen();
close();
} finally {
super.finalize();
final int callingUid = Binder.getCallingUid();
final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid));
final int moveId = mNextMoveId.getAndIncrement();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- movePackageInternal(packageName, volumeUuid, moveId, callingUid, user);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to move " + packageName, e);
- mMoveCallbacks.notifyStatusChanged(moveId, e.error);
- }
+ mHandler.post(() -> {
+ try {
+ movePackageInternal(packageName, volumeUuid, moveId, callingUid, user);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to move " + packageName, e);
+ mMoveCallbacks.notifyStatusChanged(moveId, e.error);
}
});
return moveId;
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final PackageManager pm = mContext.getPackageManager();
- final boolean currentAsec;
final String currentVolumeUuid;
final File codeFile;
final String installerPackageName;
final int targetSdkVersion;
final PackageFreezer freezer;
final int[] installedUserIds;
+ final boolean isCurrentLocationExternal;
// reader
synchronized (mPackages) {
"3rd party apps are not allowed on internal storage");
}
- if (pkg.applicationInfo.isExternalAsec()) {
- currentAsec = true;
- currentVolumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
- } else if (pkg.applicationInfo.isForwardLocked()) {
- currentAsec = true;
- currentVolumeUuid = "forward_locked";
- } else {
- currentAsec = false;
- currentVolumeUuid = ps.volumeUuid;
+ currentVolumeUuid = ps.volumeUuid;
- final File probe = new File(pkg.codePath);
- final File probeOat = new File(probe, "oat");
- if (!probe.isDirectory() || !probeOat.isDirectory()) {
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Move only supported for modern cluster style installs");
- }
+ final File probe = new File(pkg.codePath);
+ final File probeOat = new File(probe, "oat");
+ if (!probe.isDirectory() || !probeOat.isDirectory()) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Move only supported for modern cluster style installs");
}
if (Objects.equals(currentVolumeUuid, volumeUuid)) {
"Failed to move already frozen package");
}
+ isCurrentLocationExternal = isExternal(pkg);
codeFile = new File(pkg.codePath);
installerPackageName = ps.installerPackageName;
packageAbiOverride = ps.cpuAbiOverrideString;
final boolean moveCompleteApp;
final File measurePath;
+ installFlags = INSTALL_INTERNAL;
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
- installFlags = INSTALL_INTERNAL;
- moveCompleteApp = !currentAsec;
+ moveCompleteApp = true;
measurePath = Environment.getDataAppDirectory(volumeUuid);
} else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
- installFlags = INSTALL_EXTERNAL;
moveCompleteApp = false;
measurePath = storage.getPrimaryPhysicalVolume().getPath();
} else {
"Move location not mounted private volume");
}
- Preconditions.checkState(!currentAsec);
-
- installFlags = INSTALL_INTERNAL;
moveCompleteApp = true;
measurePath = Environment.getDataAppDirectory(volumeUuid);
}
case PackageInstaller.STATUS_SUCCESS:
mMoveCallbacks.notifyStatusChanged(moveId,
PackageManager.MOVE_SUCCEEDED);
+ logAppMovedStorage(packageName, isCurrentLocationExternal);
break;
case PackageInstaller.STATUS_FAILURE_STORAGE:
mMoveCallbacks.notifyStatusChanged(moveId,
final MoveInfo move;
if (moveCompleteApp) {
// Kick off a thread to report progress estimates
- new Thread() {
- @Override
- public void run() {
- while (true) {
- try {
- if (installedLatch.await(1, TimeUnit.SECONDS)) {
- break;
- }
- } catch (InterruptedException ignored) {
+ new Thread(() -> {
+ while (true) {
+ try {
+ if (installedLatch.await(1, TimeUnit.SECONDS)) {
+ break;
}
-
- final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
- final int progress = 10 + (int) MathUtils.constrain(
- ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
- mMoveCallbacks.notifyStatusChanged(moveId, progress);
+ } catch (InterruptedException ignored) {
}
+
+ final long deltaFreeBytes = startFreeBytes - measurePath.getUsableSpace();
+ final int progress = 10 + (int) MathUtils.constrain(
+ ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
+ mMoveCallbacks.notifyStatusChanged(moveId, progress);
}
- }.start();
+ }).start();
final String dataAppName = codeFile.getName();
move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
installerPackageName, volumeUuid, null /*verificationInfo*/, user,
- packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ packageAbiOverride, null /*grantedPermissions*/,
+ null /*whitelistedRestrictedPermissions*/, PackageParser.SigningDetails.UNKNOWN,
+ PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
mHandler.sendMessage(msg);
}
+ /**
+ * Logs that an app has been moved from internal to external storage and vice versa.
+ * @param packageName The package that was moved.
+ */
+ private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
+ final PackageParser.Package pkg;
+ synchronized (mPackages) {
+ pkg = mPackages.get(packageName);
+ }
+ if (pkg == null) {
+ return;
+ }
+
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+ int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
+
+ if (!isPreviousLocationExternal && isExternal(pkg)) {
+ // Move from internal to external storage.
+ StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
+ StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
+ packageName);
+ } else if (isPreviousLocationExternal && !isExternal(pkg)) {
+ // Move from external to internal storage.
+ StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
+ StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
+ packageName);
+ }
+ }
+
@Override
public int movePrimaryStorage(String volumeUuid) throws RemoteException {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
}
@Override
- public void unregisterMoveCallback(IPackageMoveObserver callback) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
- mMoveCallbacks.unregister(callback);
+ 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, int userHandle) {
+ synchronized (mPackages) {
+ mDirtyUsers.remove(userHandle);
+ mUserNeedsBadging.delete(userHandle);
+ mSettings.removeUserLPw(userHandle);
+ mPendingBroadcasts.remove(userHandle);
+ mInstantAppRegistry.onUserRemovedLPw(userHandle);
+ removeUnusedPackagesLPw(userManager, userHandle);
+ }
+ }
+
+ /**
+ * We're removing userHandle and would like to remove any downloaded packages
+ * that are no longer in use by any other user.
+ * @param userHandle the user being removed
+ */
+ @GuardedBy("mPackages")
+ private void removeUnusedPackagesLPw(UserManagerService userManager, final int userHandle) {
+ final boolean DEBUG_CLEAN_APKS = false;
+ int [] users = userManager.getUserIds();
+ Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+ while (psit.hasNext()) {
+ PackageSetting ps = psit.next();
+ if (ps.pkg == null) {
+ continue;
+ }
+ final String packageName = ps.pkg.packageName;
+ // Skip over if system app or static shared library
+ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
+ || !TextUtils.isEmpty(ps.pkg.staticSharedLibName)) {
+ continue;
+ }
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, "Checking package " + packageName);
+ }
+ boolean keep = shouldKeepUninstalledPackageLPr(packageName);
+ if (keep) {
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, " Keeping package " + packageName + " - requested by DO");
+ }
+ } else {
+ for (int i = 0; i < users.length; i++) {
+ if (users[i] != userHandle && ps.getInstalled(users[i])) {
+ keep = true;
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, " Keeping package " + packageName + " for user "
+ + users[i]);
+ }
+ break;
+ }
+ }
+ }
+ if (!keep) {
+ if (DEBUG_CLEAN_APKS) {
+ Slog.i(TAG, " Removing package " + packageName);
+ }
+ //end run
+ mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+ userHandle, 0));
+ }
+ }
+ }
+
+ /** Called by UserManagerService */
+ void createNewUser(int userId, String[] disallowedPackages) {
+ synchronized (mInstallLock) {
+ mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
+ }
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(userId);
+ scheduleWritePackageListLocked(userId);
+ primeDomainVerificationsLPw(userId);
+ }
+ }
+
+ void onNewUserCreated(final int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissions(userId);
+ synchronized(mPackages) {
+ // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(),
+ mPermissionCallback);
+ }
+ }
+
+ boolean readPermissionStateForUser(@UserIdInt int userId) {
+ synchronized (mPackages) {
+ mSettings.readPermissionStateForUserSyncLPr(userId);
+ return mSettings.areDefaultRuntimePermissionsGrantedLPr(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 (mPackages) {
+ return mSettings.getVerifierDeviceIdentityLPw();
+ }
+ }
+
+ @Override
+ public void setPermissionEnforced(String permission, boolean enforced) {
+ // TODO: Now that we no longer change GID for storage, this should to away.
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ "setPermissionEnforced");
+ if (READ_EXTERNAL_STORAGE.equals(permission)) {
+ synchronized (mPackages) {
+ if (mSettings.mReadExternalStorageEnforced == null
+ || mSettings.mReadExternalStorageEnforced != enforced) {
+ mSettings.mReadExternalStorageEnforced =
+ enforced ? Boolean.TRUE : Boolean.FALSE;
+ mSettings.writeLPr();
+ }
+ }
+ // kill any non-foreground processes so we restart them and
+ // grant/revoke the GID.
+ final IActivityManager am = ActivityManager.getService();
+ if (am != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ am.killProcessesBelowForeground("setPermissionEnforcement");
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("No selective enforcement for " + permission);
+ }
+ }
+
+ @Override
+ @Deprecated
+ public boolean isPermissionEnforced(String permission) {
+ // allow instant applications
+ return true;
+ }
+
+ @Override
+ public boolean isStorageLow() {
+ // allow instant applications
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (dsm != null) {
+ return dsm.isMemoryLow();
+ } else {
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public IPackageInstaller getPackageInstaller() {
+ if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return mInstallerService;
+ }
+
+ @Override
+ public IArtManager getArtManager() {
+ return mArtManagerService;
+ }
+
+ private boolean userNeedsBadging(int userId) {
+ int index = mUserNeedsBadging.indexOfKey(userId);
+ if (index < 0) {
+ final UserInfo userInfo;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ userInfo = sUserManager.getUserInfo(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ final boolean b;
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ b = true;
+ } else {
+ b = false;
+ }
+ mUserNeedsBadging.put(userId, b);
+ return b;
+ }
+ return mUserNeedsBadging.valueAt(index);
+ }
+
+ @Override
+ public KeySet getKeySetByAlias(String packageName, String alias) {
+ if (packageName == null || alias == null) {
+ return null;
+ }
+ synchronized(mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
+ }
+ }
+
+ @Override
+ public KeySet getSigningKeySet(String packageName) {
+ if (packageName == null) {
+ return null;
+ }
+ synchronized(mPackages) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ // filter and pretend the package doesn't exist
+ Slog.w(TAG, "KeySet requested for filtered package: " + packageName
+ + ", uid:" + callingUid);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (pkg.applicationInfo.uid != callingUid
+ && Process.SYSTEM_UID != callingUid) {
+ throw new SecurityException("May not access signing KeySet of other apps.");
+ }
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ 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(mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null
+ || filterAppAccessLPr((PackageSetting) pkg.mExtras, 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.mKeySetManagerService;
+ return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
+ }
+ return false;
+ }
}
@Override
- public boolean setInstallLocation(int loc) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
- null);
- if (getInstallLocation() == loc) {
- return true;
+ public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) {
+ final int callingUid = Binder.getCallingUid();
+ if (getInstantAppPackageName(callingUid) != null) {
+ return false;
}
- 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;
+ if (packageName == null || ks == null) {
+ return false;
+ }
+ synchronized(mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null
+ || filterAppAccessLPr((PackageSetting) pkg.mExtras, 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.mKeySetManagerService;
+ return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
+ }
+ return false;
}
- 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, int userHandle) {
- synchronized (mPackages) {
- mDirtyUsers.remove(userHandle);
- mUserNeedsBadging.delete(userHandle);
- mSettings.removeUserLPw(userHandle);
- mPendingBroadcasts.remove(userHandle);
- mInstantAppRegistry.onUserRemovedLPw(userHandle);
- removeUnusedPackagesLPw(userManager, userHandle);
+ @GuardedBy("mPackages")
+ private void deletePackageIfUnusedLPr(final String packageName) {
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ return;
+ }
+ if (!ps.isAnyInstalled(sUserManager.getUserIds())) {
+ // TODO Implement atomic delete if package is unused
+ // It is currently possible that the package will be deleted even if it is installed
+ // after this method returns.
+ mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+ 0, PackageManager.DELETE_ALL_USERS));
}
}
/**
- * We're removing userHandle and would like to remove any downloaded packages
- * that are no longer in use by any other user.
- * @param userHandle the user being removed
+ * Check and throw if the given before/after packages would be considered a
+ * downgrade.
*/
- private void removeUnusedPackagesLPw(UserManagerService userManager, final int userHandle) {
- final boolean DEBUG_CLEAN_APKS = false;
- int [] users = userManager.getUserIds();
- Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
- while (psit.hasNext()) {
- PackageSetting ps = psit.next();
- if (ps.pkg == null) {
- continue;
- }
- final String packageName = ps.pkg.packageName;
- // Skip over if system app
- if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- continue;
- }
- if (DEBUG_CLEAN_APKS) {
- Slog.i(TAG, "Checking package " + packageName);
+ private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
+ throws PackageManagerException {
+ if (after.getLongVersionCode() < before.getLongVersionCode()) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update version code " + after.versionCode + " is older than current "
+ + before.getLongVersionCode());
+ } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
+ if (after.baseRevisionCode < before.baseRevisionCode) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update base revision code " + after.baseRevisionCode
+ + " is older than current " + before.baseRevisionCode);
}
- boolean keep = shouldKeepUninstalledPackageLPr(packageName);
- if (keep) {
- if (DEBUG_CLEAN_APKS) {
- Slog.i(TAG, " Keeping package " + packageName + " - requested by DO");
- }
- } else {
- for (int i = 0; i < users.length; i++) {
- if (users[i] != userHandle && ps.getInstalled(users[i])) {
- keep = true;
- if (DEBUG_CLEAN_APKS) {
- Slog.i(TAG, " Keeping package " + packageName + " for user "
- + users[i]);
+
+ if (!ArrayUtils.isEmpty(after.splitNames)) {
+ for (int i = 0; i < after.splitNames.length; i++) {
+ final String splitName = after.splitNames[i];
+ final int j = ArrayUtils.indexOf(before.splitNames, splitName);
+ if (j != -1) {
+ if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
+ throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
+ "Update split " + splitName + " revision code "
+ + after.splitRevisionCodes[i] + " is older than current "
+ + before.splitRevisionCodes[j]);
}
- break;
}
}
}
- if (!keep) {
- if (DEBUG_CLEAN_APKS) {
- Slog.i(TAG, " Removing package " + packageName);
- }
- mHandler.post(new Runnable() {
- public void run() {
- deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- userHandle, 0);
- } //end run
- });
- }
}
}
- /** Called by UserManagerService */
- void createNewUser(int userId, String[] disallowedPackages) {
- synchronized (mInstallLock) {
- mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
- }
- synchronized (mPackages) {
- scheduleWritePackageRestrictionsLocked(userId);
- scheduleWritePackageListLocked(userId);
- applyFactoryDefaultBrowserLPw(userId);
- primeDomainVerificationsLPw(userId);
- }
- }
+ private static class MoveCallbacks extends Handler {
+ private static final int MSG_CREATED = 1;
+ private static final int MSG_STATUS_CHANGED = 2;
- void onNewUserCreated(final int userId) {
- mDefaultPermissionPolicy.grantDefaultPermissions(userId);
- // If permission review for legacy apps is required, we represent
- // dagerous permissions for such apps as always granted runtime
- // permissions to keep per user flag state whether review is needed.
- // Hence, if a new user is added we have to propagate dangerous
- // permission grants for these legacy apps.
- if (mPermissionReviewRequired) {
- updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
- | UPDATE_PERMISSIONS_REPLACE_ALL);
+ private final RemoteCallbackList<IPackageMoveObserver>
+ mCallbacks = new RemoteCallbackList<>();
+
+ private final SparseIntArray mLastStatus = new SparseIntArray();
+
+ public MoveCallbacks(Looper looper) {
+ super(looper);
}
- }
- @Override
- public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can read the verifier device identity");
+ public void register(IPackageMoveObserver callback) {
+ mCallbacks.register(callback);
+ }
- synchronized (mPackages) {
- return mSettings.getVerifierDeviceIdentityLPw();
+ public void unregister(IPackageMoveObserver callback) {
+ mCallbacks.unregister(callback);
}
- }
- @Override
- public void setPermissionEnforced(String permission, boolean enforced) {
- // TODO: Now that we no longer change GID for storage, this should to away.
- mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
- "setPermissionEnforced");
- if (READ_EXTERNAL_STORAGE.equals(permission)) {
- synchronized (mPackages) {
- if (mSettings.mReadExternalStorageEnforced == null
- || mSettings.mReadExternalStorageEnforced != enforced) {
- mSettings.mReadExternalStorageEnforced = enforced;
- mSettings.writeLPr();
+ @Override
+ public void handleMessage(Message msg) {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ final IPackageMoveObserver callback = mCallbacks.getBroadcastItem(i);
+ try {
+ invokeCallback(callback, msg.what, args);
+ } catch (RemoteException ignored) {
}
}
- // kill any non-foreground processes so we restart them and
- // grant/revoke the GID.
- final IActivityManager am = ActivityManager.getService();
- if (am != null) {
- final long token = Binder.clearCallingIdentity();
- try {
- am.killProcessesBelowForeground("setPermissionEnforcement");
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(token);
+ mCallbacks.finishBroadcast();
+ args.recycle();
+ }
+
+ private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
+ throws RemoteException {
+ switch (what) {
+ case MSG_CREATED: {
+ callback.onCreated(args.argi1, (Bundle) args.arg2);
+ break;
+ }
+ case MSG_STATUS_CHANGED: {
+ callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
+ break;
}
}
- } else {
- throw new IllegalArgumentException("No selective enforcement for " + permission);
+ }
+
+ private void notifyCreated(int moveId, Bundle extras) {
+ Slog.v(TAG, "Move " + moveId + " created " + extras.toString());
+
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = moveId;
+ args.arg2 = extras;
+ obtainMessage(MSG_CREATED, args).sendToTarget();
+ }
+
+ private void notifyStatusChanged(int moveId, int status) {
+ notifyStatusChanged(moveId, status, -1);
+ }
+
+ private void notifyStatusChanged(int moveId, int status, long estMillis) {
+ Slog.v(TAG, "Move " + moveId + " status " + status);
+
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = moveId;
+ args.argi2 = status;
+ args.arg3 = estMillis;
+ obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
+
+ synchronized (mLastStatus) {
+ mLastStatus.put(moveId, status);
+ }
}
}
- @Override
- @Deprecated
- public boolean isPermissionEnforced(String permission) {
- // allow instant applications
- return true;
- }
+ private final static class OnPermissionChangeListeners extends Handler {
+ private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
- @Override
- public boolean isStorageLow() {
- // allow instant applications
- final long token = Binder.clearCallingIdentity();
- try {
- final DeviceStorageMonitorInternal
- dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
- if (dsm != null) {
- return dsm.isMemoryLow();
- } else {
- return false;
+ private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
+ new RemoteCallbackList<>();
+
+ public OnPermissionChangeListeners(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_PERMISSIONS_CHANGED: {
+ final int uid = msg.arg1;
+ handleOnPermissionsChanged(uid);
+ } break;
}
- } finally {
- Binder.restoreCallingIdentity(token);
}
- }
- @Override
- public IPackageInstaller getPackageInstaller() {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
+ public void addListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.register(listener);
+
}
- return mInstallerService;
- }
- private boolean userNeedsBadging(int userId) {
- int index = mUserNeedsBadging.indexOfKey(userId);
- if (index < 0) {
- final UserInfo userInfo;
- final long token = Binder.clearCallingIdentity();
+ public void removeListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.unregister(listener);
+ }
+
+ public void onPermissionsChanged(int uid) {
+ if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+ }
+
+ private void handleOnPermissionsChanged(int uid) {
+ final int count = mPermissionListeners.beginBroadcast();
try {
- userInfo = sUserManager.getUserInfo(userId);
+ for (int i = 0; i < count; i++) {
+ IOnPermissionsChangeListener callback = mPermissionListeners
+ .getBroadcastItem(i);
+ try {
+ callback.onPermissionsChanged(uid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Permission listener is dead", e);
+ }
+ }
} finally {
- Binder.restoreCallingIdentity(token);
- }
- final boolean b;
- if (userInfo != null && userInfo.isManagedProfile()) {
- b = true;
- } else {
- b = false;
+ mPermissionListeners.finishBroadcast();
}
- 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;
+ private class PackageManagerNative extends IPackageManagerNative.Stub {
+ @Override
+ public String[] getNamesForUids(int[] uids) throws RemoteException {
+ final String[] results = PackageManagerService.this.getNamesForUids(uids);
+ // 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;
}
- synchronized(mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+
+ // 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;
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
- Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+ // 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";
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
+ return "";
}
- }
- @Override
- public KeySet getSigningKeySet(String packageName) {
- if (packageName == null) {
- return null;
+ @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;
}
- synchronized(mPackages) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+
+ @Override
+ public int getTargetSdkVersionForPackage(String packageName)
+ throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo info = getApplicationInfo(packageName, 0, callingUser);
+ if (info == null) {
+ throw new RemoteException(
+ "Couldn't get ApplicationInfo for package " + packageName);
}
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
- // filter and pretend the package doesn't exist
- Slog.w(TAG, "KeySet requested for filtered package: " + packageName
- + ", uid:" + callingUid);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+ return info.targetSdkVersion;
+ }
+
+ @Override
+ public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames)
+ throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ boolean[] results = new boolean[packageNames.length];
+ for (int i = results.length - 1; i >= 0; --i) {
+ ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser);
+ results[i] = appInfo == null ? false : appInfo.isAudioPlaybackCaptureAllowed();
}
- if (pkg.applicationInfo.uid != callingUid
- && Process.SYSTEM_UID != callingUid) {
- throw new SecurityException("May not access signing KeySet of other apps.");
+ 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);
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return new KeySet(ksms.getSigningKeySetByPackageNameLPr(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 isPackageSignedByKeySet(String packageName, KeySet ks) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return false;
+ private class PackageManagerInternalImpl extends PackageManagerInternal {
+ @Override
+ public void updatePermissionFlagsTEMP(String permName, String packageName, int flagMask,
+ int flagValues, int userId) {
+ PackageManagerService.this.updatePermissionFlags(
+ permName, packageName, flagMask, flagValues, true, userId);
}
- if (packageName == null || ks == null) {
- return false;
+
+ @Override
+ public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
+ int callingUid) {
+ return PackageManagerService.this.getInstalledApplicationsListInternal(flags, userId,
+ callingUid);
}
- synchronized(mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null
- || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
- UserHandle.getUserId(callingUid))) {
- Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+
+
+ @Override
+ public boolean isPlatformSigned(String packageName) {
+ PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+ if (packageSetting == null) {
+ return false;
}
- IBinder ksh = ks.getToken();
- if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
+ PackageParser.Package pkg = packageSetting.pkg;
+ if (pkg == null) {
+ // May happen if package in on a removable sd card
+ return false;
}
- return false;
+ return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
+ || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+ PackageParser.SigningDetails.CertCapabilities.PERMISSION);
}
- }
- @Override
- public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return false;
+ @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);
}
- if (packageName == null || ks == null) {
- return false;
+
+ @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);
}
- synchronized(mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null
- || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
- UserHandle.getUserId(callingUid))) {
- Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
- throw new IllegalArgumentException("Unknown package: " + packageName);
+
+ @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) {
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p == null) {
+ return null;
+ }
+ return p.mSigningDetails;
}
- IBinder ksh = ks.getToken();
- if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
+ }
+
+ private SigningDetails getSigningDetails(int uid) {
+ synchronized (mPackages) {
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ return ((SharedUserSetting) obj).signatures.mSigningDetails;
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return ps.signatures.mSigningDetails;
+ }
+ }
+ return SigningDetails.UNKNOWN;
+ }
+ }
+
+ @Override
+ public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
+ return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
+ }
+
+ @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(PackageParser.Package pkg, int callingUid, int userId) {
+ synchronized (mPackages) {
+ return PackageManagerService.this.filterAppAccessLPr(
+ (PackageSetting) pkg.mExtras, callingUid, userId);
}
- return false;
}
- }
- private void deletePackageIfUnusedLPr(final String packageName) {
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- return;
+ @Override
+ public PackageParser.Package getPackage(String packageName) {
+ synchronized (mPackages) {
+ packageName = resolveInternalPackageNameLPr(
+ packageName, PackageManager.VERSION_CODE_HIGHEST);
+ return mPackages.get(packageName);
+ }
}
- if (!ps.isAnyInstalled(sUserManager.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(new Runnable() {
- public void run() {
- deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- 0, PackageManager.DELETE_ALL_USERS);
+
+ @Override
+ public PackageList getPackageList(PackageListObserver observer) {
+ synchronized (mPackages) {
+ 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;
+ }
}
- }
- /**
- * Check and throw if the given before/after packages would be considered a
- * downgrade.
- */
- private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
- throws PackageManagerException {
- if (after.versionCode < before.mVersionCode) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update version code " + after.versionCode + " is older than current "
- + before.mVersionCode);
- } else if (after.versionCode == before.mVersionCode) {
- if (after.baseRevisionCode < before.baseRevisionCode) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update base revision code " + after.baseRevisionCode
- + " is older than current " + before.baseRevisionCode);
+ @Override
+ public void removePackageListObserver(PackageListObserver observer) {
+ synchronized (mPackages) {
+ mPackageListObservers.remove(observer);
}
+ }
- if (!ArrayUtils.isEmpty(after.splitNames)) {
- for (int i = 0; i < after.splitNames.length; i++) {
- final String splitName = after.splitNames[i];
- final int j = ArrayUtils.indexOf(before.splitNames, splitName);
- if (j != -1) {
- if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
- throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
- "Update split " + splitName + " revision code "
- + after.splitRevisionCodes[i] + " is older than current "
- + before.splitRevisionCodes[j]);
- }
- }
- }
+ @Override
+ public PackageParser.Package getDisabledSystemPackage(String packageName) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+ return (ps != null) ? ps.pkg : null;
}
}
- }
- private static class MoveCallbacks extends Handler {
- private static final int MSG_CREATED = 1;
- private static final int MSG_STATUS_CHANGED = 2;
+ @Override
+ public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
+ PackageParser.Package pkg = getDisabledSystemPackage(packageName);
+ return pkg == null ? null : pkg.packageName;
+ }
- private final RemoteCallbackList<IPackageMoveObserver>
- mCallbacks = new RemoteCallbackList<>();
+ @Override
+ public String getKnownPackageName(int knownPackage, int userId) {
+ switch(knownPackage) {
+ case PackageManagerInternal.PACKAGE_BROWSER:
+ return getDefaultBrowserPackageName(userId);
+ case PackageManagerInternal.PACKAGE_INSTALLER:
+ return mRequiredInstallerPackage;
+ case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
+ return mSetupWizardPackage;
+ case PackageManagerInternal.PACKAGE_SYSTEM:
+ return "android";
+ case PackageManagerInternal.PACKAGE_VERIFIER:
+ return mRequiredVerifierPackage;
+ case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
+ return mSystemTextClassifierPackage;
+ case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
+ return mRequiredPermissionControllerPackage;
+ case PackageManagerInternal.PACKAGE_WELLBEING:
+ return mWellbeingPackage;
+ case PackageManagerInternal.PACKAGE_DOCUMENTER:
+ return mDocumenterPackage;
+ case PackageManagerInternal.PACKAGE_CONFIGURATOR:
+ return mConfiguratorPackage;
+ case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
+ return mIncidentReportApproverPackage;
+ case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
+ return mAppPredictionServicePackage;
+ }
+ return null;
+ }
- private final SparseIntArray mLastStatus = new SparseIntArray();
+ @Override
+ public boolean isResolveActivityComponent(ComponentInfo component) {
+ return mResolveActivity.packageName.equals(component.packageName)
+ && mResolveActivity.name.equals(component.name);
+ }
- public MoveCallbacks(Looper looper) {
- super(looper);
+ @Override
+ public void setLocationPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setLocationPackagesProvider(provider);
}
- public void register(IPackageMoveObserver callback) {
- mCallbacks.register(callback);
+ @Override
+ public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setLocationExtraPackagesProvider(provider);
}
- public void unregister(IPackageMoveObserver callback) {
- mCallbacks.unregister(callback);
+ @Override
+ public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
}
@Override
- public void handleMessage(Message msg) {
- final SomeArgs args = (SomeArgs) msg.obj;
- final int n = mCallbacks.beginBroadcast();
- for (int i = 0; i < n; i++) {
- final IPackageMoveObserver callback = mCallbacks.getBroadcastItem(i);
- try {
- invokeCallback(callback, msg.what, args);
- } catch (RemoteException ignored) {
- }
- }
- mCallbacks.finishBroadcast();
- args.recycle();
+ public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
}
- private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
- throws RemoteException {
- switch (what) {
- case MSG_CREATED: {
- callback.onCreated(args.argi1, (Bundle) args.arg2);
- break;
+ @Override
+ public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
+ mDefaultPermissionPolicy.setSyncAdapterPackagesProvider(provider);
+ }
+
+ @Override
+ public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
+ packageName, userId);
+ }
+
+ @Override
+ public void setKeepUninstalledPackages(final List<String> packageList) {
+ Preconditions.checkNotNull(packageList);
+ List<String> removedFromList = null;
+ synchronized (mPackages) {
+ 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);
+ }
}
- case MSG_STATUS_CHANGED: {
- callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
- break;
+ mKeepUninstalledPackages = new ArrayList<>(packageList);
+ if (removedFromList != null) {
+ final int removedCount = removedFromList.size();
+ for (int i = 0; i < removedCount; i++) {
+ deletePackageIfUnusedLPr(removedFromList.get(i));
+ }
}
}
}
- private void notifyCreated(int moveId, Bundle extras) {
- Slog.v(TAG, "Move " + moveId + " created " + extras.toString());
+ @Override
+ public boolean isPermissionsReviewRequired(String packageName, int userId) {
+ synchronized (mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ return false;
+ }
- final SomeArgs args = SomeArgs.obtain();
- args.argi1 = moveId;
- args.arg2 = extras;
- obtainMessage(MSG_CREATED, args).sendToTarget();
+ return mPermissionManager.isPermissionsReviewRequired(pkg, userId);
+ }
}
- private void notifyStatusChanged(int moveId, int status) {
- notifyStatusChanged(moveId, status, -1);
+ @Override
+ public PackageInfo getPackageInfo(
+ String packageName, int flags, int filterCallingUid, int userId) {
+ return PackageManagerService.this
+ .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
+ flags, filterCallingUid, userId);
}
- private void notifyStatusChanged(int moveId, int status, long estMillis) {
- Slog.v(TAG, "Move " + moveId + " status " + status);
-
- final SomeArgs args = SomeArgs.obtain();
- args.argi1 = moveId;
- args.argi2 = status;
- args.arg3 = estMillis;
- obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
-
- synchronized (mLastStatus) {
- mLastStatus.put(moveId, status);
+ @Override
+ public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ PersistableBundle launcherExtras = null;
+ if (ps != null) {
+ launcherExtras = ps.readUserState(userId).suspendedLauncherExtras;
+ }
+ return (launcherExtras != null) ? new Bundle(launcherExtras.deepCopy()) : null;
}
}
- }
- private final static class OnPermissionChangeListeners extends Handler {
- private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
+ @Override
+ public boolean isPackageSuspended(String packageName, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return (ps != null) ? ps.getSuspended(userId) : false;
+ }
+ }
- private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
- new RemoteCallbackList<>();
+ @Override
+ public String getSuspendingPackage(String suspendedPackage, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
+ }
+ }
- public OnPermissionChangeListeners(Looper looper) {
- super(looper);
+ @Override
+ public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+ return (ps != null) ? ps.readUserState(userId).dialogInfo : null;
+ }
}
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ON_PERMISSIONS_CHANGED: {
- final int uid = msg.arg1;
- handleOnPermissionsChanged(uid);
- } break;
+ public int getDistractingPackageRestrictions(String packageName, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
}
}
- public void addListenerLocked(IOnPermissionsChangeListener listener) {
- mPermissionListeners.register(listener);
+ @Override
+ public int getPackageUid(String packageName, int flags, int userId) {
+ return PackageManagerService.this
+ .getPackageUid(packageName, flags, userId);
+ }
+ @Override
+ public ApplicationInfo getApplicationInfo(
+ String packageName, int flags, int filterCallingUid, int userId) {
+ return PackageManagerService.this
+ .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
}
- public void removeListenerLocked(IOnPermissionsChangeListener listener) {
- mPermissionListeners.unregister(listener);
+ @Override
+ public ActivityInfo getActivityInfo(
+ ComponentName component, int flags, int filterCallingUid, int userId) {
+ return PackageManagerService.this
+ .getActivityInfoInternal(component, flags, filterCallingUid, userId);
}
- public void onPermissionsChanged(int uid) {
- if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
- obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
- }
+ @Override
+ public List<ResolveInfo> queryIntentActivities(
+ Intent intent, int flags, int filterCallingUid, int userId) {
+ final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+ return PackageManagerService.this
+ .queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid,
+ userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
}
- private void handleOnPermissionsChanged(int uid) {
- final int count = mPermissionListeners.beginBroadcast();
- try {
- for (int i = 0; i < count; i++) {
- IOnPermissionsChangeListener callback = mPermissionListeners
- .getBroadcastItem(i);
- try {
- callback.onPermissionsChanged(uid);
- } catch (RemoteException e) {
- Log.e(TAG, "Permission listener is dead", e);
- }
- }
- } finally {
- mPermissionListeners.finishBroadcast();
- }
+ @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);
}
- }
- private class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
- public String[] getNamesForUids(int[] uids) throws RemoteException {
- final String[] results = PackageManagerService.this.getNamesForUids(uids);
- // 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;
+ public ComponentName getDefaultHomeActivity(int userId) {
+ return PackageManagerService.this.getDefaultHomeActivity(userId);
}
- // 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;
+ 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);
}
- // 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";
+ final int sz = profileOwnerPackages.size();
+ for (int i = 0; i < sz; i++) {
+ if (profileOwnerPackages.valueAt(i) != null) {
+ usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
+ }
}
- return "";
+ unsuspendForNonSystemSuspendingPackages(usersWithPoOrDo);
}
@Override
- public int getVersionCodeForPackage(String packageName) throws RemoteException {
- try {
- int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser);
- if (pInfo != null) {
- return pInfo.versionCode;
- }
- } catch (Exception e) {
- }
- return 0;
+ public boolean isPackageDataProtected(int userId, String packageName) {
+ return mProtectedPackages.isPackageDataProtected(userId, packageName);
}
- }
- private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
- public void setLocationPackagesProvider(PackagesProvider provider) {
+ public boolean isPackageStateProtected(String packageName, int userId) {
+ return mProtectedPackages.isPackageStateProtected(userId, packageName);
+ }
+
+ @Override
+ public boolean isPackageEphemeral(int userId, String packageName) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setLocationPackagesProviderLPw(provider);
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return ps != null ? ps.getInstantApp(userId) : false;
}
}
@Override
- public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
+ public boolean wasPackageEverLaunched(String packageName, int userId) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setVoiceInteractionPackagesProviderLPw(provider);
+ return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
}
}
@Override
- public void setSmsAppPackagesProvider(PackagesProvider provider) {
+ public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setSmsAppPackagesProviderLPw(provider);
+ return mSettings.isEnabledAndMatchLPr(info, flags, userId);
}
}
@Override
- public void setDialerAppPackagesProvider(PackagesProvider provider) {
+ public boolean userNeedsBadging(int userId) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setDialerAppPackagesProviderLPw(provider);
+ return PackageManagerService.this.userNeedsBadging(userId);
}
}
@Override
- public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
+ public void grantRuntimePermission(String packageName, String permName, int userId,
+ boolean overridePolicy) {
+ PackageManagerService.this.mPermissionManager.grantRuntimePermission(
+ permName, packageName, overridePolicy, getCallingUid(), userId,
+ mPermissionCallback);
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ boolean overridePolicy) {
+ mPermissionManager.revokeRuntimePermission(
+ permName, packageName, overridePolicy, userId,
+ mPermissionCallback);
+ }
+
+ @Override
+ public String getNameForUid(int uid) {
+ return PackageManagerService.this.getNameForUid(uid);
+ }
+
+ @Override
+ public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage,
+ Bundle verificationBundle, int userId) {
+ PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
+ responseObj, origIntent, resolvedType, callingPackage, verificationBundle,
+ userId);
+ }
+
+ @Override
+ public void grantEphemeralAccess(int userId, Intent intent,
+ int targetAppId, int ephemeralAppId) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setSimCallManagerPackagesProviderLPw(provider);
+ mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
+ targetAppId, ephemeralAppId);
}
}
@Override
- public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
+ public boolean isInstantAppInstallerComponent(ComponentName component) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setSyncAdapterPackagesProviderLPw(provider);
+ return mInstantAppInstallerActivity != null
+ && mInstantAppInstallerActivity.getComponentName().equals(component);
}
}
@Override
- public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsAppLPr(
- packageName, userId);
+ public void pruneInstantApps() {
+ mInstantAppRegistry.pruneInstantApps();
+ }
+
+ @Override
+ public String getSetupWizardPackageName() {
+ return mSetupWizardPackage;
+ }
+
+ public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
+ if (policy != null) {
+ mExternalSourcesPolicy = policy;
}
}
@Override
- public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+ public boolean isPackagePersistent(String packageName) {
synchronized (mPackages) {
- mSettings.setDefaultDialerPackageNameLPw(packageName, userId);
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerAppLPr(
- packageName, userId);
+ PackageParser.Package pkg = mPackages.get(packageName);
+ return pkg != null
+ ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_PERSISTENT)) ==
+ (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
+ : false;
}
}
@Override
- public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+ public boolean isLegacySystemApp(PackageParser.Package pkg) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManagerLPr(
- packageName, userId);
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ return mPromoteSystemApps
+ && ps.isSystem()
+ && mExistingSystemPackages.contains(ps.name);
}
}
@Override
- public void setKeepUninstalledPackages(final List<String> packageList) {
- Preconditions.checkNotNull(packageList);
- List<String> removedFromList = null;
+ public List<PackageInfo> getOverlayPackages(int userId) {
+ final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
synchronized (mPackages) {
- 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<>();
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayTarget != null) {
+ PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
+ if (pkg != null) {
+ overlayPackages.add(pkg);
}
- 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));
}
}
}
+ return overlayPackages;
}
@Override
- public boolean isPermissionsReviewRequired(String packageName, int userId) {
+ public List<String> getTargetPackageNames(int userId) {
+ List<String> targetPackages = new ArrayList<>();
synchronized (mPackages) {
- // If we do not support permission review, done.
- if (!mPermissionReviewRequired) {
- return false;
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayTarget == null) {
+ targetPackages.add(p.packageName);
+ }
}
+ }
+ return targetPackages;
+ }
- PackageSetting packageSetting = mSettings.mPackages.get(packageName);
- if (packageSetting == null) {
+ @Override
+ public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
+ @Nullable List<String> overlayPackageNames) {
+ synchronized (mPackages) {
+ if (targetPackageName == null || mPackages.get(targetPackageName) == null) {
+ Slog.e(TAG, "failed to find package " + targetPackageName);
return false;
}
-
- // Permission review applies only to apps not supporting the new permission model.
- if (packageSetting.pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
- return false;
+ ArrayList<String> overlayPaths = null;
+ if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
+ final int N = overlayPackageNames.size();
+ overlayPaths = new ArrayList<>(N);
+ for (int i = 0; i < N; i++) {
+ final String packageName = overlayPackageNames.get(i);
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ Slog.e(TAG, "failed to find package " + packageName);
+ return false;
+ }
+ overlayPaths.add(pkg.baseCodePath);
+ }
}
- // Legacy apps have the permission and get user consent on launch.
- PermissionsState permissionsState = packageSetting.getPermissionsState();
- return permissionsState.isPermissionReviewRequired(userId);
+ final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+ ps.setOverlayPaths(overlayPaths, userId);
+ return true;
}
}
@Override
- public PackageInfo getPackageInfo(
- String packageName, int flags, int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
- flags, filterCallingUid, userId);
+ public ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ int flags, int userId, boolean resolveForStart, int filterCallingUid) {
+ return resolveIntentInternal(
+ intent, resolvedType, flags, userId, resolveForStart, filterCallingUid);
}
@Override
- public ApplicationInfo getApplicationInfo(
- String packageName, int flags, int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
+ public ResolveInfo resolveService(Intent intent, String resolvedType,
+ int flags, int userId, int callingUid) {
+ return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid);
}
@Override
- public ActivityInfo getActivityInfo(
- ComponentName component, int flags, int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getActivityInfoInternal(component, flags, filterCallingUid, userId);
+ public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+ return PackageManagerService.this.resolveContentProviderInternal(
+ name, flags, userId);
}
@Override
- public List<ResolveInfo> queryIntentActivities(
- Intent intent, int flags, int filterCallingUid, int userId) {
- final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
- return PackageManagerService.this
- .queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid,
- userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
+ public void addIsolatedUid(int isolatedUid, int ownerUid) {
+ synchronized (mPackages) {
+ mIsolatedOwners.put(isolatedUid, ownerUid);
+ }
}
@Override
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
+ public void removeIsolatedUid(int isolatedUid) {
+ synchronized (mPackages) {
+ mIsolatedOwners.delete(isolatedUid);
+ }
}
@Override
- public void setDeviceAndProfileOwnerPackages(
- int deviceOwnerUserId, String deviceOwnerPackage,
- SparseArray<String> profileOwnerPackages) {
- mProtectedPackages.setDeviceAndProfileOwnerPackages(
- deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+ public int getUidTargetSdkVersion(int uid) {
+ synchronized (mPackages) {
+ return getUidTargetSdkVersionLockedLPr(uid);
+ }
}
@Override
- public boolean isPackageDataProtected(int userId, String packageName) {
- return mProtectedPackages.isPackageDataProtected(userId, packageName);
+ public int getPackageTargetSdkVersion(String packageName) {
+ synchronized (mPackages) {
+ return getPackageTargetSdkVersionLockedLPr(packageName);
+ }
}
@Override
- public boolean isPackageEphemeral(int userId, String packageName) {
+ public boolean canAccessInstantApps(int callingUid, int userId) {
+ return PackageManagerService.this.canViewInstantApps(callingUid, userId);
+ }
+
+ @Override
+ public boolean canAccessComponent(int callingUid, ComponentName component, int userId) {
synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- return ps != null ? ps.getInstantApp(userId) : false;
+ final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ return ps != null && !PackageManagerService.this.filterAppAccessLPr(
+ ps, callingUid, component, TYPE_UNKNOWN, userId);
}
}
@Override
- public boolean wasPackageEverLaunched(String packageName, int userId) {
+ public boolean hasInstantApplicationMetadata(String packageName, int userId) {
synchronized (mPackages) {
- return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
+ return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId);
}
}
@Override
- public void grantRuntimePermission(String packageName, String name, int userId,
- boolean overridePolicy) {
- PackageManagerService.this.grantRuntimePermission(packageName, name, userId,
- overridePolicy);
+ public void notifyPackageUse(String packageName, int reason) {
+ synchronized (mPackages) {
+ PackageManagerService.this.notifyPackageUseLocked(packageName, reason);
+ }
}
@Override
- public void revokeRuntimePermission(String packageName, String name, int userId,
- boolean overridePolicy) {
- PackageManagerService.this.revokeRuntimePermission(packageName, name, userId,
- overridePolicy);
+ public CheckPermissionDelegate getCheckPermissionDelegate() {
+ synchronized (mPackages) {
+ return PackageManagerService.this.getCheckPermissionDelegateLocked();
+ }
}
@Override
- public String getNameForUid(int uid) {
- return PackageManagerService.this.getNameForUid(uid);
+ public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
+ synchronized (mPackages) {
+ PackageManagerService.this.setCheckPermissionDelegateLocked(delegate);
+ }
}
@Override
- public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
- Intent origIntent, String resolvedType, String callingPackage,
- Bundle verificationBundle, int userId) {
- PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
- responseObj, origIntent, resolvedType, callingPackage, verificationBundle,
- userId);
+ public SparseArray<String> getAppsWithSharedUserIds() {
+ synchronized (mPackages) {
+ return getAppsWithSharedUserIdsLocked();
+ }
+ }
+
+ @Override
+ public String getSharedUserIdForPackage(String packageName) {
+ synchronized (mPackages) {
+ return getSharedUserIdForPackageLocked(packageName);
+ }
}
@Override
- public void grantEphemeralAccess(int userId, Intent intent,
- int targetAppId, int ephemeralAppId) {
+ public String[] getPackagesForSharedUserId(String sharedUserId, int userId) {
synchronized (mPackages) {
- mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
- targetAppId, ephemeralAppId);
+ return getPackagesForSharedUserIdLocked(sharedUserId, userId);
}
}
@Override
- public boolean isInstantAppInstallerComponent(ComponentName component) {
- synchronized (mPackages) {
- return mInstantAppInstallerActivity != null
- && mInstantAppInstallerActivity.getComponentName().equals(component);
- }
+ public boolean isOnlyCoreApps() {
+ return PackageManagerService.this.isOnlyCoreApps();
}
@Override
- public void pruneInstantApps() {
- mInstantAppRegistry.pruneInstantApps();
+ public void freeStorage(String volumeUuid, long bytes, int storageFlags)
+ throws IOException {
+ PackageManagerService.this.freeStorage(volumeUuid, bytes, storageFlags);
}
@Override
- public String getSetupWizardPackageName() {
- return mSetupWizardPackage;
+ public void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+ PackageManagerService.this.forEachPackage(actionLocked);
}
- public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
- if (policy != null) {
- mExternalSourcesPolicy = policy;
- }
+ @Override
+ public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+ @UserIdInt int userId) {
+ PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
}
@Override
- public boolean isPackagePersistent(String packageName) {
+ public ArraySet<String> getEnabledComponents(String packageName, int userId) {
synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- return pkg != null
- ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_PERSISTENT)) ==
- (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
- : false;
+ PackageSetting setting = mSettings.getPackageLPr(packageName);
+ if (setting == null) {
+ return new ArraySet<>();
+ }
+ return setting.getEnabledComponents(userId);
}
}
@Override
- public List<PackageInfo> getOverlayPackages(int userId) {
- final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
+ public ArraySet<String> getDisabledComponents(String packageName, int userId) {
synchronized (mPackages) {
- for (PackageParser.Package p : mPackages.values()) {
- if (p.mOverlayTarget != null) {
- PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
- if (pkg != null) {
- overlayPackages.add(pkg);
- }
- }
+ PackageSetting setting = mSettings.getPackageLPr(packageName);
+ if (setting == null) {
+ return new ArraySet<>();
}
+ return setting.getDisabledComponents(userId);
}
- return overlayPackages;
}
@Override
- public List<String> getTargetPackageNames(int userId) {
- List<String> targetPackages = new ArrayList<>();
+ public @PackageManager.EnabledState int getApplicationEnabledState(
+ String packageName, int userId) {
synchronized (mPackages) {
- for (PackageParser.Package p : mPackages.values()) {
- if (p.mOverlayTarget == null) {
- targetPackages.add(p.packageName);
- }
+ PackageSetting setting = mSettings.getPackageLPr(packageName);
+ if (setting == null) {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
}
+ return setting.getEnabled(userId);
}
- return targetPackages;
}
@Override
- public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
- @Nullable List<String> overlayPackageNames) {
+ 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) {
+ PackageParser.Package pkg;
synchronized (mPackages) {
- if (targetPackageName == null || mPackages.get(targetPackageName) == null) {
- Slog.e(TAG, "failed to find package " + targetPackageName);
+ pkg = mPackages.get(packageName);
+ if (pkg == null) {
return false;
}
- ArrayList<String> overlayPaths = null;
- if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
- final int N = overlayPackageNames.size();
- overlayPaths = new ArrayList<>(N);
- for (int i = 0; i < N; i++) {
- final String packageName = overlayPackageNames.get(i);
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- Slog.e(TAG, "failed to find package " + packageName);
- return false;
- }
- overlayPaths.add(pkg.baseCodePath);
- }
- }
-
- final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
- ps.setOverlayPaths(overlayPaths, userId);
- return true;
}
+ return mArtManagerService.compileLayouts(pkg);
}
@Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- int flags, int userId) {
- return resolveIntentInternal(
- intent, resolvedType, flags, userId, true /*resolveForStart*/);
+ public void finishPackageInstall(int token, boolean didLaunch) {
+ PackageManagerService.this.finishPackageInstall(token, didLaunch);
}
+ @Nullable
@Override
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- int flags, int userId, int callingUid) {
- return resolveServiceInternal(intent, resolvedType, flags, userId, callingUid);
+ public String removeLegacyDefaultBrowserPackageName(int userId) {
+ synchronized (mPackages) {
+ return mSettings.removeDefaultBrowserPackageNameLPw(userId);
+ }
}
@Override
- public void addIsolatedUid(int isolatedUid, int ownerUid) {
+ public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
synchronized (mPackages) {
- mIsolatedOwners.put(isolatedUid, ownerUid);
+ mDefaultBrowserProvider = provider;
}
}
@Override
- public void removeIsolatedUid(int isolatedUid) {
+ public void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider) {
synchronized (mPackages) {
- mIsolatedOwners.delete(isolatedUid);
+ mDefaultDialerProvider = provider;
}
}
@Override
- public int getUidTargetSdkVersion(int uid) {
+ public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
synchronized (mPackages) {
- return getUidTargetSdkVersionLockedLPr(uid);
+ mDefaultHomeProvider = provider;
}
}
@Override
- public boolean canAccessInstantApps(int callingUid, int userId) {
- return PackageManagerService.this.canViewInstantApps(callingUid, userId);
+ public boolean isApexPackage(String packageName) {
+ return PackageManagerService.this.mApexManager.isApexPackage(packageName);
}
@Override
- public boolean hasInstantApplicationMetadata(String packageName, int userId) {
+ public void uninstallApex(String packageName, long versionCode, int userId,
+ IntentSender intentSender) {
+ 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 (userId != UserHandle.USER_ALL) {
+ 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 boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
synchronized (mPackages) {
- return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId);
+ return mDefaultPermissionPolicy.wereDefaultPermissionsGrantedSinceBoot(userId);
}
}
@Override
- public void notifyPackageUse(String packageName, int reason) {
+ public void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint,
+ @UserIdInt int userId) {
synchronized (mPackages) {
- PackageManagerService.this.notifyPackageUseLocked(packageName, reason);
+ mSettings.setRuntimePermissionsFingerPrintLPr(fingerPrint, userId);
+ }
+ }
+
+ @Override
+ public void migrateLegacyObbData() {
+ try {
+ mInstaller.migrateLegacyObbData();
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+ }
+
+ @GuardedBy("mPackages")
+ private SparseArray<String> getAppsWithSharedUserIdsLocked() {
+ final SparseArray<String> sharedUserIds = new SparseArray<>();
+ synchronized (mPackages) {
+ for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
+ sharedUserIds.put(UserHandle.getAppId(setting.userId), setting.name);
+ }
+ }
+ return sharedUserIds;
+ }
+
+ @GuardedBy("mPackages")
+ private String getSharedUserIdForPackageLocked(String packageName) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return (ps != null && ps.isSharedUser()) ? ps.sharedUser.name : null;
+ }
+
+ @GuardedBy("mPackages")
+ private String[] getPackagesForSharedUserIdLocked(String sharedUserId, int userId) {
+ try {
+ final SharedUserSetting sus = mSettings.getSharedUserLPw(
+ sharedUserId, 0, 0, false);
+ if (sus == null) {
+ return EmptyArray.STRING;
+ }
+ String[] res = new String[sus.packages.size()];
+ final Iterator<PackageSetting> it = sus.packages.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ PackageSetting ps = it.next();
+ if (ps.getInstalled(userId)) {
+ res[i++] = ps.name;
+ } else {
+ res = ArrayUtils.removeElement(String.class, res, res[i]);
+ }
}
+ return res;
+ } catch (PackageManagerException e) {
+ // Should not happen
+ }
+ return EmptyArray.STRING;
+ }
+
+ @Override
+ public int getRuntimePermissionsVersion(@UserIdInt int userId) {
+ Preconditions.checkArgumentNonnegative(userId);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+ "setRuntimePermissionVersion");
+ synchronized (mPackages) {
+ return mSettings.getDefaultRuntimePermissionsVersionLPr(userId);
+ }
+ }
+
+ @Override
+ public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) {
+ Preconditions.checkArgumentNonnegative(version);
+ Preconditions.checkArgumentNonnegative(userId);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+ "setRuntimePermissionVersion");
+ synchronized (mPackages) {
+ mSettings.setDefaultRuntimePermissionsVersionLPr(version, userId);
}
}
synchronized (mPackages) {
final long identity = Binder.clearCallingIdentity();
try {
- mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledCarrierAppsLPr(
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledCarrierApps(
packageNames, userId);
} finally {
Binder.restoreCallingIdentity(identity);
synchronized (mPackages) {
final long identity = Binder.clearCallingIdentity();
try {
- mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServicesLPr(
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServices(
packageNames, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ @Override
+ public void grantDefaultPermissionsToEnabledTelephonyDataServices(
+ String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledTelephonyDataServices");
+ synchronized (mPackages) {
+ Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
+ grantDefaultPermissionsToEnabledTelephonyDataServices(
+ packageNames, userId));
+ }
+ }
+
+ @Override
+ public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+ String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromDisabledTelephonyDataServices");
+ synchronized (mPackages) {
+ Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
+ revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+ packageNames, userId));
+ }
+ }
+
+ @Override
+ public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
+ enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToActiveLuiApp(
+ packageName, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.revokeDefaultPermissionsFromLuiApps(packageNames, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+ synchronized (mPackages) {
+ int numPackages = mPackages.size();
+ for (int i = 0; i < numPackages; i++) {
+ actionLocked.accept(mPackages.valueAt(i));
+ }
+ }
+ }
+
+ void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+ @UserIdInt int userId) {
+ synchronized (mPackages) {
+ int numPackages = mPackages.size();
+ for (int i = 0; i < numPackages; i++) {
+ PackageParser.Package pkg = mPackages.valueAt(i);
+ PackageSetting setting = mSettings.getPackageLPr(pkg.packageName);
+ if (setting == null || !setting.getInstalled(userId)) {
+ continue;
+ }
+ actionLocked.accept(pkg);
+ }
+ }
+ }
+
private static void enforceSystemOrPhoneCaller(String tag) {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
@Override
public int getInstallReason(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"get install reason");
synchronized (mPackages) {
if (info.targetSdkVersion < Build.VERSION_CODES.O) {
return false;
}
+ if (isInstantApp(packageName, userId)) {
+ return false;
+ }
String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
return false;
}
}
- if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)) {
+ if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)
+ || sUserManager.hasUserRestriction(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userId)) {
return false;
}
if (mExternalSourcesPolicy != null) {
public String getInstantAppAndroidId(String packageName, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
"getInstantAppAndroidId");
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppAndroidId");
// Make sure the target is an Instant App.
}
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);
+
+ mPermissionManager.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(mPackages) {
+ 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);
+
+ mPermissionManager.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(mPackages) {
+ 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);
+
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
+ false /*requireFullPermission*/, true /*checkShell*/, "isPackageStateProtected");
+
+ if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID
+ && checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) != PERMISSION_GRANTED) {
+ throw new SecurityException("Caller must have the "
+ + MANAGE_DEVICE_ADMINS + " permission.");
+ }
+
+ return mProtectedPackages.isPackageStateProtected(userId, packageName);
+ }
+
+ @Override
+ public void sendDeviceCustomizationReadyBroadcast() {
+ mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY,
+ "sendDeviceCustomizationReadyBroadcast");
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final Intent intent = new Intent(Intent.ACTION_DEVICE_CUSTOMIZATION_READY);
+ intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ final IActivityManager am = ActivityManager.getService();
+ final String[] requiredPermissions = {
+ Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY,
+ };
+ try {
+ am.broadcastIntent(null, intent, null, null, 0, null, null, requiredPermissions,
+ android.app.AppOpsManager.OP_NONE, null, false, false, UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ static class ActiveInstallSession {
+ private final String mPackageName;
+ private final File mStagedDir;
+ private final IPackageInstallObserver2 mObserver;
+ private final PackageInstaller.SessionParams mSessionParams;
+ private final String mInstallerPackageName;
+ private final int mInstallerUid;
+ private final UserHandle mUser;
+ private final SigningDetails mSigningDetails;
+
+ ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, String installerPackageName,
+ int installerUid, UserHandle user, SigningDetails signingDetails) {
+ mPackageName = packageName;
+ mStagedDir = stagedDir;
+ mObserver = observer;
+ mSessionParams = sessionParams;
+ mInstallerPackageName = installerPackageName;
+ mInstallerUid = installerUid;
+ mUser = user;
+ mSigningDetails = signingDetails;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public File getStagedDir() {
+ return mStagedDir;
+ }
+
+ public IPackageInstallObserver2 getObserver() {
+ return mObserver;
+ }
+
+ public PackageInstaller.SessionParams getSessionParams() {
+ return mSessionParams;
+ }
+
+ public String getInstallerPackageName() {
+ return mInstallerPackageName;
+ }
+
+ public int getInstallerUid() {
+ return mInstallerUid;
+ }
+
+ public UserHandle getUser() {
+ return mUser;
+ }
+
+ public SigningDetails getSigningDetails() {
+ return mSigningDetails;
+ }
+ }
}
interface PackageSender {
+ /**
+ * @param userIds User IDs where the action occurred on a full application
+ * @param instantUserIds User IDs where the action occurred on an instant application
+ */
void sendPackageBroadcast(final String action, final String pkg,
final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds);
+ final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int... userIds);
+ boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
+ void notifyPackageAdded(String packageName, int uid);
+ void notifyPackageChanged(String packageName, int uid);
+ void notifyPackageRemoved(String packageName, int uid);
}