summaryrefslogtreecommitdiff
path: root/com/android/server/pm/Settings.java
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
committerJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
commit10d07c88d69cc64f73a069163e7ea5ba2519a099 (patch)
tree8dbd149eb350320a29c3d10e7ad3201de1c5cbee /com/android/server/pm/Settings.java
parent677516fb6b6f207d373984757d3d9450474b6b00 (diff)
downloadandroid-28-10d07c88d69cc64f73a069163e7ea5ba2519a099.tar.gz
Import Android SDK Platform PI [4335822]
/google/data/ro/projects/android/fetch_artifact \ --bid 4335822 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4335822.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: Ic8f04be005a71c2b9abeaac754d8da8d6f9a2c32
Diffstat (limited to 'com/android/server/pm/Settings.java')
-rw-r--r--com/android/server/pm/Settings.java5687
1 files changed, 5687 insertions, 0 deletions
diff --git a/com/android/server/pm/Settings.java b/com/android/server/pm/Settings.java
new file mode 100644
index 00000000..56835f69
--- /dev/null
+++ b/com/android/server/pm/Settings.java
@@ -0,0 +1,5687 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+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_ENABLED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageCleanItem;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.pm.VerifierDeviceIdentity;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.service.pm.PackageServiceDumpProto;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+import android.util.SparseLongArray;
+import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import com.android.server.backup.PreferredActivityBackupHelper;
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.PackageManagerService.DumpState;
+import com.android.server.pm.PermissionsState.PermissionState;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Holds information about dynamic settings.
+ */
+final class Settings {
+ private static final String TAG = "PackageSettings";
+
+ /**
+ * Current version of the package database. Set it to the latest version in
+ * the {@link DatabaseVersion} class below to ensure the database upgrade
+ * doesn't happen repeatedly.
+ * <p>
+ * Note that care should be taken to make sure all database upgrades are
+ * idempotent.
+ */
+ public static final int CURRENT_DATABASE_VERSION = DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
+
+ /**
+ * This class contains constants that can be referred to from upgrade code.
+ * Insert constant values here that describe the upgrade reason. The version
+ * code must be monotonically increasing.
+ */
+ public static class DatabaseVersion {
+ /**
+ * The initial version of the database.
+ */
+ public static final int FIRST_VERSION = 1;
+
+ /**
+ * Migrating the Signature array from the entire certificate chain to
+ * just the signing certificate.
+ */
+ public static final int SIGNATURE_END_ENTITY = 2;
+
+ /**
+ * There was a window of time in
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP} where we persisted
+ * certificates after potentially mutating them. To switch back to the
+ * original untouched certificates, we need to force a collection pass.
+ */
+ public static final int SIGNATURE_MALFORMED_RECOVER = 3;
+ }
+
+ private static final boolean DEBUG_STOPPED = false;
+ private static final boolean DEBUG_MU = false;
+ private static final boolean DEBUG_KERNEL = false;
+ private static final boolean DEBUG_PARSER = false;
+
+ private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
+
+ private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
+ private static final String ATTR_ENFORCEMENT = "enforcement";
+
+ private static final String TAG_ITEM = "item";
+ private static final String TAG_DISABLED_COMPONENTS = "disabled-components";
+ private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
+ private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
+ private static final String TAG_PACKAGE = "pkg";
+ private static final String TAG_SHARED_USER = "shared-user";
+ private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
+ private static final String TAG_PERMISSIONS = "perms";
+ private static final String TAG_CHILD_PACKAGE = "child-package";
+ private static final String TAG_USES_STATIC_LIB = "uses-static-lib";
+ private static final String TAG_BLOCK_UNINSTALL_PACKAGES = "block-uninstall-packages";
+ private static final String TAG_BLOCK_UNINSTALL = "block-uninstall";
+
+ private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
+ "persistent-preferred-activities";
+ static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
+ "crossProfile-intent-filters";
+ private static final String TAG_DOMAIN_VERIFICATION = "domain-verification";
+ private static final String TAG_DEFAULT_APPS = "default-apps";
+ private static final String TAG_ALL_INTENT_FILTER_VERIFICATION =
+ "all-intent-filter-verifications";
+ private static final String TAG_DEFAULT_BROWSER = "default-browser";
+ private static final String TAG_DEFAULT_DIALER = "default-dialer";
+ private static final String TAG_VERSION = "version";
+
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_USER = "user";
+ private static final String ATTR_CODE = "code";
+ private static final String ATTR_GRANTED = "granted";
+ private static final String ATTR_FLAGS = "flags";
+ private static final String ATTR_VERSION = "version";
+
+ private static final String ATTR_CE_DATA_INODE = "ceDataInode";
+ private static final String ATTR_INSTALLED = "inst";
+ private static final String ATTR_STOPPED = "stopped";
+ private static final String ATTR_NOT_LAUNCHED = "nl";
+ // Legacy, here for reading older versions of the package-restrictions.
+ private static final String ATTR_BLOCKED = "blocked";
+ // New name for the above attribute.
+ private static final String ATTR_HIDDEN = "hidden";
+ private static final String ATTR_SUSPENDED = "suspended";
+ // Legacy, uninstall blocks are stored separately.
+ @Deprecated
+ private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
+ private static final String ATTR_ENABLED = "enabled";
+ private static final String ATTR_ENABLED_CALLER = "enabledCaller";
+ private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
+ private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
+ private static final String ATTR_INSTALL_REASON = "install-reason";
+ private static final String ATTR_INSTANT_APP = "instant-app";
+ private static final String ATTR_VIRTUAL_PRELOAD = "virtual-preload";
+
+ private static final String ATTR_PACKAGE_NAME = "packageName";
+ private static final String ATTR_FINGERPRINT = "fingerprint";
+ private static final String ATTR_VOLUME_UUID = "volumeUuid";
+ private static final String ATTR_SDK_VERSION = "sdkVersion";
+ private static final String ATTR_DATABASE_VERSION = "databaseVersion";
+ private static final String ATTR_DONE = "done";
+
+ // Bookkeeping for restored permission grants
+ private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
+ // package name: ATTR_PACKAGE_NAME
+ private static final String TAG_PERMISSION_ENTRY = "perm";
+ // permission name: ATTR_NAME
+ // permission granted (boolean): ATTR_GRANTED
+ private static final String ATTR_USER_SET = "set";
+ private static final String ATTR_USER_FIXED = "fixed";
+ private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+
+ // Flag mask of restored permission grants that are applied at install time
+ private static final int USER_RUNTIME_GRANT_MASK =
+ FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED
+ | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+
+ private final Object mLock;
+
+ private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
+
+ private final File mSettingsFilename;
+ private final File mBackupSettingsFilename;
+ private final File mPackageListFilename;
+ private final File mStoppedPackagesFilename;
+ private final File mBackupStoppedPackagesFilename;
+ /** The top level directory in configfs for sdcardfs to push the package->uid,userId mappings */
+ private final File mKernelMappingFilename;
+
+ /** Map from package name to settings */
+ final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
+
+ /** List of packages that installed other packages */
+ final ArraySet<String> mInstallerPackages = new ArraySet<>();
+
+ /** Map from package name to appId and excluded userids */
+ private final ArrayMap<String, KernelPackageState> mKernelMapping = new ArrayMap<>();
+
+ // List of replaced system applications
+ private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
+ new ArrayMap<String, PackageSetting>();
+
+ /** List of packages that are blocked for uninstall for specific users */
+ private final SparseArray<ArraySet<String>> mBlockUninstallPackages = new SparseArray<>();
+
+ // Set of restored intent-filter verification states
+ private final ArrayMap<String, IntentFilterVerificationInfo> mRestoredIntentFilterVerifications =
+ new ArrayMap<String, IntentFilterVerificationInfo>();
+
+ private static final class KernelPackageState {
+ int appId;
+ int[] excludedUserIds;
+ }
+
+ // Bookkeeping for restored user permission grants
+ final class RestoredPermissionGrant {
+ String permissionName;
+ boolean granted;
+ int grantBits;
+
+ RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) {
+ permissionName = name;
+ granted = isGranted;
+ grantBits = theGrantBits;
+ }
+ }
+
+ // This would be more compact as a flat array of restored grants or something, but we
+ // may have quite a few, especially during early device lifetime, and avoiding all those
+ // linear lookups will be important.
+ private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>
+ mRestoredUserGrants =
+ new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>();
+
+ private static int mFirstAvailableUid = 0;
+
+ /** Map from volume UUID to {@link VersionInfo} */
+ private ArrayMap<String, VersionInfo> mVersion = new ArrayMap<>();
+
+ /**
+ * Version details for a storage volume that may hold apps.
+ */
+ public static class VersionInfo {
+ /**
+ * These are the last platform API version we were using for the apps
+ * installed on internal and external storage. It is used to grant newer
+ * permissions one time during a system upgrade.
+ */
+ int sdkVersion;
+
+ /**
+ * The current database version for apps on internal storage. This is
+ * used to upgrade the format of the packages.xml database not
+ * necessarily tied to an SDK version.
+ */
+ int databaseVersion;
+
+ /**
+ * Last known value of {@link Build#FINGERPRINT}. Used to determine when
+ * an system update has occurred, meaning we need to clear code caches.
+ */
+ String fingerprint;
+
+ /**
+ * Force all version information to match current system values,
+ * typically after resolving any required upgrade steps.
+ */
+ public void forceCurrent() {
+ sdkVersion = Build.VERSION.SDK_INT;
+ databaseVersion = CURRENT_DATABASE_VERSION;
+ fingerprint = Build.FINGERPRINT;
+ }
+ }
+
+ Boolean mReadExternalStorageEnforced;
+
+ /** Device identity for the purpose of package verification. */
+ private VerifierDeviceIdentity mVerifierDeviceIdentity;
+
+ // The user's preferred activities associated with particular intent
+ // filters.
+ final SparseArray<PreferredIntentResolver> mPreferredActivities =
+ new SparseArray<PreferredIntentResolver>();
+
+ // The persistent preferred activities of the user's profile/device owner
+ // associated with particular intent filters.
+ final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
+ new SparseArray<PersistentPreferredIntentResolver>();
+
+ // For every user, it is used to find to which other users the intent can be forwarded.
+ final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
+ new SparseArray<CrossProfileIntentResolver>();
+
+ final ArrayMap<String, SharedUserSetting> mSharedUsers =
+ new ArrayMap<String, SharedUserSetting>();
+ private final ArrayList<Object> mUserIds = new ArrayList<Object>();
+ private final SparseArray<Object> mOtherUserIds =
+ new SparseArray<Object>();
+
+ // For reading/writing settings file.
+ private final ArrayList<Signature> mPastSignatures =
+ new ArrayList<Signature>();
+ private final ArrayMap<Long, Integer> mKeySetRefs =
+ new ArrayMap<Long, Integer>();
+
+ // Mapping from permission names to info about them.
+ final ArrayMap<String, BasePermission> mPermissions =
+ new ArrayMap<String, BasePermission>();
+
+ // Mapping from permission tree names to info about them.
+ final ArrayMap<String, BasePermission> mPermissionTrees =
+ new ArrayMap<String, BasePermission>();
+
+ // Packages that have been uninstalled and still need their external
+ // storage data deleted.
+ final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
+
+ // Packages that have been renamed since they were first installed.
+ // Keys are the new names of the packages, values are the original
+ // names. The packages appear everywhere else under their original
+ // names.
+ private final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
+
+ // For every user, it is used to find the package name of the default Browser App.
+ final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
+
+ // For every user, a record of the package name of the default Dialer App.
+ final SparseArray<String> mDefaultDialerApp = new SparseArray<String>();
+
+ // App-link priority tracking, per-user
+ final SparseIntArray mNextAppLinkGeneration = new SparseIntArray();
+
+ final StringBuilder mReadMessages = new StringBuilder();
+
+ /**
+ * Used to track packages that have a shared user ID that hasn't been read
+ * in yet.
+ * <p>
+ * TODO: make this just a local variable that is passed in during package
+ * scanning to make it less confusing.
+ */
+ private final ArrayList<PackageSetting> mPendingPackages = new ArrayList<>();
+
+ private final File mSystemDir;
+
+ public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+
+ Settings(Object lock) {
+ this(Environment.getDataDirectory(), lock);
+ }
+
+ Settings(File dataDir, Object lock) {
+ mLock = lock;
+
+ mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
+
+ mSystemDir = new File(dataDir, "system");
+ mSystemDir.mkdirs();
+ FileUtils.setPermissions(mSystemDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mSettingsFilename = new File(mSystemDir, "packages.xml");
+ mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
+ mPackageListFilename = new File(mSystemDir, "packages.list");
+ FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+
+ final File kernelDir = new File("/config/sdcardfs");
+ mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
+
+ // Deprecated: Needed for migration
+ mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
+ mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
+ }
+
+ PackageSetting getPackageLPr(String pkgName) {
+ return mPackages.get(pkgName);
+ }
+
+ String getRenamedPackageLPr(String pkgName) {
+ return mRenamedPackages.get(pkgName);
+ }
+
+ String addRenamedPackageLPw(String pkgName, String origPkgName) {
+ return mRenamedPackages.put(pkgName, origPkgName);
+ }
+
+ void setInstallStatus(String pkgName, final int status) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ if(p.getInstallStatus() != status) {
+ p.setInstallStatus(status);
+ }
+ }
+ }
+
+ void applyPendingPermissionGrantsLPw(String packageName, int userId) {
+ ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+ mRestoredUserGrants.get(userId);
+ if (grantsByPackage == null || grantsByPackage.size() == 0) {
+ return;
+ }
+
+ ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName);
+ if (grants == null || grants.size() == 0) {
+ return;
+ }
+
+ final PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.e(TAG, "Can't find supposedly installed package " + packageName);
+ return;
+ }
+ final PermissionsState perms = ps.getPermissionsState();
+
+ for (RestoredPermissionGrant grant : grants) {
+ BasePermission bp = mPermissions.get(grant.permissionName);
+ if (bp != null) {
+ if (grant.granted) {
+ perms.grantRuntimePermission(bp, userId);
+ }
+ perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits);
+ }
+ }
+
+ // And remove it from the pending-grant bookkeeping
+ grantsByPackage.remove(packageName);
+ if (grantsByPackage.size() < 1) {
+ mRestoredUserGrants.remove(userId);
+ }
+ writeRuntimePermissionsForUserLPr(userId, false);
+ }
+
+ void setInstallerPackageName(String pkgName, String installerPkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ if (p != null) {
+ p.setInstallerPackageName(installerPkgName);
+ if (installerPkgName != null) {
+ mInstallerPackages.add(installerPkgName);
+ }
+ }
+ }
+
+ /** Gets and optionally creates a new shared user id. */
+ SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
+ boolean create) throws PackageManagerException {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s == null && create) {
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
+ s.userId = newUserIdLPw(s);
+ if (s.userId < 0) {
+ // < 0 means we couldn't assign a userid; throw exception
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Creating shared user " + name + " failed");
+ }
+ Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
+ mSharedUsers.put(name, s);
+ }
+ return s;
+ }
+
+ Collection<SharedUserSetting> getAllSharedUsersLPw() {
+ return mSharedUsers.values();
+ }
+
+ boolean disableSystemPackageLPw(String name, boolean replaced) {
+ final PackageSetting p = mPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not an installed package");
+ return false;
+ }
+ final PackageSetting dp = mDisabledSysPackages.get(name);
+ // always make sure the system package code and resource paths dont change
+ if (dp == null && p.pkg != null && p.pkg.isSystemApp() && !p.pkg.isUpdatedSystemApp()) {
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ mDisabledSysPackages.put(name, p);
+
+ if (replaced) {
+ // a little trick... when we install the new package, we don't
+ // want to modify the existing PackageSetting for the built-in
+ // version. so at this point we need a new PackageSetting that
+ // is okay to muck with.
+ PackageSetting newp = new PackageSetting(p);
+ replacePackageLPw(name, newp);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ PackageSetting enableSystemPackageLPw(String name) {
+ PackageSetting p = mDisabledSysPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
+ return null;
+ }
+ // Reset flag in ApplicationInfo object
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
+ p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
+ p.secondaryCpuAbiString, p.cpuAbiOverrideString,
+ p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
+ p.parentPackageName, p.childPackageNames, p.usesStaticLibraries,
+ p.usesStaticLibrariesVersions);
+ mDisabledSysPackages.remove(name);
+ return ret;
+ }
+
+ boolean isDisabledSystemPackageLPr(String name) {
+ return mDisabledSysPackages.containsKey(name);
+ }
+
+ void removeDisabledSystemPackageLPw(String name) {
+ mDisabledSysPackages.remove(name);
+ }
+
+ PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
+ pkgFlags, int pkgPrivateFlags, String parentPackageName,
+ List<String> childPackageNames, String[] usesStaticLibraries,
+ int[] usesStaticLibraryNames) {
+ PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.appId == uid) {
+ return p;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate package, keeping first: " + name);
+ return null;
+ }
+ p = new PackageSetting(name, realName, codePath, resourcePath,
+ legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
+ cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName,
+ childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
+ p.appId = uid;
+ if (addUserIdLPw(uid, p, name)) {
+ mPackages.put(name, p);
+ return p;
+ }
+ return null;
+ }
+
+ SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s != null) {
+ if (s.userId == uid) {
+ return s;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared user, keeping first: " + name);
+ return null;
+ }
+ s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
+ s.userId = uid;
+ if (addUserIdLPw(uid, s, name)) {
+ mSharedUsers.put(name, s);
+ return s;
+ }
+ return null;
+ }
+
+ void pruneSharedUsersLPw() {
+ ArrayList<String> removeStage = new ArrayList<String>();
+ for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) {
+ final SharedUserSetting sus = entry.getValue();
+ if (sus == null) {
+ removeStage.add(entry.getKey());
+ continue;
+ }
+ // remove packages that are no longer installed
+ for (Iterator<PackageSetting> iter = sus.packages.iterator(); iter.hasNext();) {
+ PackageSetting ps = iter.next();
+ if (mPackages.get(ps.name) == null) {
+ iter.remove();
+ }
+ }
+ if (sus.packages.size() == 0) {
+ removeStage.add(entry.getKey());
+ }
+ }
+ for (int i = 0; i < removeStage.size(); i++) {
+ mSharedUsers.remove(removeStage.get(i));
+ }
+ }
+
+ // Transfer ownership of permissions from one package to another.
+ void transferPermissionsLPw(String origPkg, String newPkg) {
+ // Transfer ownership of permissions to the new package.
+ for (int i=0; i<2; i++) {
+ ArrayMap<String, BasePermission> permissions =
+ i == 0 ? mPermissionTrees : mPermissions;
+ for (BasePermission bp : permissions.values()) {
+ if (origPkg.equals(bp.sourcePackage)) {
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
+ "Moving permission " + bp.name
+ + " from pkg " + bp.sourcePackage
+ + " to " + newPkg);
+ bp.sourcePackage = newPkg;
+ bp.packageSetting = null;
+ bp.perm = null;
+ if (bp.pendingInfo != null) {
+ bp.pendingInfo.packageName = newPkg;
+ }
+ bp.uid = 0;
+ bp.setGids(null, false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a new {@code PackageSetting} object.
+ * Use this method instead of the constructor to ensure a settings object is created
+ * with the correct base.
+ */
+ static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
+ PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
+ File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
+ String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
+ UserHandle installUser, boolean allowInstall, boolean instantApp,
+ boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
+ UserManagerService userManager,
+ String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
+ final PackageSetting pkgSetting;
+ if (originalPkg != null) {
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ + pkgName + " is adopting original package " + originalPkg.name);
+ pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
+ pkgSetting.childPackageNames =
+ (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
+ pkgSetting.codePath = codePath;
+ pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
+ pkgSetting.origPackage = originalPkg;
+ pkgSetting.parentPackageName = parentPkgName;
+ pkgSetting.pkgFlags = pkgFlags;
+ pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
+ pkgSetting.primaryCpuAbiString = primaryCpuAbi;
+ pkgSetting.resourcePath = resourcePath;
+ pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
+ // NOTE: Create a deeper copy of the package signatures so we don't
+ // overwrite the signatures in the original package setting.
+ pkgSetting.signatures = new PackageSignatures();
+ pkgSetting.versionCode = versionCode;
+ pkgSetting.usesStaticLibraries = usesStaticLibraries;
+ pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
+ // Update new package state.
+ pkgSetting.setTimeStamp(codePath.lastModified());
+ } else {
+ pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
+ legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
+ null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
+ parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
+ usesStaticLibrariesVersions);
+ pkgSetting.setTimeStamp(codePath.lastModified());
+ pkgSetting.sharedUser = sharedUser;
+ // If this is not a system app, it starts out stopped.
+ if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (DEBUG_STOPPED) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e);
+ }
+ List<UserInfo> users = getAllUsers(userManager);
+ final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
+ if (users != null && allowInstall) {
+ for (UserInfo user : users) {
+ // By default we consider this app to be installed
+ // for the user if no user has been specified (which
+ // means to leave it at its original value, and the
+ // original default value is true), or we are being
+ // asked to install for all users, or this is the
+ // user we are installing for.
+ final boolean installed = installUser == null
+ || (installUserId == UserHandle.USER_ALL
+ && !isAdbInstallDisallowed(userManager, user.id))
+ || installUserId == user.id;
+ pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
+ installed,
+ true /*stopped*/,
+ true /*notLaunched*/,
+ false /*hidden*/,
+ false /*suspended*/,
+ instantApp,
+ virtualPreload,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
+ 0, PackageManager.INSTALL_REASON_UNKNOWN);
+ }
+ }
+ }
+ if (sharedUser != null) {
+ pkgSetting.appId = sharedUser.userId;
+ } else {
+ // Clone the setting here for disabled system packages
+ if (disabledPkg != null) {
+ // For disabled packages a new setting is created
+ // from the existing user id. This still has to be
+ // added to list of user id's
+ // Copy signatures from previous setting
+ pkgSetting.signatures = new PackageSignatures(disabledPkg.signatures);
+ pkgSetting.appId = disabledPkg.appId;
+ // Clone permissions
+ pkgSetting.getPermissionsState().copyFrom(disabledPkg.getPermissionsState());
+ // Clone component info
+ List<UserInfo> users = getAllUsers(userManager);
+ if (users != null) {
+ for (UserInfo user : users) {
+ final int userId = user.id;
+ pkgSetting.setDisabledComponentsCopy(
+ disabledPkg.getDisabledComponents(userId), userId);
+ pkgSetting.setEnabledComponentsCopy(
+ disabledPkg.getEnabledComponents(userId), userId);
+ }
+ }
+ }
+ }
+ }
+ return pkgSetting;
+ }
+
+ /**
+ * Updates the given package setting using the provided information.
+ * <p>
+ * WARNING: The provided PackageSetting object may be mutated.
+ */
+ static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
+ @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
+ @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
+ @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
+ int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
+ @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
+ @Nullable int[] usesStaticLibrariesVersions) throws PackageManagerException {
+ final String pkgName = pkgSetting.name;
+ if (pkgSetting.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + pkgName + " shared user changed from "
+ + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>")
+ + " to " + (sharedUser != null ? sharedUser.name : "<nothing>"));
+ throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Updating application package " + pkgName + " failed");
+ }
+
+ if (!pkgSetting.codePath.equals(codePath)) {
+ // Check to see if its a disabled system app
+ if ((pkgSetting.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ // This is an updated system app with versions in both system
+ // and data partition. Just let the most recent version
+ // take precedence.
+ Slog.w(PackageManagerService.TAG,
+ "Trying to update system app code path from "
+ + pkgSetting.codePathString + " to " + codePath.toString());
+ } else {
+ // Just a change in the code path is not an issue, but
+ // let's log a message about it.
+ Slog.i(PackageManagerService.TAG,
+ "Package " + pkgName + " codePath changed from "
+ + pkgSetting.codePath + " to " + codePath
+ + "; Retaining data and using new");
+
+ // The owner user's installed flag is set false
+ // when the application was installed by other user
+ // and the installed flag is not updated
+ // when the application is appended as system app later.
+ if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
+ && disabledPkg == null) {
+ List<UserInfo> allUserInfos = getAllUsers(userManager);
+ if (allUserInfos != null) {
+ for (UserInfo userInfo : allUserInfos) {
+ pkgSetting.setInstalled(true, userInfo.id);
+ }
+ }
+ }
+
+ /*
+ * Since we've changed paths, we need to prefer the new
+ * native library path over the one stored in the
+ * package settings since we might have moved from
+ * internal to external storage or vice versa.
+ */
+ pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
+ }
+ }
+ // If what we are scanning is a system (and possibly privileged) package,
+ // then make it so, regardless of whether it was previously installed only
+ // in the data partition.
+ pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+ pkgSetting.pkgPrivateFlags |=
+ pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ pkgSetting.primaryCpuAbiString = primaryCpuAbi;
+ pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
+ if (childPkgNames != null) {
+ pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
+ }
+ if (usesStaticLibraries != null) {
+ pkgSetting.usesStaticLibraries = Arrays.copyOf(usesStaticLibraries,
+ usesStaticLibraries.length);
+ }
+ if (usesStaticLibrariesVersions != null) {
+ pkgSetting.usesStaticLibrariesVersions = Arrays.copyOf(usesStaticLibrariesVersions,
+ usesStaticLibrariesVersions.length);
+ }
+ }
+
+ /**
+ * Registers a user ID with the system. Potentially allocates a new user ID.
+ * @throws PackageManagerException If a user ID could not be allocated.
+ */
+ void addUserToSettingLPw(PackageSetting p) throws PackageManagerException {
+ if (p.appId == 0) {
+ // Assign new user ID
+ p.appId = newUserIdLPw(p);
+ } else {
+ // Add new setting to list of user IDs
+ addUserIdLPw(p.appId, p, p.name);
+ }
+ if (p.appId < 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + p.name + " could not be assigned a valid UID");
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Package " + p.name + " could not be assigned a valid UID");
+ }
+ }
+
+ /**
+ * Writes per-user package restrictions if the user state has changed. If the user
+ * state has not changed, this does nothing.
+ */
+ void writeUserRestrictionsLPw(PackageSetting newPackage, PackageSetting oldPackage) {
+ // package doesn't exist; do nothing
+ if (getPackageLPr(newPackage.name) == null) {
+ return;
+ }
+ // no users defined; do nothing
+ final List<UserInfo> allUsers = getAllUsers(UserManagerService.getInstance());
+ if (allUsers == null) {
+ return;
+ }
+ for (UserInfo user : allUsers) {
+ final PackageUserState oldUserState = oldPackage == null
+ ? PackageSettingBase.DEFAULT_USER_STATE
+ : oldPackage.readUserState(user.id);
+ if (!oldUserState.equals(newPackage.readUserState(user.id))) {
+ writePackageRestrictionsLPr(user.id);
+ }
+ }
+ }
+
+ static boolean isAdbInstallDisallowed(UserManagerService userManager, int userId) {
+ return userManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
+ userId);
+ }
+
+ void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+ p.pkg = pkg;
+ // pkg.mSetEnabled = p.getEnabled(userId);
+ // pkg.mSetStopped = p.getStopped(userId);
+ final String volumeUuid = pkg.applicationInfo.volumeUuid;
+ final String codePath = pkg.applicationInfo.getCodePath();
+ final String resourcePath = pkg.applicationInfo.getResourcePath();
+ final String legacyNativeLibraryPath = pkg.applicationInfo.nativeLibraryRootDir;
+ // Update volume if needed
+ if (!Objects.equals(volumeUuid, p.volumeUuid)) {
+ Slog.w(PackageManagerService.TAG, "Volume for " + p.pkg.packageName +
+ " changing from " + p.volumeUuid + " to " + volumeUuid);
+ p.volumeUuid = volumeUuid;
+ }
+ // Update code path if needed
+ if (!Objects.equals(codePath, p.codePathString)) {
+ Slog.w(PackageManagerService.TAG, "Code path for " + p.pkg.packageName +
+ " changing from " + p.codePathString + " to " + codePath);
+ p.codePath = new File(codePath);
+ p.codePathString = codePath;
+ }
+ //Update resource path if needed
+ if (!Objects.equals(resourcePath, p.resourcePathString)) {
+ Slog.w(PackageManagerService.TAG, "Resource path for " + p.pkg.packageName +
+ " changing from " + p.resourcePathString + " to " + resourcePath);
+ p.resourcePath = new File(resourcePath);
+ p.resourcePathString = resourcePath;
+ }
+ // Update the native library paths if needed
+ if (!Objects.equals(legacyNativeLibraryPath, p.legacyNativeLibraryPathString)) {
+ p.legacyNativeLibraryPathString = legacyNativeLibraryPath;
+ }
+
+ // Update the required Cpu Abi
+ p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+ p.cpuAbiOverrideString = pkg.cpuAbiOverride;
+ // Update version code if needed
+ if (pkg.mVersionCode != p.versionCode) {
+ p.versionCode = pkg.mVersionCode;
+ }
+ // Update signatures if needed.
+ if (p.signatures.mSignatures == null) {
+ p.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // Update flags if needed.
+ if (pkg.applicationInfo.flags != p.pkgFlags) {
+ p.pkgFlags = pkg.applicationInfo.flags;
+ }
+ // If this app defines a shared user id initialize
+ // the shared user signatures as well.
+ if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // Update static shared library dependencies if needed
+ if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null
+ && pkg.usesStaticLibraries.size() == pkg.usesStaticLibrariesVersions.length) {
+ p.usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
+ pkg.usesStaticLibraries.toArray(p.usesStaticLibraries);
+ p.usesStaticLibrariesVersions = pkg.usesStaticLibrariesVersions;
+ } else {
+ p.usesStaticLibraries = null;
+ p.usesStaticLibrariesVersions = null;
+ }
+ addPackageSettingLPw(p, p.sharedUser);
+ }
+
+ // Utility method that adds a PackageSetting to mPackages and
+ // completes updating the shared user attributes and any restored
+ // app link verification state
+ private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
+ mPackages.put(p.name, p);
+ if (sharedUser != null) {
+ if (p.sharedUser != null && p.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user "
+ + p.sharedUser + " but is now " + sharedUser
+ + "; I am not changing its files so it will probably fail!");
+ p.sharedUser.removePackage(p);
+ } else if (p.appId != sharedUser.userId) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user id " + p.appId
+ + " but is now user " + sharedUser
+ + " with id " + sharedUser.userId
+ + "; I am not changing its files so it will probably fail!");
+ }
+
+ sharedUser.addPackage(p);
+ p.sharedUser = sharedUser;
+ p.appId = sharedUser.userId;
+ }
+
+ // If the we know about this user id, we have to update it as it
+ // has to point to the same PackageSetting instance as the package.
+ Object userIdPs = getUserIdLPr(p.appId);
+ if (sharedUser == null) {
+ if (userIdPs != null && userIdPs != p) {
+ replaceUserIdLPw(p.appId, p);
+ }
+ } else {
+ if (userIdPs != null && userIdPs != sharedUser) {
+ replaceUserIdLPw(p.appId, sharedUser);
+ }
+ }
+
+ IntentFilterVerificationInfo ivi = mRestoredIntentFilterVerifications.get(p.name);
+ if (ivi != null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Applying restored IVI for " + p.name + " : " + ivi.getStatusString());
+ }
+ mRestoredIntentFilterVerifications.remove(p.name);
+ p.setIntentFilterVerificationInfo(ivi);
+ }
+ }
+
+ /*
+ * Update the shared user setting when a package using
+ * specifying the shared user id is removed. The gids
+ * associated with each permission of the deleted package
+ * are removed from the shared user's gid list only if its
+ * not in use by other permissions of packages in the
+ * shared user setting.
+ */
+ int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(PackageManagerService.TAG,
+ "Trying to update info for null package. Just ignoring");
+ return UserHandle.USER_NULL;
+ }
+
+ // No sharedUserId
+ if (deletedPs.sharedUser == null) {
+ return UserHandle.USER_NULL;
+ }
+
+ SharedUserSetting sus = deletedPs.sharedUser;
+
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+ BasePermission bp = mPermissions.get(eachPerm);
+ if (bp == null) {
+ continue;
+ }
+
+ // Check if another package in the shared user needs the permission.
+ boolean used = false;
+ for (PackageSetting pkg : sus.packages) {
+ if (pkg.pkg != null
+ && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName)
+ && pkg.pkg.requestedPermissions.contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ if (used) {
+ continue;
+ }
+
+ PermissionsState permissionsState = sus.getPermissionsState();
+ PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName);
+
+ // If the package is shadowing is a disabled system package,
+ // do not drop permissions that the shadowed package requests.
+ if (disabledPs != null) {
+ boolean reqByDisabledSysPkg = false;
+ for (String permission : disabledPs.pkg.requestedPermissions) {
+ if (permission.equals(eachPerm)) {
+ reqByDisabledSysPkg = true;
+ break;
+ }
+ }
+ if (reqByDisabledSysPkg) {
+ continue;
+ }
+ }
+
+ // Try to revoke as an install permission which is for all users.
+ // The package is gone - no need to keep flags for applying policy.
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+
+ if (permissionsState.revokeInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ return UserHandle.USER_ALL;
+ }
+
+ // Try to revoke as an install permission which is per user.
+ if (permissionsState.revokeRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ return userId;
+ }
+ }
+
+ return UserHandle.USER_NULL;
+ }
+
+ int removePackageLPw(String name) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ mPackages.remove(name);
+ removeInstallerPackageStatus(name);
+ if (p.sharedUser != null) {
+ p.sharedUser.removePackage(p);
+ if (p.sharedUser.packages.size() == 0) {
+ mSharedUsers.remove(p.sharedUser.name);
+ removeUserIdLPw(p.sharedUser.userId);
+ return p.sharedUser.userId;
+ }
+ } else {
+ removeUserIdLPw(p.appId);
+ return p.appId;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if {@param packageName} is an installer package and if so, clear the installer
+ * package name of the packages that are installed by this.
+ */
+ private void removeInstallerPackageStatus(String packageName) {
+ // Check if the package to be removed is an installer package.
+ if (!mInstallerPackages.contains(packageName)) {
+ return;
+ }
+ for (int i = 0; i < mPackages.size(); i++) {
+ final PackageSetting ps = mPackages.valueAt(i);
+ final String installerPackageName = ps.getInstallerPackageName();
+ if (installerPackageName != null
+ && installerPackageName.equals(packageName)) {
+ ps.setInstallerPackageName(null);
+ ps.isOrphaned = true;
+ }
+ }
+ mInstallerPackages.remove(packageName);
+ }
+
+ private void replacePackageLPw(String name, PackageSetting newp) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.sharedUser != null) {
+ p.sharedUser.removePackage(p);
+ p.sharedUser.addPackage(newp);
+ } else {
+ replaceUserIdLPw(p.appId, newp);
+ }
+ }
+ mPackages.put(name, newp);
+ }
+
+ private boolean addUserIdLPw(int uid, Object obj, Object name) {
+ if (uid > Process.LAST_APPLICATION_UID) {
+ return false;
+ }
+
+ if (uid >= Process.FIRST_APPLICATION_UID) {
+ int N = mUserIds.size();
+ final int index = uid - Process.FIRST_APPLICATION_UID;
+ while (index >= N) {
+ mUserIds.add(null);
+ N++;
+ }
+ if (mUserIds.get(index) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate user id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mUserIds.set(index, obj);
+ } else {
+ if (mOtherUserIds.get(uid) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mOtherUserIds.put(uid, obj);
+ }
+ return true;
+ }
+
+ public Object getUserIdLPr(int uid) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - Process.FIRST_APPLICATION_UID;
+ return index < N ? mUserIds.get(index) : null;
+ } else {
+ return mOtherUserIds.get(uid);
+ }
+ }
+
+ private void removeUserIdLPw(int uid) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - Process.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, null);
+ } else {
+ mOtherUserIds.remove(uid);
+ }
+ setFirstAvailableUid(uid+1);
+ }
+
+ private void replaceUserIdLPw(int uid, Object obj) {
+ if (uid >= Process.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - Process.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, obj);
+ } else {
+ mOtherUserIds.put(uid, obj);
+ }
+ }
+
+ PreferredIntentResolver editPreferredActivitiesLPw(int userId) {
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir == null) {
+ pir = new PreferredIntentResolver();
+ mPreferredActivities.put(userId, pir);
+ }
+ return pir;
+ }
+
+ PersistentPreferredIntentResolver editPersistentPreferredActivitiesLPw(int userId) {
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir == null) {
+ ppir = new PersistentPreferredIntentResolver();
+ mPersistentPreferredActivities.put(userId, ppir);
+ }
+ return ppir;
+ }
+
+ CrossProfileIntentResolver editCrossProfileIntentResolverLPw(int userId) {
+ CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(userId);
+ if (cpir == null) {
+ cpir = new CrossProfileIntentResolver();
+ mCrossProfileIntentResolvers.put(userId, cpir);
+ }
+ return cpir;
+ }
+
+ /**
+ * The following functions suppose that you have a lock for managing access to the
+ * mIntentFiltersVerifications map.
+ */
+
+ /* package protected */
+ IntentFilterVerificationInfo getIntentFilterVerificationLPr(String packageName) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.w(PackageManagerService.TAG, "No package known: " + packageName);
+ }
+ return null;
+ }
+ return ps.getIntentFilterVerificationInfo();
+ }
+
+ /* package protected */
+ IntentFilterVerificationInfo createIntentFilterVerificationIfNeededLPw(String packageName,
+ ArraySet<String> domains) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.w(PackageManagerService.TAG, "No package known: " + packageName);
+ }
+ return null;
+ }
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi == null) {
+ ivi = new IntentFilterVerificationInfo(packageName, domains);
+ ps.setIntentFilterVerificationInfo(ivi);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(PackageManagerService.TAG,
+ "Creating new IntentFilterVerificationInfo for pkg: " + packageName);
+ }
+ } else {
+ ivi.setDomains(domains);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(PackageManagerService.TAG,
+ "Setting domains to existing IntentFilterVerificationInfo for pkg: " +
+ packageName + " and with domains: " + ivi.getDomainsString());
+ }
+ }
+ return ivi;
+ }
+
+ int getIntentFilterVerificationStatusLPr(String packageName, int userId) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.w(PackageManagerService.TAG, "No package known: " + packageName);
+ }
+ return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+ return (int)(ps.getDomainVerificationStatusForUser(userId) >> 32);
+ }
+
+ boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, int userId) {
+ // Update the status for the current package
+ PackageSetting current = mPackages.get(packageName);
+ if (current == null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.w(PackageManagerService.TAG, "No package known: " + packageName);
+ }
+ return false;
+ }
+
+ final int alwaysGeneration;
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+ alwaysGeneration = mNextAppLinkGeneration.get(userId) + 1;
+ mNextAppLinkGeneration.put(userId, alwaysGeneration);
+ } else {
+ alwaysGeneration = 0;
+ }
+
+ current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId);
+ return true;
+ }
+
+ /**
+ * Used for Settings App and PackageManagerService dump. Should be read only.
+ */
+ List<IntentFilterVerificationInfo> getIntentFilterVerificationsLPr(
+ String packageName) {
+ if (packageName == null) {
+ return Collections.<IntentFilterVerificationInfo>emptyList();
+ }
+ ArrayList<IntentFilterVerificationInfo> result = new ArrayList<>();
+ for (PackageSetting ps : mPackages.values()) {
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi == null || TextUtils.isEmpty(ivi.getPackageName()) ||
+ !ivi.getPackageName().equalsIgnoreCase(packageName)) {
+ continue;
+ }
+ result.add(ivi);
+ }
+ return result;
+ }
+
+ boolean removeIntentFilterVerificationLPw(String packageName, int userId) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.w(PackageManagerService.TAG, "No package known: " + packageName);
+ }
+ return false;
+ }
+ ps.clearDomainVerificationStatusForUser(userId);
+ return true;
+ }
+
+ boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) {
+ boolean result = false;
+ for (int userId : userIds) {
+ result |= removeIntentFilterVerificationLPw(packageName, userId);
+ }
+ return result;
+ }
+
+ boolean setDefaultBrowserPackageNameLPw(String packageName, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return false;
+ }
+ if (packageName != null) {
+ mDefaultBrowserApp.put(userId, packageName);
+ } else {
+ mDefaultBrowserApp.remove(userId);
+ }
+ writePackageRestrictionsLPr(userId);
+ return true;
+ }
+
+ String getDefaultBrowserPackageNameLPw(int userId) {
+ return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.get(userId);
+ }
+
+ boolean setDefaultDialerPackageNameLPw(String packageName, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return false;
+ }
+ mDefaultDialerApp.put(userId, packageName);
+ writePackageRestrictionsLPr(userId);
+ return true;
+ }
+
+ String getDefaultDialerPackageNameLPw(int userId) {
+ return (userId == UserHandle.USER_ALL) ? null : mDefaultDialerApp.get(userId);
+ }
+
+ private File getUserPackagesStateFile(int userId) {
+ // TODO: Implement a cleaner solution when adding tests.
+ // This instead of Environment.getUserSystemDirectory(userId) to support testing.
+ File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
+ return new File(userDir, "package-restrictions.xml");
+ }
+
+ private File getUserRuntimePermissionsFile(int userId) {
+ // TODO: Implement a cleaner solution when adding tests.
+ // This instead of Environment.getUserSystemDirectory(userId) to support testing.
+ File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
+ return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
+ }
+
+ private File getUserPackagesStateBackupFile(int userId) {
+ return new File(Environment.getUserSystemDirectory(userId),
+ "package-restrictions-backup.xml");
+ }
+
+ void writeAllUsersPackageRestrictionsLPr() {
+ List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+ if (users == null) return;
+
+ for (UserInfo user : users) {
+ writePackageRestrictionsLPr(user.id);
+ }
+ }
+
+ void writeAllRuntimePermissionsLPr() {
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+ }
+ }
+
+ boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
+ return mRuntimePermissionsPersistence
+ .areDefaultRuntimPermissionsGrantedLPr(userId);
+ }
+
+ void onDefaultRuntimePermissionsGrantedLPr(int userId) {
+ mRuntimePermissionsPersistence
+ .onDefaultRuntimePermissionsGrantedLPr(userId);
+ }
+
+ public VersionInfo findOrCreateVersion(String volumeUuid) {
+ VersionInfo ver = mVersion.get(volumeUuid);
+ if (ver == null) {
+ ver = new VersionInfo();
+ mVersion.put(volumeUuid, ver);
+ }
+ return ver;
+ }
+
+ public VersionInfo getInternalVersion() {
+ return mVersion.get(StorageManager.UUID_PRIVATE_INTERNAL);
+ }
+
+ public VersionInfo getExternalVersion() {
+ return mVersion.get(StorageManager.UUID_PRIMARY_PHYSICAL);
+ }
+
+ public void onVolumeForgotten(String fsUuid) {
+ mVersion.remove(fsUuid);
+ }
+
+ /**
+ * Applies the preferred activity state described by the given XML. This code
+ * also supports the restore-from-backup code path.
+ *
+ * @see PreferredActivityBackupHelper
+ */
+ void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ editPreferredActivitiesLPw(userId).addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private void readPersistentPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ 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;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PersistentPreferredActivity ppa = new PersistentPreferredActivity(parser);
+ editPersistentPreferredActivitiesLPw(userId).addFilter(ppa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <" + TAG_PERSISTENT_PREFERRED_ACTIVITIES + ">: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private void readCrossProfileIntentFiltersLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ 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_ITEM)) {
+ CrossProfileIntentFilter cpif = new CrossProfileIntentFilter(parser);
+ editCrossProfileIntentResolverLPw(userId).addFilter(cpif);
+ } else {
+ String msg = "Unknown element under " + TAG_CROSS_PROFILE_INTENT_FILTERS + ": " +
+ tagName;
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private void readDomainVerificationLPw(XmlPullParser parser, PackageSettingBase packageSetting)
+ throws XmlPullParserException, IOException {
+ IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
+ packageSetting.setIntentFilterVerificationInfo(ivi);
+ if (DEBUG_PARSER) {
+ Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName());
+ }
+ }
+
+ private void readRestoredIntentFilterVerifications(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ 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_DOMAIN_VERIFICATION)) {
+ IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Restored IVI for " + ivi.getPackageName()
+ + " status=" + ivi.getStatusString());
+ }
+ mRestoredIntentFilterVerifications.put(ivi.getPackageName(), ivi);
+ } else {
+ Slog.w(TAG, "Unknown element: " + tagName);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void readDefaultAppsLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ 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;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ mDefaultBrowserApp.put(userId, packageName);
+ } else if (tagName.equals(TAG_DEFAULT_DIALER)) {
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ mDefaultDialerApp.put(userId, packageName);
+ } else {
+ String msg = "Unknown element under " + TAG_DEFAULT_APPS + ": " +
+ parser.getName();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void readBlockUninstallPackagesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ ArraySet<String> packages = new ArraySet<>();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_BLOCK_UNINSTALL)) {
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ packages.add(packageName);
+ } else {
+ String msg = "Unknown element under " + TAG_BLOCK_UNINSTALL_PACKAGES + ": " +
+ parser.getName();
+ PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ if (packages.isEmpty()) {
+ mBlockUninstallPackages.remove(userId);
+ } else {
+ mBlockUninstallPackages.put(userId, packages);
+ }
+ }
+
+ void readPackageRestrictionsLPr(int userId) {
+ if (DEBUG_MU) {
+ Log.i(TAG, "Reading package restrictions for user=" + userId);
+ }
+ FileInputStream str = null;
+ File userPackagesStateFile = getUserPackagesStateFile(userId);
+ File backupFile = getUserPackagesStateBackupFile(userId);
+ if (backupFile.exists()) {
+ try {
+ str = new FileInputStream(backupFile);
+ mReadMessages.append("Reading from backup stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "Need to read from backup stopped packages file");
+ if (userPackagesStateFile.exists()) {
+ // If both the backup and normal file exist, we
+ // ignore the normal one since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
+ + userPackagesStateFile);
+ userPackagesStateFile.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ try {
+ if (str == null) {
+ if (!userPackagesStateFile.exists()) {
+ mReadMessages.append("No stopped packages file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "No stopped packages file; "
+ + "assuming all started");
+ // At first boot, make sure no packages are stopped.
+ // We usually want to have third party apps initialize
+ // in the stopped state, but not at first boot. Also
+ // consider all applications to be installed.
+ for (PackageSetting pkg : mPackages.values()) {
+ pkg.setUserState(userId, 0, COMPONENT_ENABLED_STATE_DEFAULT,
+ true /*installed*/,
+ false /*stopped*/,
+ false /*notLaunched*/,
+ false /*hidden*/,
+ false /*suspended*/,
+ false /*instantApp*/,
+ false /*virtualPreload*/,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
+ 0, PackageManager.INSTALL_REASON_UNKNOWN);
+ }
+ return;
+ }
+ str = new FileInputStream(userPackagesStateFile);
+ }
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in package restrictions file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager stopped packages");
+ return;
+ }
+
+ int maxAppLinkGeneration = 0;
+
+ int outerDepth = parser.getDepth();
+ PackageSetting ps = null;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_PACKAGE)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ ps = mPackages.get(name);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for stopped package "
+ + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ final long ceDataInode = XmlUtils.readLongAttribute(parser, ATTR_CE_DATA_INODE,
+ 0);
+ final boolean installed = XmlUtils.readBooleanAttribute(parser, ATTR_INSTALLED,
+ true);
+ final boolean stopped = XmlUtils.readBooleanAttribute(parser, ATTR_STOPPED,
+ false);
+ final boolean notLaunched = XmlUtils.readBooleanAttribute(parser,
+ ATTR_NOT_LAUNCHED, false);
+
+ // For backwards compatibility with the previous name of "blocked", which
+ // now means hidden, read the old attribute as well.
+ final String blockedStr = parser.getAttributeValue(null, ATTR_BLOCKED);
+ boolean hidden = blockedStr == null
+ ? false : Boolean.parseBoolean(blockedStr);
+ final String hiddenStr = parser.getAttributeValue(null, ATTR_HIDDEN);
+ hidden = hiddenStr == null
+ ? hidden : Boolean.parseBoolean(hiddenStr);
+
+ final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
+ false);
+ final boolean blockUninstall = XmlUtils.readBooleanAttribute(parser,
+ ATTR_BLOCK_UNINSTALL, false);
+ final boolean instantApp = XmlUtils.readBooleanAttribute(parser,
+ ATTR_INSTANT_APP, false);
+ final boolean virtualPreload = XmlUtils.readBooleanAttribute(parser,
+ ATTR_VIRTUAL_PRELOAD, false);
+ final int enabled = XmlUtils.readIntAttribute(parser, ATTR_ENABLED,
+ COMPONENT_ENABLED_STATE_DEFAULT);
+ final String enabledCaller = parser.getAttributeValue(null,
+ ATTR_ENABLED_CALLER);
+
+ final int verifState = XmlUtils.readIntAttribute(parser,
+ ATTR_DOMAIN_VERIFICATON_STATE,
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+ final int linkGeneration = XmlUtils.readIntAttribute(parser,
+ ATTR_APP_LINK_GENERATION, 0);
+ if (linkGeneration > maxAppLinkGeneration) {
+ maxAppLinkGeneration = linkGeneration;
+ }
+ final int installReason = XmlUtils.readIntAttribute(parser,
+ ATTR_INSTALL_REASON, PackageManager.INSTALL_REASON_UNKNOWN);
+
+ ArraySet<String> enabledComponents = null;
+ ArraySet<String> disabledComponents = null;
+
+ int packageDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > packageDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ tagName = parser.getName();
+ if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
+ enabledComponents = readComponentsLPr(parser);
+ } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
+ disabledComponents = readComponentsLPr(parser);
+ }
+ }
+
+ if (blockUninstall) {
+ setBlockUninstallLPw(userId, name, true);
+ }
+ ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
+ hidden, suspended, instantApp, virtualPreload, enabledCaller,
+ enabledComponents, disabledComponents, verifState, linkGeneration,
+ installReason);
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser, userId);
+ } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
+ readPersistentPreferredActivitiesLPw(parser, userId);
+ } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
+ readCrossProfileIntentFiltersLPw(parser, userId);
+ } else if (tagName.equals(TAG_DEFAULT_APPS)) {
+ readDefaultAppsLPw(parser, userId);
+ } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) {
+ readBlockUninstallPackagesLPw(parser, userId);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1);
+
+ } catch (XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Error reading stopped packages: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
+ e);
+
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
+ e);
+ }
+ }
+
+ void setBlockUninstallLPw(int userId, String packageName, boolean blockUninstall) {
+ ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+ if (blockUninstall) {
+ if (packages == null) {
+ packages = new ArraySet<String>();
+ mBlockUninstallPackages.put(userId, packages);
+ }
+ packages.add(packageName);
+ } else if (packages != null) {
+ packages.remove(packageName);
+ if (packages.isEmpty()) {
+ mBlockUninstallPackages.remove(userId);
+ }
+ }
+ }
+
+ boolean getBlockUninstallLPr(int userId, String packageName) {
+ ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+ if (packages == null) {
+ return false;
+ }
+ return packages.contains(packageName);
+ }
+
+ private ArraySet<String> readComponentsLPr(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ ArraySet<String> components = null;
+ int type;
+ int outerDepth = parser.getDepth();
+ String tagName;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ String componentName = parser.getAttributeValue(null, ATTR_NAME);
+ if (componentName != null) {
+ if (components == null) {
+ components = new ArraySet<String>();
+ }
+ components.add(componentName);
+ }
+ }
+ }
+ return components;
+ }
+
+ /**
+ * Record the state of preferred activity configuration into XML. This is used both
+ * for recording packages.xml internally and for supporting backup/restore of the
+ * preferred activity configuration.
+ */
+ void writePreferredActivitiesLPr(XmlSerializer serializer, int userId, boolean full)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "preferred-activities");
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir != null) {
+ for (final PreferredActivity pa : pir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ pa.writeToXml(serializer, full);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "preferred-activities");
+ }
+
+ void writePersistentPreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir != null) {
+ for (final PersistentPreferredActivity ppa : ppir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ ppa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
+ }
+
+ void writeCrossProfileIntentFiltersLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
+ CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(userId);
+ if (cpir != null) {
+ for (final CrossProfileIntentFilter cpif : cpir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ cpif.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
+ }
+
+ void writeDomainVerificationsLPr(XmlSerializer serializer,
+ IntentFilterVerificationInfo verificationInfo)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ if (verificationInfo != null && verificationInfo.getPackageName() != null) {
+ serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
+ verificationInfo.writeToXml(serializer);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Wrote domain verification for package: "
+ + verificationInfo.getPackageName());
+ }
+ serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+ }
+ }
+
+ // Specifically for backup/restore
+ void writeAllDomainVerificationsLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_ALL_INTENT_FILTER_VERIFICATION);
+ final int N = mPackages.size();
+ for (int i = 0; i < N; i++) {
+ PackageSetting ps = mPackages.valueAt(i);
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi != null) {
+ writeDomainVerificationsLPr(serializer, ivi);
+ }
+ }
+ serializer.endTag(null, TAG_ALL_INTENT_FILTER_VERIFICATION);
+ }
+
+ // Specifically for backup/restore
+ void readAllDomainVerificationsLPr(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ mRestoredIntentFilterVerifications.clear();
+
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
+ IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
+ final String pkgName = ivi.getPackageName();
+ final PackageSetting ps = mPackages.get(pkgName);
+ if (ps != null) {
+ // known/existing package; update in place
+ ps.setIntentFilterVerificationInfo(ivi);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Restored IVI for existing app " + pkgName
+ + " status=" + ivi.getStatusString());
+ }
+ } else {
+ mRestoredIntentFilterVerifications.put(pkgName, ivi);
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Restored IVI for pending app " + pkgName
+ + " status=" + ivi.getStatusString());
+ }
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <all-intent-filter-verification>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ // Specifically for backup/restore
+ public void processRestoredPermissionGrantLPr(String pkgName, String permission,
+ boolean isGranted, int restoredFlagSet, int userId)
+ throws IOException, XmlPullParserException {
+ mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
+ pkgName, permission, isGranted, restoredFlagSet, userId);
+ }
+
+ void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, TAG_DEFAULT_APPS);
+ String defaultBrowser = mDefaultBrowserApp.get(userId);
+ if (!TextUtils.isEmpty(defaultBrowser)) {
+ serializer.startTag(null, TAG_DEFAULT_BROWSER);
+ serializer.attribute(null, ATTR_PACKAGE_NAME, defaultBrowser);
+ serializer.endTag(null, TAG_DEFAULT_BROWSER);
+ }
+ String defaultDialer = mDefaultDialerApp.get(userId);
+ if (!TextUtils.isEmpty(defaultDialer)) {
+ serializer.startTag(null, TAG_DEFAULT_DIALER);
+ serializer.attribute(null, ATTR_PACKAGE_NAME, defaultDialer);
+ serializer.endTag(null, TAG_DEFAULT_DIALER);
+ }
+ serializer.endTag(null, TAG_DEFAULT_APPS);
+ }
+
+ void writeBlockUninstallPackagesLPr(XmlSerializer serializer, int userId)
+ throws IOException {
+ ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+ if (packages != null) {
+ serializer.startTag(null, TAG_BLOCK_UNINSTALL_PACKAGES);
+ for (int i = 0; i < packages.size(); i++) {
+ serializer.startTag(null, TAG_BLOCK_UNINSTALL);
+ serializer.attribute(null, ATTR_PACKAGE_NAME, packages.valueAt(i));
+ serializer.endTag(null, TAG_BLOCK_UNINSTALL);
+ }
+ serializer.endTag(null, TAG_BLOCK_UNINSTALL_PACKAGES);
+ }
+ }
+
+ void writePackageRestrictionsLPr(int userId) {
+ if (DEBUG_MU) {
+ Log.i(TAG, "Writing package restrictions for user=" + userId);
+ }
+ // Keep the old stopped packages around until we know the new ones have
+ // been successfully written.
+ File userPackagesStateFile = getUserPackagesStateFile(userId);
+ File backupFile = getUserPackagesStateBackupFile(userId);
+ new File(userPackagesStateFile.getParent()).mkdirs();
+ if (userPackagesStateFile.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist packages earlier. So preserve the older
+ // backup for future reference since the current packages
+ // might have been corrupted.
+ if (!backupFile.exists()) {
+ if (!userPackagesStateFile.renameTo(backupFile)) {
+ Slog.wtf(PackageManagerService.TAG,
+ "Unable to backup user packages state file, "
+ + "current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ userPackagesStateFile.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
+ }
+ }
+
+ try {
+ final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
+ final BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ final PackageUserState ustate = pkg.readUserState(userId);
+ if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
+
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, pkg.name);
+ if (ustate.ceDataInode != 0) {
+ XmlUtils.writeLongAttribute(serializer, ATTR_CE_DATA_INODE, ustate.ceDataInode);
+ }
+ if (!ustate.installed) {
+ serializer.attribute(null, ATTR_INSTALLED, "false");
+ }
+ if (ustate.stopped) {
+ serializer.attribute(null, ATTR_STOPPED, "true");
+ }
+ if (ustate.notLaunched) {
+ serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
+ }
+ if (ustate.hidden) {
+ serializer.attribute(null, ATTR_HIDDEN, "true");
+ }
+ if (ustate.suspended) {
+ serializer.attribute(null, ATTR_SUSPENDED, "true");
+ }
+ if (ustate.instantApp) {
+ serializer.attribute(null, ATTR_INSTANT_APP, "true");
+ }
+ if (ustate.virtualPreload) {
+ serializer.attribute(null, ATTR_VIRTUAL_PRELOAD, "true");
+ }
+ if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attribute(null, ATTR_ENABLED,
+ Integer.toString(ustate.enabled));
+ if (ustate.lastDisableAppCaller != null) {
+ serializer.attribute(null, ATTR_ENABLED_CALLER,
+ ustate.lastDisableAppCaller);
+ }
+ }
+ if (ustate.domainVerificationStatus !=
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ XmlUtils.writeIntAttribute(serializer, ATTR_DOMAIN_VERIFICATON_STATE,
+ ustate.domainVerificationStatus);
+ }
+ if (ustate.appLinkGeneration != 0) {
+ XmlUtils.writeIntAttribute(serializer, ATTR_APP_LINK_GENERATION,
+ ustate.appLinkGeneration);
+ }
+ if (ustate.installReason != PackageManager.INSTALL_REASON_UNKNOWN) {
+ serializer.attribute(null, ATTR_INSTALL_REASON,
+ Integer.toString(ustate.installReason));
+ }
+ if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
+ serializer.startTag(null, TAG_ENABLED_COMPONENTS);
+ for (final String name : ustate.enabledComponents) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_ENABLED_COMPONENTS);
+ }
+ if (!ArrayUtils.isEmpty(ustate.disabledComponents)) {
+ serializer.startTag(null, TAG_DISABLED_COMPONENTS);
+ for (final String name : ustate.disabledComponents) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, name);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_DISABLED_COMPONENTS);
+ }
+
+ serializer.endTag(null, TAG_PACKAGE);
+ }
+
+ writePreferredActivitiesLPr(serializer, userId, true);
+ writePersistentPreferredActivitiesLPr(serializer, userId);
+ writeCrossProfileIntentFiltersLPr(serializer, userId);
+ writeDefaultAppsLPr(serializer, userId);
+ writeBlockUninstallPackagesLPr(serializer, userId);
+
+ serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ backupFile.delete();
+ FileUtils.setPermissions(userPackagesStateFile.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
+ -1, -1);
+
+ // Done, all is good!
+ return;
+ } catch(java.io.IOException e) {
+ Slog.wtf(PackageManagerService.TAG,
+ "Unable to write package manager user packages state, "
+ + " current changes will be lost at reboot", e);
+ }
+
+ // Clean up partially written files
+ if (userPackagesStateFile.exists()) {
+ if (!userPackagesStateFile.delete()) {
+ Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
+ + mStoppedPackagesFilename);
+ }
+ }
+ }
+
+ void readInstallPermissionsLPr(XmlPullParser parser,
+ PermissionsState permissionsState) throws IOException, XmlPullParserException {
+ 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;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+
+ BasePermission bp = mPermissions.get(name);
+ if (bp == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown permission: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
+ final boolean granted = grantedStr == null
+ || Boolean.parseBoolean(grantedStr);
+
+ String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
+ final int flags = (flagsStr != null)
+ ? Integer.parseInt(flagsStr, 16) : 0;
+
+ if (granted) {
+ if (permissionsState.grantInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
+ } else {
+ if (permissionsState.revokeInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void writePermissionsLPr(XmlSerializer serializer, List<PermissionState> permissionStates)
+ throws IOException {
+ if (permissionStates.isEmpty()) {
+ return;
+ }
+
+ serializer.startTag(null, TAG_PERMISSIONS);
+
+ for (PermissionState permissionState : permissionStates) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, permissionState.getName());
+ serializer.attribute(null, ATTR_GRANTED, String.valueOf(permissionState.isGranted()));
+ serializer.attribute(null, ATTR_FLAGS, Integer.toHexString(permissionState.getFlags()));
+ serializer.endTag(null, TAG_ITEM);
+ }
+
+ serializer.endTag(null, TAG_PERMISSIONS);
+ }
+
+ void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames)
+ throws IOException {
+ if (childPackageNames == null) {
+ return;
+ }
+ final int childCount = childPackageNames.size();
+ for (int i = 0; i < childCount; i++) {
+ String childPackageName = childPackageNames.get(i);
+ serializer.startTag(null, TAG_CHILD_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, childPackageName);
+ serializer.endTag(null, TAG_CHILD_PACKAGE);
+ }
+ }
+
+ void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
+ throws IOException, XmlPullParserException {
+ 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;
+ }
+ String libName = parser.getAttributeValue(null, ATTR_NAME);
+ String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
+
+ int libVersion = -1;
+ try {
+ libVersion = Integer.parseInt(libVersionStr);
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+
+ if (libName != null && libVersion >= 0) {
+ outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
+ outPs.usesStaticLibraries, libName);
+ outPs.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+ outPs.usesStaticLibrariesVersions, libVersion);
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries,
+ int[] usesStaticLibraryVersions) throws IOException {
+ if (ArrayUtils.isEmpty(usesStaticLibraries) || ArrayUtils.isEmpty(usesStaticLibraryVersions)
+ || usesStaticLibraries.length != usesStaticLibraryVersions.length) {
+ return;
+ }
+ final int libCount = usesStaticLibraries.length;
+ for (int i = 0; i < libCount; i++) {
+ final String libName = usesStaticLibraries[i];
+ final int libVersion = usesStaticLibraryVersions[i];
+ serializer.startTag(null, TAG_USES_STATIC_LIB);
+ serializer.attribute(null, ATTR_NAME, libName);
+ serializer.attribute(null, ATTR_VERSION, Integer.toString(libVersion));
+ serializer.endTag(null, TAG_USES_STATIC_LIB);
+ }
+ }
+
+ // Note: assumed "stopped" field is already cleared in all packages.
+ // Legacy reader, used to read in the old file format after an upgrade. Not used after that.
+ void readStoppedLPw() {
+ FileInputStream str = null;
+ if (mBackupStoppedPackagesFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupStoppedPackagesFilename);
+ mReadMessages.append("Reading from backup stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "Need to read from backup stopped packages file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and normal file exist, we
+ // ignore the normal one since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
+ + mStoppedPackagesFilename);
+ mStoppedPackagesFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ try {
+ if (str == null) {
+ if (!mStoppedPackagesFilename.exists()) {
+ mReadMessages.append("No stopped packages file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "No stopped packages file file; assuming all started");
+ // At first boot, make sure no packages are stopped.
+ // We usually want to have third party apps initialize
+ // in the stopped state, but not at first boot.
+ for (PackageSetting pkg : mPackages.values()) {
+ pkg.setStopped(false, 0);
+ pkg.setNotLaunched(false, 0);
+ }
+ return;
+ }
+ str = new FileInputStream(mStoppedPackagesFilename);
+ }
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager stopped packages");
+ return;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_PACKAGE)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ PackageSetting ps = mPackages.get(name);
+ if (ps != null) {
+ ps.setStopped(true, 0);
+ if ("1".equals(parser.getAttributeValue(null, ATTR_NOT_LAUNCHED))) {
+ ps.setNotLaunched(true, 0);
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG,
+ "No package known for stopped package " + name);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch (XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Error reading stopped packages: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
+ e);
+
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages",
+ e);
+
+ }
+ }
+
+ void writeLPr() {
+ //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
+
+ // Keep the old settings around until we know the new ones have
+ // been successfully written.
+ if (mSettingsFilename.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist settings earlier. So preserve the older
+ // backup for future reference since the current settings
+ // might have been corrupted.
+ if (!mBackupSettingsFilename.exists()) {
+ if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
+ Slog.wtf(PackageManagerService.TAG,
+ "Unable to backup package manager settings, "
+ + " current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ mSettingsFilename.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
+ }
+ }
+
+ mPastSignatures.clear();
+
+ try {
+ FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
+ BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ //XmlSerializer serializer = XmlUtils.serializerInstance();
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, "packages");
+
+ for (int i = 0; i < mVersion.size(); i++) {
+ final String volumeUuid = mVersion.keyAt(i);
+ final VersionInfo ver = mVersion.valueAt(i);
+
+ serializer.startTag(null, TAG_VERSION);
+ XmlUtils.writeStringAttribute(serializer, ATTR_VOLUME_UUID, volumeUuid);
+ XmlUtils.writeIntAttribute(serializer, ATTR_SDK_VERSION, ver.sdkVersion);
+ XmlUtils.writeIntAttribute(serializer, ATTR_DATABASE_VERSION, ver.databaseVersion);
+ XmlUtils.writeStringAttribute(serializer, ATTR_FINGERPRINT, ver.fingerprint);
+ serializer.endTag(null, TAG_VERSION);
+ }
+
+ if (mVerifierDeviceIdentity != null) {
+ serializer.startTag(null, "verifier");
+ serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
+ serializer.endTag(null, "verifier");
+ }
+
+ if (mReadExternalStorageEnforced != null) {
+ serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
+ serializer.attribute(
+ null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
+ serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
+ }
+
+ serializer.startTag(null, "permission-trees");
+ for (BasePermission bp : mPermissionTrees.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permission-trees");
+
+ serializer.startTag(null, "permissions");
+ for (BasePermission bp : mPermissions.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permissions");
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ writePackageLPr(serializer, pkg);
+ }
+
+ for (final PackageSetting pkg : mDisabledSysPackages.values()) {
+ writeDisabledSysPackageLPr(serializer, pkg);
+ }
+
+ for (final SharedUserSetting usr : mSharedUsers.values()) {
+ serializer.startTag(null, "shared-user");
+ serializer.attribute(null, ATTR_NAME, usr.name);
+ serializer.attribute(null, "userId",
+ Integer.toString(usr.userId));
+ usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ writePermissionsLPr(serializer, usr.getPermissionsState()
+ .getInstallPermissionStates());
+ serializer.endTag(null, "shared-user");
+ }
+
+ if (mPackagesToBeCleaned.size() > 0) {
+ for (PackageCleanItem item : mPackagesToBeCleaned) {
+ final String userStr = Integer.toString(item.userId);
+ serializer.startTag(null, "cleaning-package");
+ serializer.attribute(null, ATTR_NAME, item.packageName);
+ serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
+ serializer.attribute(null, ATTR_USER, userStr);
+ serializer.endTag(null, "cleaning-package");
+ }
+ }
+
+ if (mRenamedPackages.size() > 0) {
+ for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ serializer.startTag(null, "renamed-package");
+ serializer.attribute(null, "new", e.getKey());
+ serializer.attribute(null, "old", e.getValue());
+ serializer.endTag(null, "renamed-package");
+ }
+ }
+
+ final int numIVIs = mRestoredIntentFilterVerifications.size();
+ if (numIVIs > 0) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, "Writing restored-ivi entries to packages.xml");
+ }
+ serializer.startTag(null, "restored-ivi");
+ for (int i = 0; i < numIVIs; i++) {
+ IntentFilterVerificationInfo ivi = mRestoredIntentFilterVerifications.valueAt(i);
+ writeDomainVerificationsLPr(serializer, ivi);
+ }
+ serializer.endTag(null, "restored-ivi");
+ } else {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, " no restored IVI entries to write");
+ }
+ }
+
+ mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
+
+ serializer.endTag(null, "packages");
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ mBackupSettingsFilename.delete();
+ FileUtils.setPermissions(mSettingsFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
+ -1, -1);
+
+ writeKernelMappingLPr();
+ writePackageListLPr();
+ writeAllUsersPackageRestrictionsLPr();
+ writeAllRuntimePermissionsLPr();
+ return;
+
+ } catch(XmlPullParserException e) {
+ Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ } catch(java.io.IOException e) {
+ Slog.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ }
+ // Clean up partially written files
+ if (mSettingsFilename.exists()) {
+ if (!mSettingsFilename.delete()) {
+ Slog.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: "
+ + mSettingsFilename);
+ }
+ }
+ //Debug.stopMethodTracing();
+ }
+
+ private void writeKernelRemoveUserLPr(int userId) {
+ if (mKernelMappingFilename == null) return;
+
+ File removeUserIdFile = new File(mKernelMappingFilename, "remove_userid");
+ if (DEBUG_KERNEL) Slog.d(TAG, "Writing " + userId + " to " + removeUserIdFile
+ .getAbsolutePath());
+ writeIntToFile(removeUserIdFile, userId);
+ }
+
+ void writeKernelMappingLPr() {
+ if (mKernelMappingFilename == null) return;
+
+ final String[] known = mKernelMappingFilename.list();
+ final ArraySet<String> knownSet = new ArraySet<>(known.length);
+ for (String name : known) {
+ knownSet.add(name);
+ }
+
+ for (final PackageSetting ps : mPackages.values()) {
+ // Package is actively claimed
+ knownSet.remove(ps.name);
+ writeKernelMappingLPr(ps);
+ }
+
+ // Remove any unclaimed mappings
+ for (int i = 0; i < knownSet.size(); i++) {
+ final String name = knownSet.valueAt(i);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Dropping mapping " + name);
+
+ mKernelMapping.remove(name);
+ new File(mKernelMappingFilename, name).delete();
+ }
+ }
+
+ void writeKernelMappingLPr(PackageSetting ps) {
+ if (mKernelMappingFilename == null || ps == null || ps.name == null) return;
+
+ KernelPackageState cur = mKernelMapping.get(ps.name);
+ final boolean firstTime = cur == null;
+ int[] excludedUserIds = ps.getNotInstalledUserIds();
+ final boolean userIdsChanged = firstTime
+ || !Arrays.equals(excludedUserIds, cur.excludedUserIds);
+
+ // Package directory
+ final File dir = new File(mKernelMappingFilename, ps.name);
+
+ if (firstTime) {
+ dir.mkdir();
+ // Create a new mapping state
+ cur = new KernelPackageState();
+ mKernelMapping.put(ps.name, cur);
+ }
+
+ // If mapping is incorrect or non-existent, write the appid file
+ if (cur.appId != ps.appId) {
+ final File appIdFile = new File(dir, "appid");
+ writeIntToFile(appIdFile, ps.appId);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Mapping " + ps.name + " to " + ps.appId);
+ }
+
+ if (userIdsChanged) {
+ // Build the exclusion list -- the ids to add to the exclusion list
+ for (int i = 0; i < excludedUserIds.length; i++) {
+ if (cur.excludedUserIds == null || !ArrayUtils.contains(cur.excludedUserIds,
+ excludedUserIds[i])) {
+ writeIntToFile(new File(dir, "excluded_userids"), excludedUserIds[i]);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Writing " + excludedUserIds[i] + " to "
+ + ps.name + "/excluded_userids");
+ }
+ }
+ // Build the inclusion list -- the ids to remove from the exclusion list
+ if (cur.excludedUserIds != null) {
+ for (int i = 0; i < cur.excludedUserIds.length; i++) {
+ if (!ArrayUtils.contains(excludedUserIds, cur.excludedUserIds[i])) {
+ writeIntToFile(new File(dir, "clear_userid"),
+ cur.excludedUserIds[i]);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Writing " + cur.excludedUserIds[i] + " to "
+ + ps.name + "/clear_userid");
+
+ }
+ }
+ }
+ cur.excludedUserIds = excludedUserIds;
+ }
+ }
+
+ private void writeIntToFile(File file, int value) {
+ try {
+ FileUtils.bytesToFile(file.getAbsolutePath(),
+ Integer.toString(value).getBytes(StandardCharsets.US_ASCII));
+ } catch (IOException ignored) {
+ Slog.w(TAG, "Couldn't write " + value + " to " + file.getAbsolutePath());
+ }
+ }
+
+ void writePackageListLPr() {
+ writePackageListLPr(-1);
+ }
+
+ void writePackageListLPr(int creatingUserId) {
+ // Only derive GIDs for active users (not dying)
+ final List<UserInfo> users = UserManagerService.getInstance().getUsers(true);
+ int[] userIds = new int[users.size()];
+ for (int i = 0; i < userIds.length; i++) {
+ userIds[i] = users.get(i).id;
+ }
+ if (creatingUserId != -1) {
+ userIds = ArrayUtils.appendInt(userIds, creatingUserId);
+ }
+
+ // Write package list file now, use a JournaledFile.
+ File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp");
+ JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+ final File writeTarget = journal.chooseForWrite();
+ FileOutputStream fstr;
+ BufferedWriter writer = null;
+ try {
+ fstr = new FileOutputStream(writeTarget);
+ writer = new BufferedWriter(new OutputStreamWriter(fstr, Charset.defaultCharset()));
+ FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+
+ StringBuilder sb = new StringBuilder();
+ for (final PackageSetting pkg : mPackages.values()) {
+ if (pkg.pkg == null || pkg.pkg.applicationInfo == null
+ || pkg.pkg.applicationInfo.dataDir == null) {
+ if (!"android".equals(pkg.name)) {
+ Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ }
+ continue;
+ }
+
+ final ApplicationInfo ai = pkg.pkg.applicationInfo;
+ final String dataPath = ai.dataDir;
+ final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ final int[] gids = pkg.getPermissionsState().computeGids(userIds);
+
+ // Avoid any application that has a space in its path.
+ if (dataPath.indexOf(' ') >= 0)
+ continue;
+
+ // we store on each line the following information for now:
+ //
+ // pkgName - package name
+ // userId - application-specific user id
+ // debugFlag - 0 or 1 if the package is debuggable.
+ // dataPath - path to package's data path
+ // seinfo - seinfo label for the app (assigned at install time)
+ // gids - supplementary gids this app launches with
+ //
+ // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+ //
+ // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+ // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+ // frameworks/base/libs/packagelistparser
+ // system/core/run-as/run-as.c
+ //
+ sb.setLength(0);
+ sb.append(ai.packageName);
+ sb.append(" ");
+ sb.append(ai.uid);
+ sb.append(isDebug ? " 1 " : " 0 ");
+ sb.append(dataPath);
+ sb.append(" ");
+ sb.append(ai.seInfo);
+ sb.append(" ");
+ if (gids != null && gids.length > 0) {
+ sb.append(gids[0]);
+ for (int i = 1; i < gids.length; i++) {
+ sb.append(",");
+ sb.append(gids[i]);
+ }
+ } else {
+ sb.append("none");
+ }
+ sb.append("\n");
+ writer.append(sb);
+ }
+ writer.flush();
+ FileUtils.sync(fstr);
+ writer.close();
+ journal.commit();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed to write packages.list", e);
+ IoUtils.closeQuietly(writer);
+ journal.rollback();
+ }
+ }
+
+ void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "updated-package");
+ serializer.attribute(null, ATTR_NAME, pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.legacyNativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
+ }
+ if (pkg.primaryCpuAbiString != null) {
+ serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);
+ }
+ if (pkg.secondaryCpuAbiString != null) {
+ serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString);
+ }
+ if (pkg.cpuAbiOverrideString != null) {
+ serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
+ }
+
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.appId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
+ }
+
+ if (pkg.parentPackageName != null) {
+ serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
+ }
+
+ writeChildPackagesLPw(serializer, pkg.childPackageNames);
+
+ writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+
+ // If this is a shared user, the permissions will be written there.
+ if (pkg.sharedUser == null) {
+ writePermissionsLPr(serializer, pkg.getPermissionsState()
+ .getInstallPermissionStates());
+ }
+
+ serializer.endTag(null, "updated-package");
+ }
+
+ void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "package");
+ serializer.attribute(null, ATTR_NAME, pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+
+ if (pkg.legacyNativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
+ }
+ if (pkg.primaryCpuAbiString != null) {
+ serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);
+ }
+ if (pkg.secondaryCpuAbiString != null) {
+ serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString);
+ }
+ if (pkg.cpuAbiOverrideString != null) {
+ serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
+ }
+
+ serializer.attribute(null, "publicFlags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "privateFlags", Integer.toString(pkg.pkgPrivateFlags));
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.appId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
+ }
+ if (pkg.uidError) {
+ serializer.attribute(null, "uidError", "true");
+ }
+ if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ serializer.attribute(null, "installStatus", "false");
+ }
+ if (pkg.installerPackageName != null) {
+ serializer.attribute(null, "installer", pkg.installerPackageName);
+ }
+ if (pkg.isOrphaned) {
+ serializer.attribute(null, "isOrphaned", "true");
+ }
+ if (pkg.volumeUuid != null) {
+ serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
+ }
+ if (pkg.categoryHint != ApplicationInfo.CATEGORY_UNDEFINED) {
+ serializer.attribute(null, "categoryHint",
+ Integer.toString(pkg.categoryHint));
+ }
+ if (pkg.parentPackageName != null) {
+ serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
+ }
+ if (pkg.updateAvailable) {
+ serializer.attribute(null, "updateAvailable", "true");
+ }
+
+ writeChildPackagesLPw(serializer, pkg.childPackageNames);
+
+ writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+
+ pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
+
+ writePermissionsLPr(serializer, pkg.getPermissionsState()
+ .getInstallPermissionStates());
+
+ writeSigningKeySetLPr(serializer, pkg.keySetData);
+ writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
+ writeKeySetAliasesLPr(serializer, pkg.keySetData);
+ writeDomainVerificationsLPr(serializer, pkg.verificationInfo);
+
+ serializer.endTag(null, "package");
+ }
+
+ void writeSigningKeySetLPr(XmlSerializer serializer,
+ PackageKeySetData data) throws IOException {
+ serializer.startTag(null, "proper-signing-keyset");
+ serializer.attribute(null, "identifier",
+ Long.toString(data.getProperSigningKeySet()));
+ serializer.endTag(null, "proper-signing-keyset");
+ }
+
+ void writeUpgradeKeySetsLPr(XmlSerializer serializer,
+ PackageKeySetData data) throws IOException {
+ long properSigning = data.getProperSigningKeySet();
+ if (data.isUsingUpgradeKeySets()) {
+ for (long id : data.getUpgradeKeySets()) {
+ serializer.startTag(null, "upgrade-keyset");
+ serializer.attribute(null, "identifier", Long.toString(id));
+ serializer.endTag(null, "upgrade-keyset");
+ }
+ }
+ }
+
+ void writeKeySetAliasesLPr(XmlSerializer serializer,
+ PackageKeySetData data) throws IOException {
+ for (Map.Entry<String, Long> e: data.getAliases().entrySet()) {
+ serializer.startTag(null, "defined-keyset");
+ serializer.attribute(null, "alias", e.getKey());
+ serializer.attribute(null, "identifier", Long.toString(e.getValue()));
+ serializer.endTag(null, "defined-keyset");
+ }
+ }
+
+ void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
+ throws XmlPullParserException, java.io.IOException {
+ if (bp.sourcePackage != null) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, bp.name);
+ serializer.attribute(null, "package", bp.sourcePackage);
+ if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
+ + bp.type);
+ if (bp.type == BasePermission.TYPE_DYNAMIC) {
+ final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
+ if (pi != null) {
+ serializer.attribute(null, "type", "dynamic");
+ if (pi.icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ }
+ if (pi.nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ }
+ }
+ }
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+
+ ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
+ final ArraySet<String> kList = new ArraySet<String>(mPackages.keySet());
+ final Iterator<String> its = kList.iterator();
+ final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
+ while (its.hasNext()) {
+ final String key = its.next();
+ final PackageSetting ps = mPackages.get(key);
+ if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ ret.add(ps);
+ }
+ }
+ return ret;
+ }
+
+ void addPackageToCleanLPw(PackageCleanItem pkg) {
+ if (!mPackagesToBeCleaned.contains(pkg)) {
+ mPackagesToBeCleaned.add(pkg);
+ }
+ }
+
+ boolean readLPw(@NonNull List<UserInfo> users) {
+ FileInputStream str = null;
+ if (mBackupSettingsFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupSettingsFilename);
+ mReadMessages.append("Reading from backup settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "Need to read from backup settings file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and settings file exist, we
+ // ignore the settings since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ + mSettingsFilename);
+ mSettingsFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ mPendingPackages.clear();
+ mPastSignatures.clear();
+ mKeySetRefs.clear();
+ mInstallerPackages.clear();
+
+ try {
+ if (str == null) {
+ if (!mSettingsFilename.exists()) {
+ mReadMessages.append("No settings file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "No settings file; creating initial state");
+ // It's enough to just touch version details to create them
+ // with default values
+ findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
+ findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
+ return false;
+ }
+ str = new FileInputStream(mSettingsFilename);
+ }
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager settings");
+ Slog.wtf(PackageManagerService.TAG,
+ "No start tag found in package manager settings");
+ return false;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("package")) {
+ readPackageLPw(parser);
+ } else if (tagName.equals("permissions")) {
+ readPermissionsLPw(mPermissions, parser);
+ } else if (tagName.equals("permission-trees")) {
+ readPermissionsLPw(mPermissionTrees, parser);
+ } else if (tagName.equals("shared-user")) {
+ readSharedUserLPw(parser);
+ } else if (tagName.equals("preferred-packages")) {
+ // no longer used.
+ } else if (tagName.equals("preferred-activities")) {
+ // Upgrading from old single-user implementation;
+ // these are the preferred activities for user 0.
+ readPreferredActivitiesLPw(parser, 0);
+ } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
+ // TODO: check whether this is okay! as it is very
+ // similar to how preferred-activities are treated
+ readPersistentPreferredActivitiesLPw(parser, 0);
+ } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
+ // TODO: check whether this is okay! as it is very
+ // similar to how preferred-activities are treated
+ readCrossProfileIntentFiltersLPw(parser, 0);
+ } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+ readDefaultAppsLPw(parser, 0);
+ } else if (tagName.equals("updated-package")) {
+ readDisabledSysPackageLPw(parser);
+ } else if (tagName.equals("cleaning-package")) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String userStr = parser.getAttributeValue(null, ATTR_USER);
+ String codeStr = parser.getAttributeValue(null, ATTR_CODE);
+ if (name != null) {
+ int userId = UserHandle.USER_SYSTEM;
+ boolean andCode = true;
+ try {
+ if (userStr != null) {
+ userId = Integer.parseInt(userStr);
+ }
+ } catch (NumberFormatException e) {
+ }
+ if (codeStr != null) {
+ andCode = Boolean.parseBoolean(codeStr);
+ }
+ addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
+ }
+ } else if (tagName.equals("renamed-package")) {
+ String nname = parser.getAttributeValue(null, "new");
+ String oname = parser.getAttributeValue(null, "old");
+ if (nname != null && oname != null) {
+ mRenamedPackages.put(nname, oname);
+ }
+ } else if (tagName.equals("restored-ivi")) {
+ readRestoredIntentFilterVerifications(parser);
+ } else if (tagName.equals("last-platform-version")) {
+ // Upgrade from older XML schema
+ final VersionInfo internal = findOrCreateVersion(
+ StorageManager.UUID_PRIVATE_INTERNAL);
+ final VersionInfo external = findOrCreateVersion(
+ StorageManager.UUID_PRIMARY_PHYSICAL);
+
+ internal.sdkVersion = XmlUtils.readIntAttribute(parser, "internal", 0);
+ external.sdkVersion = XmlUtils.readIntAttribute(parser, "external", 0);
+ internal.fingerprint = external.fingerprint =
+ XmlUtils.readStringAttribute(parser, "fingerprint");
+
+ } else if (tagName.equals("database-version")) {
+ // Upgrade from older XML schema
+ final VersionInfo internal = findOrCreateVersion(
+ StorageManager.UUID_PRIVATE_INTERNAL);
+ final VersionInfo external = findOrCreateVersion(
+ StorageManager.UUID_PRIMARY_PHYSICAL);
+
+ internal.databaseVersion = XmlUtils.readIntAttribute(parser, "internal", 0);
+ external.databaseVersion = XmlUtils.readIntAttribute(parser, "external", 0);
+
+ } else if (tagName.equals("verifier")) {
+ final String deviceIdentity = parser.getAttributeValue(null, "device");
+ try {
+ mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
+ } catch (IllegalArgumentException e) {
+ Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+ + e.getMessage());
+ }
+ } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
+ final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
+ mReadExternalStorageEnforced = "1".equals(enforcement);
+ } else if (tagName.equals("keyset-settings")) {
+ mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
+ } else if (TAG_VERSION.equals(tagName)) {
+ final String volumeUuid = XmlUtils.readStringAttribute(parser,
+ ATTR_VOLUME_UUID);
+ final VersionInfo ver = findOrCreateVersion(volumeUuid);
+ ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
+ ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
+ ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch (XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+ }
+
+ // If the build is setup to drop runtime permissions
+ // on update drop the files before loading them.
+ if (PackageManagerService.CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE) {
+ final VersionInfo internal = getInternalVersion();
+ if (!Build.FINGERPRINT.equals(internal.fingerprint)) {
+ for (UserInfo user : users) {
+ mRuntimePermissionsPersistence.deleteUserRuntimePermissionsFile(user.id);
+ }
+ }
+ }
+
+ final int N = mPendingPackages.size();
+
+ for (int i = 0; i < N; i++) {
+ final PackageSetting p = mPendingPackages.get(i);
+ final int sharedUserId = p.getSharedUserId();
+ final Object idObj = getUserIdLPr(sharedUserId);
+ if (idObj instanceof SharedUserSetting) {
+ final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
+ p.sharedUser = sharedUser;
+ p.appId = sharedUser.userId;
+ addPackageSettingLPw(p, sharedUser);
+ } else if (idObj != null) {
+ String msg = "Bad package setting: package " + p.name + " has shared uid "
+ + sharedUserId + " that is not a shared uid\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ } else {
+ String msg = "Bad package setting: package " + p.name + " has shared uid "
+ + sharedUserId + " that is not defined\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ }
+ }
+ mPendingPackages.clear();
+
+ if (mBackupStoppedPackagesFilename.exists()
+ || mStoppedPackagesFilename.exists()) {
+ // Read old file
+ readStoppedLPw();
+ mBackupStoppedPackagesFilename.delete();
+ mStoppedPackagesFilename.delete();
+ // Migrate to new file format
+ writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
+ } else {
+ for (UserInfo user : users) {
+ readPackageRestrictionsLPr(user.id);
+ }
+ }
+
+ for (UserInfo user : users) {
+ mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
+ }
+
+ /*
+ * Make sure all the updated system packages have their shared users
+ * associated with them.
+ */
+ final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
+ while (disabledIt.hasNext()) {
+ final PackageSetting disabledPs = disabledIt.next();
+ final Object id = getUserIdLPr(disabledPs.appId);
+ if (id != null && id instanceof SharedUserSetting) {
+ disabledPs.sharedUser = (SharedUserSetting) id;
+ }
+ }
+
+ mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ + mSharedUsers.size() + " shared uids\n");
+
+ writeKernelMappingLPr();
+
+ return true;
+ }
+
+ void applyDefaultPreferredAppsLPw(PackageManagerService service, int userId) {
+ // First pull data from any pre-installed apps.
+ for (PackageSetting ps : mPackages.values()) {
+ if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
+ && ps.pkg.preferredActivityFilters != null) {
+ ArrayList<PackageParser.ActivityIntentInfo> intents
+ = ps.pkg.preferredActivityFilters;
+ for (int i=0; i<intents.size(); i++) {
+ PackageParser.ActivityIntentInfo aii = intents.get(i);
+ applyDefaultPreferredActivityLPw(service, aii, new ComponentName(
+ ps.name, aii.activity.className), userId);
+ }
+ }
+ }
+
+ // Read preferred apps from .../etc/preferred-apps directory.
+ File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
+ if (!preferredDir.exists() || !preferredDir.isDirectory()) {
+ return;
+ }
+ if (!preferredDir.canRead()) {
+ Slog.w(TAG, "Directory " + preferredDir + " cannot be read");
+ return;
+ }
+
+ // Iterate over the files in the directory and scan .xml files
+ for (File f : preferredDir.listFiles()) {
+ if (!f.getPath().endsWith(".xml")) {
+ Slog.i(TAG, "Non-xml file " + f + " in " + preferredDir + " directory, ignoring");
+ continue;
+ }
+ if (!f.canRead()) {
+ Slog.w(TAG, "Preferred apps file " + f + " cannot be read");
+ continue;
+ }
+
+ if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
+ InputStream str = null;
+ try {
+ str = new BufferedInputStream(new FileInputStream(f));
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ Slog.w(TAG, "Preferred apps file " + f + " does not have start tag");
+ continue;
+ }
+ if (!"preferred-activities".equals(parser.getName())) {
+ Slog.w(TAG, "Preferred apps file " + f
+ + " does not start with 'preferred-activities'");
+ continue;
+ }
+ readDefaultPreferredActivitiesLPw(service, parser, userId);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Error reading apps file " + f, e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Error reading apps file " + f, e);
+ } finally {
+ if (str != null) {
+ try {
+ str.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+
+ private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+ IntentFilter tmpPa, ComponentName cn, int userId) {
+ // The initial preferences only specify the target activity
+ // component and intent-filter, not the set of matches. So we
+ // now need to query for the matches to build the correct
+ // preferred activity entry.
+ if (PackageManagerService.DEBUG_PREFERRED) {
+ Log.d(TAG, "Processing preferred:");
+ tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), " ");
+ }
+ Intent intent = new Intent();
+ int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ intent.setAction(tmpPa.getAction(0));
+ for (int i=0; i<tmpPa.countCategories(); i++) {
+ String cat = tmpPa.getCategory(i);
+ if (cat.equals(Intent.CATEGORY_DEFAULT)) {
+ flags |= MATCH_DEFAULT_ONLY;
+ } else {
+ intent.addCategory(cat);
+ }
+ }
+
+ boolean doNonData = true;
+ boolean hasSchemes = false;
+
+ for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
+ boolean doScheme = true;
+ String scheme = tmpPa.getDataScheme(ischeme);
+ if (scheme != null && !scheme.isEmpty()) {
+ hasSchemes = true;
+ }
+ for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) {
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ PatternMatcher ssp = tmpPa.getDataSchemeSpecificPart(issp);
+ builder.opaquePart(ssp.getPath());
+ Intent finalIntent = new Intent(intent);
+ finalIntent.setData(builder.build());
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ scheme, ssp, null, null, userId);
+ doScheme = false;
+ }
+ for (int iauth=0; iauth<tmpPa.countDataAuthorities(); iauth++) {
+ boolean doAuth = true;
+ IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(iauth);
+ for (int ipath=0; ipath<tmpPa.countDataPaths(); ipath++) {
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (auth.getHost() != null) {
+ builder.authority(auth.getHost());
+ }
+ PatternMatcher path = tmpPa.getDataPath(ipath);
+ builder.path(path.getPath());
+ Intent finalIntent = new Intent(intent);
+ finalIntent.setData(builder.build());
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ scheme, null, auth, path, userId);
+ doAuth = doScheme = false;
+ }
+ if (doAuth) {
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (auth.getHost() != null) {
+ builder.authority(auth.getHost());
+ }
+ Intent finalIntent = new Intent(intent);
+ finalIntent.setData(builder.build());
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ scheme, null, auth, null, userId);
+ doScheme = false;
+ }
+ }
+ if (doScheme) {
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ Intent finalIntent = new Intent(intent);
+ finalIntent.setData(builder.build());
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ scheme, null, null, null, userId);
+ }
+ doNonData = false;
+ }
+
+ for (int idata=0; idata<tmpPa.countDataTypes(); idata++) {
+ String mimeType = tmpPa.getDataType(idata);
+ if (hasSchemes) {
+ Uri.Builder builder = new Uri.Builder();
+ for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
+ String scheme = tmpPa.getDataScheme(ischeme);
+ if (scheme != null && !scheme.isEmpty()) {
+ Intent finalIntent = new Intent(intent);
+ builder.scheme(scheme);
+ finalIntent.setDataAndType(builder.build(), mimeType);
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ scheme, null, null, null, userId);
+ }
+ }
+ } else {
+ Intent finalIntent = new Intent(intent);
+ finalIntent.setType(mimeType);
+ applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+ null, null, null, null, userId);
+ }
+ doNonData = false;
+ }
+
+ if (doNonData) {
+ applyDefaultPreferredActivityLPw(service, intent, flags, cn,
+ null, null, null, null, userId);
+ }
+ }
+
+ private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+ Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
+ IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
+ flags = service.updateFlagsForResolve(flags, userId, intent, Binder.getCallingUid(), false);
+ List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
+ intent.getType(), flags, 0);
+ if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
+ + " results: " + ri);
+ int systemMatch = 0;
+ int thirdPartyMatch = 0;
+ if (ri != null && ri.size() > 1) {
+ boolean haveAct = false;
+ ComponentName haveNonSys = null;
+ ComponentName[] set = new ComponentName[ri.size()];
+ for (int i=0; i<ri.size(); i++) {
+ ActivityInfo ai = ri.get(i).activityInfo;
+ set[i] = new ComponentName(ai.packageName, ai.name);
+ if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (ri.get(i).match >= thirdPartyMatch) {
+ // Keep track of the best match we find of all third
+ // party apps, for use later to determine if we actually
+ // want to set a preferred app for this intent.
+ if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ + ai.packageName + "/" + ai.name + ": non-system!");
+ haveNonSys = set[i];
+ break;
+ }
+ } else if (cn.getPackageName().equals(ai.packageName)
+ && cn.getClassName().equals(ai.name)) {
+ if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ + ai.packageName + "/" + ai.name + ": default!");
+ haveAct = true;
+ systemMatch = ri.get(i).match;
+ } else {
+ if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ + ai.packageName + "/" + ai.name + ": skipped");
+ }
+ }
+ if (haveNonSys != null && thirdPartyMatch < systemMatch) {
+ // If we have a matching third party app, but its match is not as
+ // good as the built-in system app, then we don't want to actually
+ // consider it a match because presumably the built-in app is still
+ // the thing we want users to see by default.
+ haveNonSys = null;
+ }
+ if (haveAct && haveNonSys == null) {
+ IntentFilter filter = new IntentFilter();
+ if (intent.getAction() != null) {
+ filter.addAction(intent.getAction());
+ }
+ if (intent.getCategories() != null) {
+ for (String cat : intent.getCategories()) {
+ filter.addCategory(cat);
+ }
+ }
+ if ((flags & MATCH_DEFAULT_ONLY) != 0) {
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+ }
+ if (scheme != null) {
+ filter.addDataScheme(scheme);
+ }
+ if (ssp != null) {
+ filter.addDataSchemeSpecificPart(ssp.getPath(), ssp.getType());
+ }
+ if (auth != null) {
+ filter.addDataAuthority(auth);
+ }
+ if (path != null) {
+ filter.addDataPath(path);
+ }
+ if (intent.getType() != null) {
+ try {
+ filter.addDataType(intent.getType());
+ } catch (IntentFilter.MalformedMimeTypeException ex) {
+ Slog.w(TAG, "Malformed mimetype " + intent.getType() + " for " + cn);
+ }
+ }
+ PreferredActivity pa = new PreferredActivity(filter, systemMatch, set, cn, true);
+ editPreferredActivitiesLPw(userId).addFilter(pa);
+ } else if (haveNonSys == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("No component ");
+ sb.append(cn.flattenToShortString());
+ sb.append(" found setting preferred ");
+ sb.append(intent);
+ sb.append("; possible matches are ");
+ for (int i=0; i<set.length; i++) {
+ if (i > 0) sb.append(", ");
+ sb.append(set[i].flattenToShortString());
+ }
+ Slog.w(TAG, sb.toString());
+ } else {
+ Slog.i(TAG, "Not setting preferred " + intent + "; found third party match "
+ + haveNonSys.flattenToShortString());
+ }
+ } else {
+ Slog.w(TAG, "No potential matches found for " + intent + " while setting preferred "
+ + cn.flattenToShortString());
+ }
+ }
+
+ private void readDefaultPreferredActivitiesLPw(PackageManagerService service,
+ XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PreferredActivity tmpPa = new PreferredActivity(parser);
+ if (tmpPa.mPref.getParseError() == null) {
+ applyDefaultPreferredActivityLPw(service, tmpPa, tmpPa.mPref.mComponent,
+ userId);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + tmpPa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
+ String v = parser.getAttributeValue(ns, name);
+ try {
+ if (v == null) {
+ return defValue;
+ }
+ return Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: attribute " + name
+ + " has bad integer value " + v + " at "
+ + parser.getPositionDescription());
+ }
+ return defValue;
+ }
+
+ private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ 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_ITEM)) {
+ final String name = parser.getAttributeValue(null, ATTR_NAME);
+ final String sourcePackage = parser.getAttributeValue(null, "package");
+ final String ptype = parser.getAttributeValue(null, "type");
+ if (name != null && sourcePackage != null) {
+ final boolean dynamic = "dynamic".equals(ptype);
+ BasePermission bp = out.get(name);
+ // If the permission is builtin, do not clobber it.
+ if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) {
+ bp = new BasePermission(name.intern(), sourcePackage,
+ dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
+ }
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
+ bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
+ if (dynamic) {
+ PermissionInfo pi = new PermissionInfo();
+ pi.packageName = sourcePackage.intern();
+ pi.name = name.intern();
+ pi.icon = readInt(parser, null, "icon", 0);
+ pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+ pi.protectionLevel = bp.protectionLevel;
+ bp.pendingInfo = pi;
+ }
+ out.put(bp.name, bp);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: permissions has" + " no name at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element reading permissions: " + parser.getName() + " at "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String realName = parser.getAttributeValue(null, "realName");
+ String codePathStr = parser.getAttributeValue(null, "codePath");
+ String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+
+ String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi");
+ String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+
+ String parentPackageName = parser.getAttributeValue(null, "parentPackageName");
+
+ String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi");
+ String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi");
+ String cpuAbiOverrideStr = parser.getAttributeValue(null, "cpuAbiOverride");
+
+ if (primaryCpuAbiStr == null && legacyCpuAbiStr != null) {
+ primaryCpuAbiStr = legacyCpuAbiStr;
+ }
+
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ String version = parser.getAttributeValue(null, "version");
+ int versionCode = 0;
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ final File codePathFile = new File(codePathStr);
+ if (PackageManagerService.locationIsPrivileged(codePathFile)) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ }
+ PackageSetting ps = new PackageSetting(name, realName, codePathFile,
+ new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
+ secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
+ parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr, 16);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ String idStr = parser.getAttributeValue(null, "userId");
+ ps.appId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if (ps.appId <= 0) {
+ String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ }
+
+ 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;
+ }
+
+ if (parser.getName().equals(TAG_PERMISSIONS)) {
+ readInstallPermissionsLPr(parser, ps.getPermissionsState());
+ } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) {
+ String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
+ if (ps.childPackageNames == null) {
+ ps.childPackageNames = new ArrayList<>();
+ }
+ ps.childPackageNames.add(childPackageName);
+ } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
+ readUsesStaticLibLPw(parser, ps);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <updated-package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ mDisabledSysPackages.put(name, ps);
+ }
+
+ private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
+ private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
+ private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29;
+ private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+
+ private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String name = null;
+ String realName = null;
+ String idStr = null;
+ String sharedIdStr = null;
+ String codePathStr = null;
+ String resourcePathStr = null;
+ String legacyCpuAbiString = null;
+ String legacyNativeLibraryPathStr = null;
+ String primaryCpuAbiString = null;
+ String secondaryCpuAbiString = null;
+ String cpuAbiOverrideString = null;
+ String systemStr = null;
+ String installerPackageName = null;
+ String isOrphaned = null;
+ String volumeUuid = null;
+ String categoryHintString = null;
+ String updateAvailable = null;
+ int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
+ String uidError = null;
+ int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
+ long timeStamp = 0;
+ long firstInstallTime = 0;
+ long lastUpdateTime = 0;
+ PackageSetting packageSetting = null;
+ String version = null;
+ int versionCode = 0;
+ String parentPackageName;
+ try {
+ name = parser.getAttributeValue(null, ATTR_NAME);
+ realName = parser.getAttributeValue(null, "realName");
+ idStr = parser.getAttributeValue(null, "userId");
+ uidError = parser.getAttributeValue(null, "uidError");
+ sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ codePathStr = parser.getAttributeValue(null, "codePath");
+ resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+
+ legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+
+ parentPackageName = parser.getAttributeValue(null, "parentPackageName");
+
+ legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
+ secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
+ cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride");
+ updateAvailable = parser.getAttributeValue(null, "updateAvailable");
+
+ if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
+ primaryCpuAbiString = legacyCpuAbiString;
+ }
+
+ version = parser.getAttributeValue(null, "version");
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+ installerPackageName = parser.getAttributeValue(null, "installer");
+ isOrphaned = parser.getAttributeValue(null, "isOrphaned");
+ volumeUuid = parser.getAttributeValue(null, "volumeUuid");
+ categoryHintString = parser.getAttributeValue(null, "categoryHint");
+ if (categoryHintString != null) {
+ try {
+ categoryHint = Integer.parseInt(categoryHintString);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ systemStr = parser.getAttributeValue(null, "publicFlags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ systemStr = parser.getAttributeValue(null, "privateFlags");
+ if (systemStr != null) {
+ try {
+ pkgPrivateFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ } else {
+ // Pre-M -- both public and private flags were stored in one "flags" field.
+ systemStr = parser.getAttributeValue(null, "flags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_HIDDEN) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
+ }
+ if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) {
+ pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+ }
+ pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN
+ | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE
+ | PRE_M_APP_INFO_FLAG_FORWARD_LOCK
+ | PRE_M_APP_INFO_FLAG_PRIVILEGED);
+ } else {
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+ : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ }
+ }
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Reading package: " + name + " userId=" + idStr
+ + " sharedUserId=" + sharedIdStr);
+ final int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ final int sharedUserId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ if (realName != null) {
+ realName = realName.intern();
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no name at "
+ + parser.getPositionDescription());
+ } else if (codePathStr == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no codePath at "
+ + parser.getPositionDescription());
+ } else if (userId > 0) {
+ packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
+ new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
+ secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
+ pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,
+ null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ + userId + " pkg=" + packageSetting);
+ if (packageSetting == null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
+ + userId + " while parsing settings at "
+ + parser.getPositionDescription());
+ } else {
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ }
+ } else if (sharedIdStr != null) {
+ if (sharedUserId > 0) {
+ packageSetting = new PackageSetting(name.intern(), realName, new File(
+ codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
+ primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
+ versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,
+ null /*childPackageNames*/, sharedUserId,
+ null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ mPendingPackages.add(packageSetting);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name
+ + ": sharedUserId=" + sharedUserId + " pkg=" + packageSetting);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad sharedId " + sharedIdStr + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ if (packageSetting != null) {
+ packageSetting.uidError = "true".equals(uidError);
+ packageSetting.installerPackageName = installerPackageName;
+ packageSetting.isOrphaned = "true".equals(isOrphaned);
+ packageSetting.volumeUuid = volumeUuid;
+ packageSetting.categoryHint = categoryHint;
+ packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
+ packageSetting.primaryCpuAbiString = primaryCpuAbiString;
+ packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
+ packageSetting.updateAvailable = "true".equals(updateAvailable);
+ // Handle legacy string here for single-user mode
+ final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
+ if (enabledStr != null) {
+ try {
+ packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */, null);
+ } catch (NumberFormatException e) {
+ if (enabledStr.equalsIgnoreCase("true")) {
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, null);
+ } else if (enabledStr.equalsIgnoreCase("false")) {
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+ } else if (enabledStr.equalsIgnoreCase("default")) {
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad enabled value: " + idStr + " at "
+ + parser.getPositionDescription());
+ }
+ }
+ } else {
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
+ }
+
+ if (installerPackageName != null) {
+ mInstallerPackages.add(installerPackageName);
+ }
+
+ final String installStatusStr = parser.getAttributeValue(null, "installStatus");
+ if (installStatusStr != null) {
+ if (installStatusStr.equalsIgnoreCase("false")) {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
+ } else {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
+ }
+ }
+
+ 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;
+ }
+
+ String tagName = parser.getName();
+ // Legacy
+ if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
+ readDisabledComponentsLPw(packageSetting, parser, 0);
+ } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
+ readEnabledComponentsLPw(packageSetting, parser, 0);
+ } else if (tagName.equals("sigs")) {
+ packageSetting.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals(TAG_PERMISSIONS)) {
+ readInstallPermissionsLPr(parser,
+ packageSetting.getPermissionsState());
+ packageSetting.installPermissionsFixed = true;
+ } else if (tagName.equals("proper-signing-keyset")) {
+ long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+ Integer refCt = mKeySetRefs.get(id);
+ if (refCt != null) {
+ mKeySetRefs.put(id, refCt + 1);
+ } else {
+ mKeySetRefs.put(id, 1);
+ }
+ packageSetting.keySetData.setProperSigningKeySet(id);
+ } else if (tagName.equals("signing-keyset")) {
+ // from v1 of keysetmanagerservice - no longer used
+ } else if (tagName.equals("upgrade-keyset")) {
+ long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+ packageSetting.keySetData.addUpgradeKeySetById(id);
+ } else if (tagName.equals("defined-keyset")) {
+ long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+ String alias = parser.getAttributeValue(null, "alias");
+ Integer refCt = mKeySetRefs.get(id);
+ if (refCt != null) {
+ mKeySetRefs.put(id, refCt + 1);
+ } else {
+ mKeySetRefs.put(id, 1);
+ }
+ packageSetting.keySetData.addDefinedKeySet(id, alias);
+ } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
+ readDomainVerificationLPw(parser, packageSetting);
+ } else if (tagName.equals(TAG_CHILD_PACKAGE)) {
+ String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
+ if (packageSetting.childPackageNames == null) {
+ packageSetting.childPackageNames = new ArrayList<>();
+ }
+ packageSetting.childPackageNames.add(childPackageName);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser,
+ int userId) throws IOException, XmlPullParserException {
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ if (name != null) {
+ packageSetting.addDisabledComponent(name.intern(), userId);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <disabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <disabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser,
+ int userId) throws IOException, XmlPullParserException {
+ 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ if (name != null) {
+ packageSetting.addEnabledComponent(name.intern(), userId);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <enabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <enabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {
+ String name = null;
+ String idStr = null;
+ int pkgFlags = 0;
+ int pkgPrivateFlags = 0;
+ SharedUserSetting su = null;
+ try {
+ name = parser.getAttributeValue(null, ATTR_NAME);
+ idStr = parser.getAttributeValue(null, "userId");
+ int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if ("true".equals(parser.getAttributeValue(null, "system"))) {
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <shared-user> has no name at "
+ + parser.getPositionDescription());
+ } else if (userId == 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: shared-user " + name
+ + " has bad userId " + idStr + " at "
+ + parser.getPositionDescription());
+ } else {
+ if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
+ == null) {
+ PackageManagerService
+ .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ + parser.getPositionDescription());
+ }
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+
+ if (su != 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;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("sigs")) {
+ su.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals("perms")) {
+ readInstallPermissionsLPr(parser, su.getPermissionsState());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <shared-user>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
+ int userHandle, String[] disallowedPackages) {
+ String[] volumeUuids;
+ String[] names;
+ int[] appIds;
+ String[] seinfos;
+ int[] targetSdkVersions;
+ int packagesCount;
+ synchronized (mPackages) {
+ Collection<PackageSetting> packages = mPackages.values();
+ packagesCount = packages.size();
+ volumeUuids = new String[packagesCount];
+ names = new String[packagesCount];
+ appIds = new int[packagesCount];
+ seinfos = new String[packagesCount];
+ targetSdkVersions = new int[packagesCount];
+ Iterator<PackageSetting> packagesIterator = packages.iterator();
+ for (int i = 0; i < packagesCount; i++) {
+ PackageSetting ps = packagesIterator.next();
+ if (ps.pkg == null || ps.pkg.applicationInfo == null) {
+ continue;
+ }
+ final boolean shouldInstall = ps.isSystem() &&
+ !ArrayUtils.contains(disallowedPackages, ps.name);
+ // Only system apps are initially installed.
+ ps.setInstalled(shouldInstall, userHandle);
+ if (!shouldInstall) {
+ writeKernelMappingLPr(ps);
+ }
+ // Need to create a data directory for all apps under this user. Accumulate all
+ // required args and call the installer after mPackages lock has been released
+ volumeUuids[i] = ps.volumeUuid;
+ names[i] = ps.name;
+ appIds[i] = ps.appId;
+ seinfos[i] = ps.pkg.applicationInfo.seInfo;
+ targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
+ }
+ }
+ for (int i = 0; i < packagesCount; i++) {
+ if (names[i] == null) {
+ continue;
+ }
+ // TODO: triage flags!
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
+ try {
+ installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
+ seinfos[i], targetSdkVersions[i]);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to prepare app data", e);
+ }
+ }
+ synchronized (mPackages) {
+ applyDefaultPreferredAppsLPw(service, userHandle);
+ }
+ }
+
+ void removeUserLPw(int userId) {
+ Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userId);
+ }
+ mPreferredActivities.remove(userId);
+ File file = getUserPackagesStateFile(userId);
+ file.delete();
+ file = getUserPackagesStateBackupFile(userId);
+ file.delete();
+ removeCrossProfileIntentFiltersLPw(userId);
+
+ mRuntimePermissionsPersistence.onUserRemovedLPw(userId);
+
+ writePackageListLPr();
+
+ // Inform kernel that the user was removed, so that packages are marked uninstalled
+ // for sdcardfs
+ writeKernelRemoveUserLPr(userId);
+ }
+
+ void removeCrossProfileIntentFiltersLPw(int userId) {
+ synchronized (mCrossProfileIntentResolvers) {
+ // userId is the source user
+ if (mCrossProfileIntentResolvers.get(userId) != null) {
+ mCrossProfileIntentResolvers.remove(userId);
+ writePackageRestrictionsLPr(userId);
+ }
+ // userId is the target user
+ int count = mCrossProfileIntentResolvers.size();
+ for (int i = 0; i < count; i++) {
+ int sourceUserId = mCrossProfileIntentResolvers.keyAt(i);
+ CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(sourceUserId);
+ boolean needsWriting = false;
+ ArraySet<CrossProfileIntentFilter> cpifs =
+ new ArraySet<CrossProfileIntentFilter>(cpir.filterSet());
+ for (CrossProfileIntentFilter cpif : cpifs) {
+ if (cpif.getTargetUserId() == userId) {
+ needsWriting = true;
+ cpir.removeFilter(cpif);
+ }
+ }
+ if (needsWriting) {
+ writePackageRestrictionsLPr(sourceUserId);
+ }
+ }
+ }
+ }
+
+ // This should be called (at least) whenever an application is removed
+ private void setFirstAvailableUid(int uid) {
+ if (uid > mFirstAvailableUid) {
+ mFirstAvailableUid = uid;
+ }
+ }
+
+ // Returns -1 if we could not find an available UserId to assign
+ private int newUserIdLPw(Object obj) {
+ // Let's be stupidly inefficient for now...
+ final int N = mUserIds.size();
+ for (int i = mFirstAvailableUid; i < N; i++) {
+ if (mUserIds.get(i) == null) {
+ mUserIds.set(i, obj);
+ return Process.FIRST_APPLICATION_UID + i;
+ }
+ }
+
+ // None left?
+ if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
+ return -1;
+ }
+
+ mUserIds.add(obj);
+ return Process.FIRST_APPLICATION_UID + N;
+ }
+
+ public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
+ if (mVerifierDeviceIdentity == null) {
+ mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
+
+ writeLPr();
+ }
+
+ return mVerifierDeviceIdentity;
+ }
+
+ boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
+ String childPackageName) {
+ final int packageCount = mDisabledSysPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ PackageSetting disabledPs = mDisabledSysPackages.valueAt(i);
+ if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) {
+ continue;
+ }
+ if (disabledPs.name.equals(parentPackageName)) {
+ continue;
+ }
+ final int childCount = disabledPs.childPackageNames.size();
+ for (int j = 0; j < childCount; j++) {
+ String currChildPackageName = disabledPs.childPackageNames.get(j);
+ if (currChildPackageName.equals(childPackageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public PackageSetting getDisabledSystemPkgLPr(String name) {
+ PackageSetting ps = mDisabledSysPackages.get(name);
+ return ps;
+ }
+
+ private String compToString(ArraySet<String> cmp) {
+ return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
+ }
+
+ boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
+ final PackageSetting ps = mPackages.get(componentInfo.packageName);
+ if (ps == null) return false;
+
+ final PackageUserState userState = ps.readUserState(userId);
+ return userState.isMatch(componentInfo, flags);
+ }
+
+ String getInstallerPackageNameLPr(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.installerPackageName;
+ }
+
+ boolean isOrphaned(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.isOrphaned;
+ }
+
+ int getApplicationEnabledSettingLPr(String packageName, int userId) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.getEnabled(userId);
+ }
+
+ int getComponentEnabledSettingLPr(ComponentName componentName, int userId) {
+ final String packageName = componentName.getPackageName();
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown component: " + componentName);
+ }
+ final String classNameStr = componentName.getClassName();
+ return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
+ }
+
+ boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
+ final PackageSetting pkgSetting = mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return !pkgSetting.getNotLaunched(userId);
+ }
+
+ boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
+ boolean stopped, boolean allowedByPermission, int uid, int userId) {
+ int appId = UserHandle.getAppId(uid);
+ final PackageSetting pkgSetting = mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (!allowedByPermission && (appId != pkgSetting.appId)) {
+ throw new SecurityException(
+ "Permission Denial: attempt to change stopped state from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
+ }
+ if (DEBUG_STOPPED) {
+ if (stopped) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(TAG, "Stopping package " + packageName, e);
+ }
+ }
+ if (pkgSetting.getStopped(userId) != stopped) {
+ pkgSetting.setStopped(stopped, userId);
+ // pkgSetting.pkg.mSetStopped = stopped;
+ if (pkgSetting.getNotLaunched(userId)) {
+ if (pkgSetting.installerPackageName != null) {
+ pm.notifyFirstLaunch(pkgSetting.name, pkgSetting.installerPackageName, userId);
+ }
+ pkgSetting.setNotLaunched(false, userId);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static List<UserInfo> getAllUsers(UserManagerService userManager) {
+ long id = Binder.clearCallingIdentity();
+ try {
+ return userManager.getUsers(false);
+ } catch (NullPointerException npe) {
+ // packagemanager not yet initialized
+ } finally {
+ Binder.restoreCallingIdentity(id);
+ }
+ return null;
+ }
+
+ /**
+ * Return all {@link PackageSetting} that are actively installed on the
+ * given {@link VolumeInfo#fsUuid}.
+ */
+ List<PackageSetting> getVolumePackagesLPr(String volumeUuid) {
+ ArrayList<PackageSetting> res = new ArrayList<>();
+ for (int i = 0; i < mPackages.size(); i++) {
+ final PackageSetting setting = mPackages.valueAt(i);
+ if (Objects.equals(volumeUuid, setting.volumeUuid)) {
+ res.add(setting);
+ }
+ }
+ return res;
+ }
+
+ static void printFlags(PrintWriter pw, int val, Object[] spec) {
+ pw.print("[ ");
+ for (int i=0; i<spec.length; i+=2) {
+ int mask = (Integer)spec[i];
+ if ((val & mask) != 0) {
+ pw.print(spec[i+1]);
+ pw.print(" ");
+ }
+ }
+ pw.print("]");
+ }
+
+ static final Object[] FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
+ ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
+ ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
+ ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
+ ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
+ ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
+ ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
+ ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
+ ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
+ ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
+ ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
+ ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
+ ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ };
+
+ private static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN",
+ ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+ ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS",
+ ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
+ ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE, "DIRECT_BOOT_AWARE",
+ ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, "PARTIALLY_DIRECT_BOOT_AWARE",
+ ApplicationInfo.PRIVATE_FLAG_INSTANT, "EPHEMERAL",
+ ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
+ ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE",
+ ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE",
+ ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION",
+ ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
+ ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
+ };
+
+ void dumpVersionLPr(IndentingPrintWriter pw) {
+ pw.increaseIndent();
+ for (int i= 0; i < mVersion.size(); i++) {
+ final String volumeUuid = mVersion.keyAt(i);
+ final VersionInfo ver = mVersion.valueAt(i);
+ if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
+ pw.println("Internal:");
+ } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
+ pw.println("External:");
+ } else {
+ pw.println("UUID " + volumeUuid + ":");
+ }
+ pw.increaseIndent();
+ pw.printPair("sdkVersion", ver.sdkVersion);
+ pw.printPair("databaseVersion", ver.databaseVersion);
+ pw.println();
+ pw.printPair("fingerprint", ver.fingerprint);
+ pw.println();
+ pw.decreaseIndent();
+ }
+ pw.decreaseIndent();
+ }
+
+ void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
+ ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
+ Date date, List<UserInfo> users, boolean dumpAll) {
+ if (checkinTag != null) {
+ pw.print(checkinTag);
+ pw.print(",");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print(",");
+ pw.print(ps.appId);
+ pw.print(",");
+ pw.print(ps.versionCode);
+ pw.print(",");
+ pw.print(ps.firstInstallTime);
+ pw.print(",");
+ pw.print(ps.lastUpdateTime);
+ pw.print(",");
+ pw.print(ps.installerPackageName != null ? ps.installerPackageName : "?");
+ pw.println();
+ if (ps.pkg != null) {
+ pw.print(checkinTag); pw.print("-"); pw.print("splt,");
+ pw.print("base,");
+ pw.println(ps.pkg.baseRevisionCode);
+ if (ps.pkg.splitNames != null) {
+ for (int i = 0; i < ps.pkg.splitNames.length; i++) {
+ pw.print(checkinTag); pw.print("-"); pw.print("splt,");
+ pw.print(ps.pkg.splitNames[i]); pw.print(",");
+ pw.println(ps.pkg.splitRevisionCodes[i]);
+ }
+ }
+ }
+ for (UserInfo user : users) {
+ pw.print(checkinTag);
+ pw.print("-");
+ pw.print("usr");
+ pw.print(",");
+ pw.print(user.id);
+ pw.print(",");
+ pw.print(ps.getInstalled(user.id) ? "I" : "i");
+ pw.print(ps.getHidden(user.id) ? "B" : "b");
+ pw.print(ps.getSuspended(user.id) ? "SU" : "su");
+ pw.print(ps.getStopped(user.id) ? "S" : "s");
+ pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
+ pw.print(ps.getInstantApp(user.id) ? "IA" : "ia");
+ pw.print(ps.getVirtulalPreload(user.id) ? "VPI" : "vpi");
+ pw.print(",");
+ pw.print(ps.getEnabled(user.id));
+ String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+ pw.print(",");
+ pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?");
+ pw.println();
+ }
+ return;
+ }
+
+ pw.print(prefix); pw.print("Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+
+ if (ps.realName != null) {
+ pw.print(prefix); pw.print(" compat name=");
+ pw.println(ps.name);
+ }
+
+ pw.print(prefix); pw.print(" userId="); pw.println(ps.appId);
+
+ if (ps.sharedUser != null) {
+ pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser);
+ }
+ pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg);
+ pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
+ if (permissionNames == null) {
+ pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(prefix); pw.print(" legacyNativeLibraryDir=");
+ pw.println(ps.legacyNativeLibraryPathString);
+ pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
+ pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
+ }
+ pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
+ if (ps.pkg != null) {
+ pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion);
+ pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
+ }
+ pw.println();
+ if (ps.pkg != null) {
+ if (ps.pkg.parentPackage != null) {
+ PackageParser.Package parentPkg = ps.pkg.parentPackage;
+ PackageSetting pps = mPackages.get(parentPkg.packageName);
+ if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) {
+ pps = mDisabledSysPackages.get(parentPkg.packageName);
+ }
+ if (pps != null) {
+ pw.print(prefix); pw.print(" parentPackage=");
+ pw.println(pps.realName != null ? pps.realName : pps.name);
+ }
+ } else if (ps.pkg.childPackages != null) {
+ pw.print(prefix); pw.print(" childPackages=[");
+ final int childCount = ps.pkg.childPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = ps.pkg.childPackages.get(i);
+ PackageSetting cps = mPackages.get(childPkg.packageName);
+ if (cps == null || !cps.codePathString.equals(childPkg.codePath)) {
+ cps = mDisabledSysPackages.get(childPkg.packageName);
+ }
+ if (cps != null) {
+ if (i > 0) {
+ pw.print(", ");
+ }
+ pw.print(cps.realName != null ? cps.realName : cps.name);
+ }
+ }
+ pw.println("]");
+ }
+ pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
+ pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println();
+ final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
+ if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
+ pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
+ }
+ pw.print(prefix); pw.print(" applicationInfo=");
+ pw.println(ps.pkg.applicationInfo.toString());
+ pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
+ FLAG_DUMP_SPEC); pw.println();
+ if (ps.pkg.applicationInfo.privateFlags != 0) {
+ pw.print(prefix); pw.print(" privateFlags="); printFlags(pw,
+ ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+ }
+ pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+ pw.print(prefix); pw.print(" supportsScreens=[");
+ boolean first = true;
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("small");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("medium");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("large");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("xlarge");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("resizeable");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("anyDensity");
+ }
+ pw.println("]");
+ if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
+ pw.print(prefix); pw.println(" dynamic libraries:");
+ for (int i = 0; i<ps.pkg.libraryNames.size(); i++) {
+ pw.print(prefix); pw.print(" ");
+ pw.println(ps.pkg.libraryNames.get(i));
+ }
+ }
+ if (ps.pkg.staticSharedLibName != null) {
+ pw.print(prefix); pw.println(" static library:");
+ pw.print(prefix); pw.print(" ");
+ pw.print("name:"); pw.print(ps.pkg.staticSharedLibName);
+ pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion);
+ }
+ if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
+ pw.print(prefix); pw.println(" usesLibraries:");
+ for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i));
+ }
+ }
+ if (ps.pkg.usesStaticLibraries != null
+ && ps.pkg.usesStaticLibraries.size() > 0) {
+ pw.print(prefix); pw.println(" usesStaticLibraries:");
+ for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" ");
+ pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:");
+ pw.println(ps.pkg.usesStaticLibrariesVersions[i]);
+ }
+ }
+ if (ps.pkg.usesOptionalLibraries != null
+ && ps.pkg.usesOptionalLibraries.size() > 0) {
+ pw.print(prefix); pw.println(" usesOptionalLibraries:");
+ for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" ");
+ pw.println(ps.pkg.usesOptionalLibraries.get(i));
+ }
+ }
+ if (ps.pkg.usesLibraryFiles != null
+ && ps.pkg.usesLibraryFiles.length > 0) {
+ pw.print(prefix); pw.println(" usesLibraryFiles:");
+ for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) {
+ pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraryFiles[i]);
+ }
+ }
+ }
+ pw.print(prefix); pw.print(" timeStamp=");
+ date.setTime(ps.timeStamp);
+ pw.println(sdf.format(date));
+ pw.print(prefix); pw.print(" firstInstallTime=");
+ date.setTime(ps.firstInstallTime);
+ pw.println(sdf.format(date));
+ pw.print(prefix); pw.print(" lastUpdateTime=");
+ date.setTime(ps.lastUpdateTime);
+ pw.println(sdf.format(date));
+ if (ps.installerPackageName != null) {
+ pw.print(prefix); pw.print(" installerPackageName=");
+ pw.println(ps.installerPackageName);
+ }
+ if (ps.volumeUuid != null) {
+ pw.print(prefix); pw.print(" volumeUuid=");
+ pw.println(ps.volumeUuid);
+ }
+ pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
+ pw.print(prefix); pw.print(" installPermissionsFixed=");
+ pw.print(ps.installPermissionsFixed);
+ pw.print(" installStatus="); pw.println(ps.installStatus);
+ pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+ pw.println();
+
+ if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
+ final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
+ pw.print(prefix); pw.println(" declared permissions:");
+ for (int i=0; i<perms.size(); i++) {
+ PackageParser.Permission perm = perms.get(i);
+ if (permissionNames != null
+ && !permissionNames.contains(perm.info.name)) {
+ continue;
+ }
+ pw.print(prefix); pw.print(" "); pw.print(perm.info.name);
+ pw.print(": prot=");
+ pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel));
+ if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+ pw.print(", COSTS_MONEY");
+ }
+ if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
+ pw.print(", HIDDEN");
+ }
+ if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+ pw.print(", INSTALLED");
+ }
+ pw.println();
+ }
+ }
+
+ if ((permissionNames != null || dumpAll) && ps.pkg != null
+ && ps.pkg.requestedPermissions != null
+ && ps.pkg.requestedPermissions.size() > 0) {
+ final ArrayList<String> perms = ps.pkg.requestedPermissions;
+ pw.print(prefix); pw.println(" requested permissions:");
+ for (int i=0; i<perms.size(); i++) {
+ String perm = perms.get(i);
+ if (permissionNames != null
+ && !permissionNames.contains(perm)) {
+ continue;
+ }
+ pw.print(prefix); pw.print(" "); pw.println(perm);
+ }
+ }
+
+ if (ps.sharedUser == null || permissionNames != null || dumpAll) {
+ PermissionsState permissionsState = ps.getPermissionsState();
+ dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState);
+ }
+
+ for (UserInfo user : users) {
+ pw.print(prefix); pw.print(" User "); pw.print(user.id); pw.print(": ");
+ pw.print("ceDataInode=");
+ pw.print(ps.getCeDataInode(user.id));
+ pw.print(" installed=");
+ pw.print(ps.getInstalled(user.id));
+ pw.print(" hidden=");
+ pw.print(ps.getHidden(user.id));
+ pw.print(" suspended=");
+ pw.print(ps.getSuspended(user.id));
+ pw.print(" stopped=");
+ pw.print(ps.getStopped(user.id));
+ pw.print(" notLaunched=");
+ pw.print(ps.getNotLaunched(user.id));
+ pw.print(" enabled=");
+ pw.print(ps.getEnabled(user.id));
+ pw.print(" instant=");
+ pw.print(ps.getInstantApp(user.id));
+ pw.print(" virtual=");
+ pw.println(ps.getVirtulalPreload(user.id));
+
+ String[] overlayPaths = ps.getOverlayPaths(user.id);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ pw.print(prefix); pw.println(" overlay paths:");
+ for (String path : overlayPaths) {
+ pw.print(prefix); pw.print(" "); pw.println(path);
+ }
+ }
+
+ String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+ if (lastDisabledAppCaller != null) {
+ pw.print(prefix); pw.print(" lastDisabledCaller: ");
+ pw.println(lastDisabledAppCaller);
+ }
+
+ if (ps.sharedUser == null) {
+ PermissionsState permissionsState = ps.getPermissionsState();
+ dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
+ .getRuntimePermissionStates(user.id), dumpAll);
+ }
+
+ if (permissionNames == null) {
+ ArraySet<String> cmp = ps.getDisabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.print(prefix); pw.println(" disabledComponents:");
+ for (String s : cmp) {
+ pw.print(prefix); pw.print(" "); pw.println(s);
+ }
+ }
+ cmp = ps.getEnabledComponents(user.id);
+ if (cmp != null && cmp.size() > 0) {
+ pw.print(prefix); pw.println(" enabledComponents:");
+ for (String s : cmp) {
+ pw.print(prefix); pw.print(" "); pw.println(s);
+ }
+ }
+ }
+ }
+ }
+
+ void dumpPackagesLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState, boolean checkin) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ final Date date = new Date();
+ boolean printedSomething = false;
+ List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+ for (final PackageSetting ps : mPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (permissionNames != null
+ && !ps.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ continue;
+ }
+
+ if (!checkin && packageName != null) {
+ dumpState.setSharedUser(ps.sharedUser);
+ }
+
+ if (!checkin && !printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Packages:");
+ printedSomething = true;
+ }
+ dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users,
+ packageName != null);
+ }
+
+ printedSomething = false;
+ if (mRenamedPackages.size() > 0 && permissionNames == null) {
+ for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ if (packageName != null && !packageName.equals(e.getKey())
+ && !packageName.equals(e.getValue())) {
+ continue;
+ }
+ if (!checkin) {
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("ren,");
+ }
+ pw.print(e.getKey());
+ pw.print(checkin ? " -> " : ",");
+ pw.println(e.getValue());
+ }
+ }
+
+ printedSomething = false;
+ if (mDisabledSysPackages.size() > 0 && permissionNames == null) {
+ for (final PackageSetting ps : mDisabledSysPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!checkin && !printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Hidden system packages:");
+ printedSomething = true;
+ }
+ dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
+ users, packageName != null);
+ }
+ }
+ }
+
+ void dumpPackagesProto(ProtoOutputStream proto) {
+ List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+
+ final int count = mPackages.size();
+ for (int i = 0; i < count; i++) {
+ final PackageSetting ps = mPackages.valueAt(i);
+ ps.writeToProto(proto, PackageServiceDumpProto.PACKAGES, users);
+ }
+ }
+
+ void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState) {
+ boolean printedSomething = false;
+ for (BasePermission p : mPermissions.values()) {
+ if (packageName != null && !packageName.equals(p.sourcePackage)) {
+ continue;
+ }
+ if (permissionNames != null && !permissionNames.contains(p.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Permissions:");
+ printedSomething = true;
+ }
+ pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(p)));
+ pw.println("):");
+ pw.print(" sourcePackage="); pw.println(p.sourcePackage);
+ pw.print(" uid="); pw.print(p.uid);
+ pw.print(" gids="); pw.print(Arrays.toString(
+ p.computeGids(UserHandle.USER_SYSTEM)));
+ pw.print(" type="); pw.print(p.type);
+ pw.print(" prot=");
+ pw.println(PermissionInfo.protectionToString(p.protectionLevel));
+ if (p.perm != null) {
+ pw.print(" perm="); pw.println(p.perm);
+ if ((p.perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
+ || (p.perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+ pw.print(" flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
+ }
+ }
+ if (p.packageSetting != null) {
+ pw.print(" packageSetting="); pw.println(p.packageSetting);
+ }
+ if (READ_EXTERNAL_STORAGE.equals(p.name)) {
+ pw.print(" enforced=");
+ pw.println(mReadExternalStorageEnforced);
+ }
+ }
+ }
+
+ void dumpSharedUsersLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
+ DumpState dumpState, boolean checkin) {
+ boolean printedSomething = false;
+ for (SharedUserSetting su : mSharedUsers.values()) {
+ if (packageName != null && su != dumpState.getSharedUser()) {
+ continue;
+ }
+ if (permissionNames != null
+ && !su.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ continue;
+ }
+ if (!checkin) {
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Shared users:");
+ printedSomething = true;
+ }
+ pw.print(" SharedUser [");
+ pw.print(su.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(su)));
+ pw.println("):");
+
+ String prefix = " ";
+ pw.print(prefix); pw.print("userId="); pw.println(su.userId);
+
+ PermissionsState permissionsState = su.getPermissionsState();
+ dumpInstallPermissionsLPr(pw, prefix, permissionNames, permissionsState);
+
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int[] gids = permissionsState.computeGids(userId);
+ List<PermissionState> permissions = permissionsState
+ .getRuntimePermissionStates(userId);
+ if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
+ pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
+ dumpGidsLPr(pw, prefix + " ", gids);
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissions,
+ packageName != null);
+ }
+ }
+ } else {
+ pw.print("suid,"); pw.print(su.userId); pw.print(","); pw.println(su.name);
+ }
+ }
+ }
+
+ void dumpSharedUsersProto(ProtoOutputStream proto) {
+ final int count = mSharedUsers.size();
+ for (int i = 0; i < count; i++) {
+ final SharedUserSetting su = mSharedUsers.valueAt(i);
+ final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
+ proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
+ proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
+ proto.end(sharedUserToken);
+ }
+ }
+
+ void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
+ pw.println("Settings parse messages:");
+ pw.print(mReadMessages.toString());
+ }
+
+ void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) {
+ if (mRestoredUserGrants.size() > 0) {
+ pw.println();
+ pw.println("Restored (pending) permission grants:");
+ for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) {
+ ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+ mRestoredUserGrants.valueAt(userIndex);
+ if (grantsByPackage != null && grantsByPackage.size() > 0) {
+ final int userId = mRestoredUserGrants.keyAt(userIndex);
+ pw.print(" User "); pw.println(userId);
+
+ for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) {
+ ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex);
+ if (grants != null && grants.size() > 0) {
+ final String pkgName = grantsByPackage.keyAt(pkgIndex);
+ pw.print(" "); pw.print(pkgName); pw.println(" :");
+
+ for (RestoredPermissionGrant g : grants) {
+ pw.print(" ");
+ pw.print(g.permissionName);
+ if (g.granted) {
+ pw.print(" GRANTED");
+ }
+ if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
+ pw.print(" user_set");
+ }
+ if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
+ pw.print(" user_fixed");
+ }
+ if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ pw.print(" revoke_on_upgrade");
+ }
+ pw.println();
+ }
+ }
+ }
+ }
+ }
+ pw.println();
+ }
+ }
+
+ private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
+ if (pkg == null) {
+ pw.print("unknown");
+ } else {
+ // [base:10, config.mdpi, config.xhdpi:12]
+ pw.print("[");
+ pw.print("base");
+ if (pkg.baseRevisionCode != 0) {
+ pw.print(":"); pw.print(pkg.baseRevisionCode);
+ }
+ if (pkg.splitNames != null) {
+ for (int i = 0; i < pkg.splitNames.length; i++) {
+ pw.print(", ");
+ pw.print(pkg.splitNames[i]);
+ if (pkg.splitRevisionCodes[i] != 0) {
+ pw.print(":"); pw.print(pkg.splitRevisionCodes[i]);
+ }
+ }
+ }
+ pw.print("]");
+ }
+ }
+
+ void dumpGidsLPr(PrintWriter pw, String prefix, int[] gids) {
+ if (!ArrayUtils.isEmpty(gids)) {
+ pw.print(prefix);
+ pw.print("gids="); pw.println(
+ PackageManagerService.arrayToString(gids));
+ }
+ }
+
+ void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
+ List<PermissionState> permissionStates, boolean dumpAll) {
+ if (!permissionStates.isEmpty() || dumpAll) {
+ pw.print(prefix); pw.println("runtime permissions:");
+ for (PermissionState permissionState : permissionStates) {
+ if (permissionNames != null
+ && !permissionNames.contains(permissionState.getName())) {
+ continue;
+ }
+ pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
+ pw.print(": granted="); pw.print(permissionState.isGranted());
+ pw.println(permissionFlagsToString(", flags=",
+ permissionState.getFlags()));
+ }
+ }
+ }
+
+ private static String permissionFlagsToString(String prefix, int flags) {
+ StringBuilder flagsString = null;
+ while (flags != 0) {
+ if (flagsString == null) {
+ flagsString = new StringBuilder();
+ flagsString.append(prefix);
+ flagsString.append("[ ");
+ }
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ flagsString.append(PackageManager.permissionFlagToString(flag));
+ flagsString.append(' ');
+ }
+ if (flagsString != null) {
+ flagsString.append(']');
+ return flagsString.toString();
+ } else {
+ return "";
+ }
+ }
+
+ void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
+ PermissionsState permissionsState) {
+ List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates();
+ if (!permissionStates.isEmpty()) {
+ pw.print(prefix); pw.println("install permissions:");
+ for (PermissionState permissionState : permissionStates) {
+ if (permissionNames != null
+ && !permissionNames.contains(permissionState.getName())) {
+ continue;
+ }
+ pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
+ pw.print(": granted="); pw.print(permissionState.isGranted());
+ pw.println(permissionFlagsToString(", flags=",
+ permissionState.getFlags()));
+ }
+ }
+ }
+
+ public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
+ if (sync) {
+ mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
+ } else {
+ mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+ }
+ }
+
+ private final class RuntimePermissionPersistence {
+ private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
+ private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
+
+ private final Handler mHandler = new MyHandler();
+
+ private final Object mLock;
+
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
+
+ @GuardedBy("mLock")
+ // The mapping keys are user ids.
+ private final SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();
+
+ @GuardedBy("mLock")
+ // The mapping keys are user ids.
+ private final SparseArray<String> mFingerprints = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ // The mapping keys are user ids.
+ private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
+
+ public RuntimePermissionPersistence(Object lock) {
+ mLock = lock;
+ }
+
+ public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
+ return mDefaultPermissionsGranted.get(userId);
+ }
+
+ public void onDefaultRuntimePermissionsGrantedLPr(int userId) {
+ mFingerprints.put(userId, Build.FINGERPRINT);
+ writePermissionsForUserAsyncLPr(userId);
+ }
+
+ public void writePermissionsForUserSyncLPr(int userId) {
+ mHandler.removeMessages(userId);
+ writePermissionsSync(userId);
+ }
+
+ public void writePermissionsForUserAsyncLPr(int userId) {
+ final long currentTimeMillis = SystemClock.uptimeMillis();
+
+ if (mWriteScheduled.get(userId)) {
+ mHandler.removeMessages(userId);
+
+ // If enough time passed, write without holding off anymore.
+ final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
+ .get(userId);
+ final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+ - lastNotWrittenMutationTimeMillis;
+ if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
+ mHandler.obtainMessage(userId).sendToTarget();
+ return;
+ }
+
+ // Hold off a bit more as settings are frequently changing.
+ final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
+ + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
+ final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
+ maxDelayMillis);
+
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, writeDelayMillis);
+ } else {
+ mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
+ mWriteScheduled.put(userId, true);
+ }
+ }
+
+ private void writePermissionsSync(int userId) {
+ AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
+
+ ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
+ ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
+
+ synchronized (mLock) {
+ mWriteScheduled.delete(userId);
+
+ final int packageCount = mPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ String packageName = mPackages.keyAt(i);
+ PackageSetting packageSetting = mPackages.valueAt(i);
+ if (packageSetting.sharedUser == null) {
+ PermissionsState permissionsState = packageSetting.getPermissionsState();
+ List<PermissionState> permissionsStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ if (!permissionsStates.isEmpty()) {
+ permissionsForPackage.put(packageName, permissionsStates);
+ }
+ }
+ }
+
+ final int sharedUserCount = mSharedUsers.size();
+ for (int i = 0; i < sharedUserCount; i++) {
+ String sharedUserName = mSharedUsers.keyAt(i);
+ SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
+ PermissionsState permissionsState = sharedUser.getPermissionsState();
+ List<PermissionState> permissionsStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ if (!permissionsStates.isEmpty()) {
+ permissionsForSharedUser.put(sharedUserName, permissionsStates);
+ }
+ }
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, StandardCharsets.UTF_8.name());
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+
+ serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
+
+ String fingerprint = mFingerprints.get(userId);
+ if (fingerprint != null) {
+ serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
+ }
+
+ final int packageCount = permissionsForPackage.size();
+ for (int i = 0; i < packageCount; i++) {
+ String packageName = permissionsForPackage.keyAt(i);
+ List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, packageName);
+ writePermissions(serializer, permissionStates);
+ serializer.endTag(null, TAG_PACKAGE);
+ }
+
+ final int sharedUserCount = permissionsForSharedUser.size();
+ for (int i = 0; i < sharedUserCount; i++) {
+ String packageName = permissionsForSharedUser.keyAt(i);
+ List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
+ serializer.startTag(null, TAG_SHARED_USER);
+ serializer.attribute(null, ATTR_NAME, packageName);
+ writePermissions(serializer, permissionStates);
+ serializer.endTag(null, TAG_SHARED_USER);
+ }
+
+ serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
+
+ // Now any restored permission grants that are waiting for the apps
+ // in question to be installed. These are stored as per-package
+ // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
+ // number of individual permission grant entities.
+ if (mRestoredUserGrants.get(userId) != null) {
+ ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
+ mRestoredUserGrants.get(userId);
+ if (restoredGrants != null) {
+ final int pkgCount = restoredGrants.size();
+ for (int i = 0; i < pkgCount; i++) {
+ final ArraySet<RestoredPermissionGrant> pkgGrants =
+ restoredGrants.valueAt(i);
+ if (pkgGrants != null && pkgGrants.size() > 0) {
+ final String pkgName = restoredGrants.keyAt(i);
+ serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
+ serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
+
+ final int N = pkgGrants.size();
+ for (int z = 0; z < N; z++) {
+ RestoredPermissionGrant g = pkgGrants.valueAt(z);
+ serializer.startTag(null, TAG_PERMISSION_ENTRY);
+ serializer.attribute(null, ATTR_NAME, g.permissionName);
+
+ if (g.granted) {
+ serializer.attribute(null, ATTR_GRANTED, "true");
+ }
+
+ if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
+ serializer.attribute(null, ATTR_USER_SET, "true");
+ }
+ if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
+ serializer.attribute(null, ATTR_USER_FIXED, "true");
+ }
+ if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
+ }
+ serializer.endTag(null, TAG_PERMISSION_ENTRY);
+ }
+ serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
+ }
+ }
+ }
+ }
+
+ serializer.endDocument();
+ destination.finishWrite(out);
+
+ if (Build.FINGERPRINT.equals(fingerprint)) {
+ mDefaultPermissionsGranted.put(userId, true);
+ }
+ // Any error while writing is fatal.
+ } catch (Throwable t) {
+ Slog.wtf(PackageManagerService.TAG,
+ "Failed to write settings, restoring backup", t);
+ destination.failWrite(out);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private void onUserRemovedLPw(int userId) {
+ // Make sure we do not
+ mHandler.removeMessages(userId);
+
+ for (SettingBase sb : mPackages.values()) {
+ revokeRuntimePermissionsAndClearFlags(sb, userId);
+ }
+
+ for (SettingBase sb : mSharedUsers.values()) {
+ revokeRuntimePermissionsAndClearFlags(sb, userId);
+ }
+
+ mDefaultPermissionsGranted.delete(userId);
+ mFingerprints.remove(userId);
+ }
+
+ private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
+ PermissionsState permissionsState = sb.getPermissionsState();
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mPermissions.get(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+ }
+ }
+ }
+
+ public void deleteUserRuntimePermissionsFile(int userId) {
+ getUserRuntimePermissionsFile(userId).delete();
+ }
+
+ public void readStateForUserSyncLPr(int userId) {
+ File permissionsFile = getUserRuntimePermissionsFile(userId);
+ if (!permissionsFile.exists()) {
+ return;
+ }
+
+ FileInputStream in;
+ try {
+ in = new AtomicFile(permissionsFile).openRead();
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(PackageManagerService.TAG, "No permissions state");
+ return;
+ }
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseRuntimePermissionsLPr(parser, userId);
+
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed parsing permissions file: "
+ + permissionsFile , e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ // Backup/restore support
+
+ public void rememberRestoredUserGrantLPr(String pkgName, String permission,
+ boolean isGranted, int restoredFlagSet, int userId) {
+ // This change will be remembered at write-settings time
+ ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+ mRestoredUserGrants.get(userId);
+ if (grantsByPackage == null) {
+ grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>();
+ mRestoredUserGrants.put(userId, grantsByPackage);
+ }
+
+ ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName);
+ if (grants == null) {
+ grants = new ArraySet<RestoredPermissionGrant>();
+ grantsByPackage.put(pkgName, grants);
+ }
+
+ RestoredPermissionGrant grant = new RestoredPermissionGrant(permission,
+ isGranted, restoredFlagSet);
+ grants.add(grant);
+ }
+
+ // Private internals
+
+ private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
+ throws IOException, XmlPullParserException {
+ final 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;
+ }
+
+ switch (parser.getName()) {
+ case TAG_RUNTIME_PERMISSIONS: {
+ String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
+ mFingerprints.put(userId, fingerprint);
+ final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
+ mDefaultPermissionsGranted.put(userId, defaultsGranted);
+ } break;
+
+ case TAG_PACKAGE: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ PackageSetting ps = mPackages.get(name);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ parsePermissionsLPr(parser, ps.getPermissionsState(), userId);
+ } break;
+
+ case TAG_SHARED_USER: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ SharedUserSetting sus = mSharedUsers.get(name);
+ if (sus == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
+ } break;
+
+ case TAG_RESTORED_RUNTIME_PERMISSIONS: {
+ final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ parseRestoredRuntimePermissionsLPr(parser, pkgName, userId);
+ } break;
+ }
+ }
+ }
+
+ private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser,
+ final String pkgName, final int userId) throws IOException, XmlPullParserException {
+ final 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;
+ }
+
+ switch (parser.getName()) {
+ case TAG_PERMISSION_ENTRY: {
+ final String permName = parser.getAttributeValue(null, ATTR_NAME);
+ final boolean isGranted = "true".equals(
+ parser.getAttributeValue(null, ATTR_GRANTED));
+
+ int permBits = 0;
+ if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
+ permBits |= FLAG_PERMISSION_USER_SET;
+ }
+ if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
+ permBits |= FLAG_PERMISSION_USER_FIXED;
+ }
+ if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
+ permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ }
+
+ if (isGranted || permBits != 0) {
+ rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
+ }
+ } break;
+ }
+ }
+ }
+
+ private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState,
+ int userId) throws IOException, XmlPullParserException {
+ final 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;
+ }
+
+ switch (parser.getName()) {
+ case TAG_ITEM: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ BasePermission bp = mPermissions.get(name);
+ if (bp == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
+ final boolean granted = grantedStr == null
+ || Boolean.parseBoolean(grantedStr);
+
+ String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
+ final int flags = (flagsStr != null)
+ ? Integer.parseInt(flagsStr, 16) : 0;
+
+ if (granted) {
+ permissionsState.grantRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ } else {
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
+
+ } break;
+ }
+ }
+ }
+
+ private void writePermissions(XmlSerializer serializer,
+ List<PermissionState> permissionStates) throws IOException {
+ for (PermissionState permissionState : permissionStates) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME,permissionState.getName());
+ serializer.attribute(null, ATTR_GRANTED,
+ String.valueOf(permissionState.isGranted()));
+ serializer.attribute(null, ATTR_FLAGS,
+ Integer.toHexString(permissionState.getFlags()));
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+
+ private final class MyHandler extends Handler {
+ public MyHandler() {
+ super(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ final int userId = message.what;
+ Runnable callback = (Runnable) message.obj;
+ writePermissionsSync(userId);
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ }
+ }
+}