summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Buynytskyy <alexbuy@google.com> 2022-11-22 00:12:28 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-11-22 00:12:28 +0000
commit1d0f68c5a65c0420c539a986ac0815f87542150f (patch)
tree6e9e29e6fbdccc58f41cb24c48190103e7585958
parent0153dd58d9269ad017ba1ef5e36fbb9d33151f96 (diff)
parent3ddd1a4289896dddb20caaa792285cd018c1b137 (diff)
Merge "Offload IO to Handler thread."
-rw-r--r--services/core/java/com/android/server/pm/PackageHandler.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java68
-rw-r--r--services/core/java/com/android/server/pm/Settings.java525
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java246
4 files changed, 590 insertions, 255 deletions
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 66ef93d12191..93a119c36f3d 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -36,7 +36,6 @@ import static com.android.server.pm.PackageManagerService.PRUNE_UNUSED_STATIC_SH
import static com.android.server.pm.PackageManagerService.SEND_PENDING_BROADCAST;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_LIST;
-import static com.android.server.pm.PackageManagerService.WRITE_PACKAGE_RESTRICTIONS;
import static com.android.server.pm.PackageManagerService.WRITE_SETTINGS;
import android.content.Intent;
@@ -119,10 +118,7 @@ final class PackageHandler extends Handler {
}
} break;
case WRITE_SETTINGS: {
- mPm.writeSettings();
- } break;
- case WRITE_PACKAGE_RESTRICTIONS: {
- mPm.writePendingRestrictions();
+ mPm.writeSettings(/*sync=*/false);
} break;
case WRITE_PACKAGE_LIST: {
mPm.writePackageList(msg.arg1);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 139c6ea28b7d..16a3ca0556fd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -558,6 +558,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
static final char RANDOM_CODEPATH_PREFIX = '-';
final Handler mHandler;
+ final Handler mBackgroundHandler;
final ProcessLoggingHandler mProcessLoggingHandler;
@@ -873,7 +874,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
// public static final int UNUSED = 5;
static final int POST_INSTALL = 9;
static final int WRITE_SETTINGS = 13;
- static final int WRITE_PACKAGE_RESTRICTIONS = 14;
+ static final int WRITE_DIRTY_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int CHECK_PENDING_VERIFICATION = 16;
// public static final int UNUSED = 17;
@@ -890,6 +891,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
static final int PRUNE_UNUSED_STATIC_SHARED_LIBRARIES = 28;
static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER = 29;
+ static final int WRITE_USER_PACKAGE_RESTRICTIONS = 30;
+
static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
private static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
private static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER_DELAY_MS = 1000;
@@ -1397,28 +1400,33 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mDirtyUsers.add(userId);
}
}
- if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
- mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
+ if (!mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS)) {
+ mBackgroundHandler.sendMessageDelayed(
+ mBackgroundHandler.obtainMessage(WRITE_DIRTY_PACKAGE_RESTRICTIONS, this),
+ WRITE_SETTINGS_DELAY);
}
}
void writePendingRestrictions() {
+ final Integer[] dirtyUsers;
synchronized (mLock) {
- mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
synchronized (mDirtyUsers) {
- for (int userId : mDirtyUsers) {
- mSettings.writePackageRestrictionsLPr(userId);
+ if (mDirtyUsers.isEmpty()) {
+ return;
}
+ dirtyUsers = mDirtyUsers.toArray(Integer[]::new);
mDirtyUsers.clear();
}
}
+ mSettings.writePackageRestrictions(dirtyUsers);
}
- void writeSettings() {
+ void writeSettings(boolean sync) {
synchronized (mLock) {
mHandler.removeMessages(WRITE_SETTINGS);
- mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
- writeSettingsLPrTEMP();
+ mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
+ writeSettingsLPrTEMP(sync);
synchronized (mDirtyUsers) {
mDirtyUsers.clear();
}
@@ -1432,6 +1440,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
+ private static final Handler.Callback BACKGROUND_HANDLER_CALLBACK = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(@NonNull Message msg) {
+ switch (msg.what) {
+ case WRITE_DIRTY_PACKAGE_RESTRICTIONS: {
+ PackageManagerService pm = (PackageManagerService) msg.obj;
+ pm.writePendingRestrictions();
+ return true;
+ }
+ case WRITE_USER_PACKAGE_RESTRICTIONS: {
+ final Runnable r = (Runnable) msg.obj;
+ r.run();
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
public static Pair<PackageManagerService, IPackageManager> main(Context context,
Installer installer, @NonNull DomainVerificationService domainVerificationService,
boolean factoryTest) {
@@ -1446,7 +1473,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
HandlerThread backgroundThread = new ServiceThread("PackageManagerBg",
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
backgroundThread.start();
- Handler backgroundHandler = new Handler(backgroundThread.getLooper());
+ Handler backgroundHandler = new Handler(backgroundThread.getLooper(),
+ BACKGROUND_HANDLER_CALLBACK);
PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
@@ -1460,7 +1488,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
- domainVerificationService, backgroundHandler, lock),
+ domainVerificationService, backgroundHandler,
+ lock),
(i, pm) -> AppsFilterImpl.create(i,
i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
@@ -1638,6 +1667,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mHandler = injector.getHandler();
+ mBackgroundHandler = injector.getBackgroundHandler();
mSharedLibraries = injector.getSharedLibrariesImpl();
mApexManager = testParams.apexManager;
@@ -1828,6 +1858,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = injector.getViewCompiler();
mSharedLibraries = mInjector.getSharedLibrariesImpl();
+ mBackgroundHandler = injector.getBackgroundHandler();
mContext.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
@@ -2902,9 +2933,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mPackageUsage.writeNow(mSettings.getPackagesLocked());
if (mHandler.hasMessages(WRITE_SETTINGS)
- || mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)
+ || mBackgroundHandler.hasMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS)
|| mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
- writeSettings();
+ writeSettings(/*sync=*/true);
}
}
}
@@ -3968,7 +3999,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
synchronized (mDirtyUsers) {
mDirtyUsers.remove(userId);
if (mDirtyUsers.isEmpty()) {
- mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ mBackgroundHandler.removeMessages(WRITE_DIRTY_PACKAGE_RESTRICTIONS);
}
}
}
@@ -6867,9 +6898,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService
* TODO: In the meantime, can this be moved to a schedule call?
* TODO(b/182523293): This should be removed once we finish migration of permission storage.
*/
- void writeSettingsLPrTEMP() {
+ void writeSettingsLPrTEMP(boolean sync) {
mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
- mSettings.writeLPr(mLiveComputer);
+ mSettings.writeLPr(mLiveComputer, sync);
+ }
+
+ // Default async version.
+ void writeSettingsLPrTEMP() {
+ writeSettingsLPrTEMP(/*sync=*/false);
}
@Override
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e33cc9ff0983..a29fa9b86297 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -29,6 +29,7 @@ import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.WRITE_USER_PACKAGE_RESTRICTIONS;
import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
import android.annotation.NonNull;
@@ -56,7 +57,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.CreateAppDataArgs;
-import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Message;
@@ -376,6 +376,13 @@ public final class Settings implements Watchable, Snappable {
/** The top level directory in configfs for sdcardfs to push the package->uid,userId mappings */
private final File mKernelMappingFilename;
+ // Lock for user package restrictions operations.
+ private final Object mPackageRestrictionsLock = new Object();
+
+ // Pending write operations.
+ @GuardedBy("mPackageRestrictionsLock")
+ private final SparseIntArray mPendingAsyncPackageRestrictionsWrites = new SparseIntArray();
+
/** Map from package name to settings */
@Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -1476,31 +1483,46 @@ public final class Settings implements Watchable, Snappable {
return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.removeReturnOld(userId);
}
- private File getUserPackagesStateFile(int userId) {
- // TODO: Implement a cleaner solution when adding tests.
+ private File getUserSystemDirectory(int userId) {
// 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");
+ return new File(new File(mSystemDir, "users"), Integer.toString(userId));
}
- 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);
+ // The method itself does not have to be guarded, but the file does.
+ @GuardedBy("mPackageRestrictionsLock")
+ private File getUserPackagesStateFile(int userId) {
+ return new File(getUserSystemDirectory(userId), "package-restrictions.xml");
}
+ // The method itself does not have to be guarded, but the file does.
+ @GuardedBy("mPackageRestrictionsLock")
private File getUserPackagesStateBackupFile(int userId) {
- return new File(Environment.getUserSystemDirectory(userId),
- "package-restrictions-backup.xml");
+ return new File(getUserSystemDirectory(userId), "package-restrictions-backup.xml");
}
+ private File getUserRuntimePermissionsFile(int userId) {
+ return new File(getUserSystemDirectory(userId), RUNTIME_PERMISSIONS_FILE_NAME);
+ }
+
+ // Default version is writing restrictions asynchronously.
void writeAllUsersPackageRestrictionsLPr() {
+ writeAllUsersPackageRestrictionsLPr(/*sync=*/false);
+ }
+
+ void writeAllUsersPackageRestrictionsLPr(boolean sync) {
List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
if (users == null) return;
+ if (sync) {
+ // Cancel all pending per-user writes.
+ synchronized (mPackageRestrictionsLock) {
+ mPendingAsyncPackageRestrictionsWrites.clear();
+ }
+ mHandler.removeMessages(WRITE_USER_PACKAGE_RESTRICTIONS);
+ }
+
for (UserInfo user : users) {
- writePackageRestrictionsLPr(user.id);
+ writePackageRestrictionsLPr(user.id, sync);
}
}
@@ -1691,63 +1713,75 @@ public final class Settings implements Watchable, Snappable {
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();
+
+ synchronized (mPackageRestrictionsLock) {
+ 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.
+ }
+ }
+
+ if (str == null && userPackagesStateFile.exists()) {
+ try {
+ str = new FileInputStream(userPackagesStateFile);
+ if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile);
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Error reading settings: " + e);
+ Slog.wtf(TAG, "Error reading package manager stopped packages", e);
}
- } 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; "
+ if (str == null) {
+ 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*/,
- 0 /*distractionFlags*/,
- null /*suspendParams*/,
- false /*instantApp*/,
- false /*virtualPreload*/,
- null /*lastDisableAppCaller*/,
- null /*enabledComponents*/,
- null /*disabledComponents*/,
- PackageManager.INSTALL_REASON_UNKNOWN,
- PackageManager.UNINSTALL_REASON_UNKNOWN,
- null /*harmfulAppWarning*/,
- null /* splashScreenTheme*/,
- 0 /*firstInstallTime*/
- );
- }
- return;
- }
- str = new FileInputStream(userPackagesStateFile);
- if (DEBUG_MU) Log.i(TAG, "Reading " + userPackagesStateFile);
+ // 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*/,
+ 0 /*distractionFlags*/,
+ null /*suspendParams*/,
+ false /*instantApp*/,
+ false /*virtualPreload*/,
+ null /*lastDisableAppCaller*/,
+ null /*enabledComponents*/,
+ null /*disabledComponents*/,
+ PackageManager.INSTALL_REASON_UNKNOWN,
+ PackageManager.UNINSTALL_REASON_UNKNOWN,
+ null /*harmfulAppWarning*/,
+ null /* splashScreenTheme*/,
+ 0 /*firstInstallTime*/
+ );
}
+ return;
+ }
+
+ try {
final TypedXmlPullParser parser = Xml.resolvePullParser(str);
int type;
@@ -2070,179 +2104,247 @@ public final class Settings implements Watchable, Snappable {
}
}
+ // Default version is writing restrictions asynchronously.
void writePackageRestrictionsLPr(int userId) {
+ writePackageRestrictionsLPr(userId, /*sync=*/false);
+ }
+
+ void writePackageRestrictionsLPr(int userId, boolean sync) {
invalidatePackageCache();
+ final long startTime = SystemClock.uptimeMillis();
+
+ if (sync) {
+ writePackageRestrictions(userId, startTime, sync);
+ } else {
+ if (DEBUG_MU) {
+ Log.i(TAG, "Scheduling deferred IO sync for user=" + userId);
+ }
+ synchronized (mPackageRestrictionsLock) {
+ int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) + 1;
+ mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
+ }
+ Runnable r = () -> writePackageRestrictions(userId, startTime, sync);
+ mHandler.obtainMessage(WRITE_USER_PACKAGE_RESTRICTIONS, r).sendToTarget();
+ }
+ }
+
+ void writePackageRestrictions(Integer[] userIds) {
+ invalidatePackageCache();
+ final long startTime = SystemClock.uptimeMillis();
+ for (int userId : userIds) {
+ writePackageRestrictions(userId, startTime, /*sync=*/true);
+ }
+ }
+
+ void writePackageRestrictions(int userId, long startTime, boolean sync) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
}
- final long startTime = SystemClock.uptimeMillis();
- // 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");
+ final File userPackagesStateFile;
+ final File backupFile;
+ final FileOutputStream fstr;
+
+ synchronized (mPackageRestrictionsLock) {
+ if (!sync) {
+ int pending = mPendingAsyncPackageRestrictionsWrites.get(userId, 0) - 1;
+ if (pending < 0) {
+ Log.i(TAG, "Cancel writing package restrictions for user=" + userId);
return;
}
- } else {
- userPackagesStateFile.delete();
- Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
+ mPendingAsyncPackageRestrictionsWrites.put(userId, pending);
+ }
+
+ // Keep the old stopped packages around until we know the new ones have
+ // been successfully written.
+ userPackagesStateFile = getUserPackagesStateFile(userId);
+ 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 {
+ fstr = new FileOutputStream(userPackagesStateFile);
+ // File is created, set permissions.
+ FileUtils.setPermissions(userPackagesStateFile.toString(),
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ -1, -1);
+ } 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);
+ return;
}
}
try {
- final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
- final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ synchronized (mLock) {
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(fstr);
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+ true);
- serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
+ serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
- if (DEBUG_MU) {
- Slogf.i(TAG, "Writing %s (%d packages)", userPackagesStateFile,
- mPackages.values().size());
- }
- for (final PackageSetting pkg : mPackages.values()) {
- final PackageUserStateInternal ustate = pkg.readUserState(userId);
if (DEBUG_MU) {
- Log.v(TAG, " pkg=" + pkg.getPackageName()
- + ", installed=" + ustate.isInstalled()
- + ", state=" + ustate.getEnabledState());
- }
+ Slogf.i(TAG, "Writing %s (%d packages)", userPackagesStateFile,
+ mPackages.values().size());
+ }
+ for (final PackageSetting pkg : mPackages.values()) {
+ final PackageUserStateInternal ustate = pkg.readUserState(userId);
+ if (DEBUG_MU) {
+ Log.v(TAG, " pkg=" + pkg.getPackageName()
+ + ", installed=" + ustate.isInstalled()
+ + ", state=" + ustate.getEnabledState());
+ }
- serializer.startTag(null, TAG_PACKAGE);
- serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
- if (ustate.getCeDataInode() != 0) {
- serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.getCeDataInode());
- }
- if (!ustate.isInstalled()) {
- serializer.attributeBoolean(null, ATTR_INSTALLED, false);
- }
- if (ustate.isStopped()) {
- serializer.attributeBoolean(null, ATTR_STOPPED, true);
- }
- if (ustate.isNotLaunched()) {
- serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
- }
- if (ustate.isHidden()) {
- serializer.attributeBoolean(null, ATTR_HIDDEN, true);
- }
- if (ustate.getDistractionFlags() != 0) {
- serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS,
- ustate.getDistractionFlags());
- }
- if (ustate.isSuspended()) {
- serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
- }
- if (ustate.isInstantApp()) {
- serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
- }
- if (ustate.isVirtualPreload()) {
- serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
- }
- if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState());
- if (ustate.getLastDisableAppCaller() != null) {
- serializer.attribute(null, ATTR_ENABLED_CALLER,
- ustate.getLastDisableAppCaller());
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
+ if (ustate.getCeDataInode() != 0) {
+ serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.getCeDataInode());
}
- }
- if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) {
- serializer.attributeInt(null, ATTR_INSTALL_REASON,
- ustate.getInstallReason());
- }
- serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
- ustate.getFirstInstallTime());
- if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) {
- serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
- ustate.getUninstallReason());
- }
- if (ustate.getHarmfulAppWarning() != null) {
- serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
- ustate.getHarmfulAppWarning());
- }
- if (ustate.getSplashScreenTheme() != null) {
- serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
- ustate.getSplashScreenTheme());
- }
- if (ustate.isSuspended()) {
- for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
- final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
- serializer.startTag(null, TAG_SUSPEND_PARAMS);
- serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage);
- final SuspendParams params =
- ustate.getSuspendParams().valueAt(i);
- if (params != null) {
- params.saveToXml(serializer);
+ if (!ustate.isInstalled()) {
+ serializer.attributeBoolean(null, ATTR_INSTALLED, false);
+ }
+ if (ustate.isStopped()) {
+ serializer.attributeBoolean(null, ATTR_STOPPED, true);
+ }
+ if (ustate.isNotLaunched()) {
+ serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
+ }
+ if (ustate.isHidden()) {
+ serializer.attributeBoolean(null, ATTR_HIDDEN, true);
+ }
+ if (ustate.getDistractionFlags() != 0) {
+ serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS,
+ ustate.getDistractionFlags());
+ }
+ if (ustate.isSuspended()) {
+ serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
+ }
+ if (ustate.isInstantApp()) {
+ serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
+ }
+ if (ustate.isVirtualPreload()) {
+ serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
+ }
+ if (ustate.getEnabledState() != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attributeInt(null, ATTR_ENABLED, ustate.getEnabledState());
+ if (ustate.getLastDisableAppCaller() != null) {
+ serializer.attribute(null, ATTR_ENABLED_CALLER,
+ ustate.getLastDisableAppCaller());
}
- serializer.endTag(null, TAG_SUSPEND_PARAMS);
}
- }
- final ArraySet<String> enabledComponents = ustate.getEnabledComponents();
- if (enabledComponents != null && enabledComponents.size() > 0) {
- serializer.startTag(null, TAG_ENABLED_COMPONENTS);
- for (int i = 0; i < enabledComponents.size(); i++) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME,
- enabledComponents.valueAt(i));
- serializer.endTag(null, TAG_ITEM);
+ if (ustate.getInstallReason() != PackageManager.INSTALL_REASON_UNKNOWN) {
+ serializer.attributeInt(null, ATTR_INSTALL_REASON,
+ ustate.getInstallReason());
}
- serializer.endTag(null, TAG_ENABLED_COMPONENTS);
- }
- final ArraySet<String> disabledComponents = ustate.getDisabledComponents();
- if (disabledComponents != null && disabledComponents.size() > 0) {
- serializer.startTag(null, TAG_DISABLED_COMPONENTS);
- for (int i = 0; i < disabledComponents.size(); i++) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME,
- disabledComponents.valueAt(i));
- serializer.endTag(null, TAG_ITEM);
+ serializer.attributeLongHex(null, ATTR_FIRST_INSTALL_TIME,
+ ustate.getFirstInstallTime());
+ if (ustate.getUninstallReason() != PackageManager.UNINSTALL_REASON_UNKNOWN) {
+ serializer.attributeInt(null, ATTR_UNINSTALL_REASON,
+ ustate.getUninstallReason());
+ }
+ if (ustate.getHarmfulAppWarning() != null) {
+ serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
+ ustate.getHarmfulAppWarning());
+ }
+ if (ustate.getSplashScreenTheme() != null) {
+ serializer.attribute(null, ATTR_SPLASH_SCREEN_THEME,
+ ustate.getSplashScreenTheme());
+ }
+ if (ustate.isSuspended()) {
+ for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
+ final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
+ serializer.startTag(null, TAG_SUSPEND_PARAMS);
+ serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage);
+ final SuspendParams params =
+ ustate.getSuspendParams().valueAt(i);
+ if (params != null) {
+ params.saveToXml(serializer);
+ }
+ serializer.endTag(null, TAG_SUSPEND_PARAMS);
+ }
+ }
+ final ArraySet<String> enabledComponents = ustate.getEnabledComponents();
+ if (enabledComponents != null && enabledComponents.size() > 0) {
+ serializer.startTag(null, TAG_ENABLED_COMPONENTS);
+ for (int i = 0; i < enabledComponents.size(); i++) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME,
+ enabledComponents.valueAt(i));
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_ENABLED_COMPONENTS);
+ }
+ final ArraySet<String> disabledComponents = ustate.getDisabledComponents();
+ if (disabledComponents != null && disabledComponents.size() > 0) {
+ serializer.startTag(null, TAG_DISABLED_COMPONENTS);
+ for (int i = 0; i < disabledComponents.size(); i++) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME,
+ disabledComponents.valueAt(i));
+ serializer.endTag(null, TAG_ITEM);
+ }
+ serializer.endTag(null, TAG_DISABLED_COMPONENTS);
}
- serializer.endTag(null, TAG_DISABLED_COMPONENTS);
- }
- serializer.endTag(null, TAG_PACKAGE);
- }
+ serializer.endTag(null, TAG_PACKAGE);
+ }
- writePreferredActivitiesLPr(serializer, userId, true);
- writePersistentPreferredActivitiesLPr(serializer, userId);
- writeCrossProfileIntentFiltersLPr(serializer, userId);
- writeDefaultAppsLPr(serializer, userId);
- writeBlockUninstallPackagesLPr(serializer, userId);
+ writePreferredActivitiesLPr(serializer, userId, true);
+ writePersistentPreferredActivitiesLPr(serializer, userId);
+ writeCrossProfileIntentFiltersLPr(serializer, userId);
+ writeDefaultAppsLPr(serializer, userId);
+ writeBlockUninstallPackagesLPr(serializer, userId);
- serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
+ serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
- serializer.endDocument();
+ serializer.endDocument();
+ }
fstr.flush();
FileUtils.sync(fstr);
- fstr.close();
+ IoUtils.closeQuietly(fstr);
- // 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);
+ synchronized (mPackageRestrictionsLock) {
+ // File is created, set permissions.
+ FileUtils.setPermissions(userPackagesStateFile.toString(),
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ -1, -1);
+ // New settings successfully written, old ones are no longer needed.
+ backupFile.delete();
+ }
+
+ if (DEBUG_MU) {
+ Log.i(TAG, "New settings successfully written for user=" + userId + ": "
+ + userPackagesStateFile);
+ }
com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
"package-user-" + userId, SystemClock.uptimeMillis() - startTime);
// Done, all is good!
return;
- } catch(java.io.IOException e) {
+ } 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);
@@ -2453,7 +2555,7 @@ public final class Settings implements Watchable, Snappable {
}
}
- void writeLPr(@NonNull Computer computer) {
+ void writeLPr(@NonNull Computer computer, boolean sync) {
//Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
final long startTime = SystemClock.uptimeMillis();
@@ -2578,7 +2680,7 @@ public final class Settings implements Watchable, Snappable {
writeKernelMappingLPr();
writePackageListLPr();
- writeAllUsersPackageRestrictionsLPr();
+ writeAllUsersPackageRestrictionsLPr(sync);
writeAllRuntimePermissionsLPr();
com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
"package", SystemClock.uptimeMillis() - startTime);
@@ -3213,7 +3315,7 @@ public final class Settings implements Watchable, Snappable {
mBackupStoppedPackagesFilename.delete();
mStoppedPackagesFilename.delete();
// Migrate to new file format
- writePackageRestrictionsLPr(UserHandle.USER_SYSTEM);
+ writePackageRestrictionsLPr(UserHandle.USER_SYSTEM, /*sync=*/true);
} else {
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id, originalFirstInstallTimes);
@@ -4284,10 +4386,15 @@ public final class Settings implements Watchable, Snappable {
entry.getValue().removeUser(userId);
}
mPreferredActivities.remove(userId);
- File file = getUserPackagesStateFile(userId);
- file.delete();
- file = getUserPackagesStateBackupFile(userId);
- file.delete();
+
+ synchronized (mPackageRestrictionsLock) {
+ File file = getUserPackagesStateFile(userId);
+ file.delete();
+ file = getUserPackagesStateBackupFile(userId);
+ file.delete();
+ mPendingAsyncPackageRestrictionsWrites.delete(userId);
+ }
+
removeCrossProfileIntentFiltersLPw(userId);
mRuntimePermissionsPersistence.onUserRemoved(userId);
@@ -4332,7 +4439,7 @@ public final class Settings implements Watchable, Snappable {
if (mVerifierDeviceIdentity == null) {
mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
- writeLPr(computer);
+ writeLPr(computer, /*sync=*/false);
}
return mVerifierDeviceIdentity;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 88932b06db82..3727d660f9a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -25,6 +25,8 @@ import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
import static android.content.pm.parsing.FrameworkParsingPackageUtils.parsePublicKey;
import static android.content.res.Resources.ID_NULL;
+import static com.android.server.pm.PackageManagerService.WRITE_USER_PACKAGE_RESTRICTIONS;
+
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
@@ -32,6 +34,7 @@ import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -45,6 +48,7 @@ import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.os.BaseBundle;
+import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
@@ -69,6 +73,7 @@ import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.testutils.TestHandler;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableTester;
import com.android.server.utils.WatchedArrayMap;
@@ -91,6 +96,7 @@ import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.PriorityQueue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
@@ -116,6 +122,10 @@ public class PackageManagerSettingsTests {
final ArrayMap<String, Long> mOrigFirstInstallTimes = new ArrayMap<>();
+ final TestHandler mHandler = new TestHandler((@NonNull Message msg) -> {
+ return true;
+ });
+
@Before
public void initializeMocks() {
MockitoAnnotations.initMocks(this);
@@ -150,7 +160,7 @@ public class PackageManagerSettingsTests {
assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
// write out, read back in and verify the same
- settings.writeLPr(computer);
+ settings.writeLPr(computer, /*sync=*/true);
assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}
@@ -180,7 +190,7 @@ public class PackageManagerSettingsTests {
writeOldFiles();
Settings settings = makeSettings();
assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
- settings.writeLPr(computer);
+ settings.writeLPr(computer, /*sync=*/true);
// Create Settings again to make it read from the new files
settings = makeSettings();
@@ -326,14 +336,14 @@ public class PackageManagerSettingsTests {
.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND)
.build();
- ps1.modifyUserState(0).putSuspendParams( "suspendingPackage1",
+ ps1.modifyUserState(0).putSuspendParams("suspendingPackage1",
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- ps1.modifyUserState(0).putSuspendParams( "suspendingPackage2",
+ ps1.modifyUserState(0).putSuspendParams("suspendingPackage2",
new SuspendParams(dialogInfo2, appExtras2, launcherExtras2));
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
watcher.verifyChangeReported("put package 1");
- ps2.modifyUserState(0).putSuspendParams( "suspendingPackage3",
+ ps2.modifyUserState(0).putSuspendParams("suspendingPackage3",
new SuspendParams(null, appExtras1, null));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
watcher.verifyChangeReported("put package 2");
@@ -342,7 +352,7 @@ public class PackageManagerSettingsTests {
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
watcher.verifyChangeReported("put package 3");
- settingsUnderTest.writePackageRestrictionsLPr(0);
+ settingsUnderTest.writePackageRestrictionsLPr(0, /*sync=*/true);
watcher.verifyChangeReported("writePackageRestrictions");
settingsUnderTest.mPackages.clear();
@@ -407,48 +417,232 @@ public class PackageManagerSettingsTests {
assertThat(defaultSetting.getUserStateOrDefault(0).isSuspended(), is(false));
}
- @Test
- public void testReadWritePackageRestrictions_distractionFlags() {
- final Settings settingsUnderTest = makeSettings();
+ private void populateDefaultSettings(Settings settings) {
+ settings.mPackages.clear();
+ settings.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ settings.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+ settings.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+ }
+
+ private void verifyDefaultDistractionFlags(Settings settings) {
+ final PackageUserState readPus1 = settings.mPackages.get(PACKAGE_NAME_1)
+ .readUserState(0);
+ assertThat(readPus1.getDistractionFlags(), is(0));
+
+ final PackageUserState readPus2 = settings.mPackages.get(PACKAGE_NAME_2)
+ .readUserState(0);
+ assertThat(readPus2.getDistractionFlags(), is(0));
+
+ final PackageUserState readPus3 = settings.mPackages.get(PACKAGE_NAME_3)
+ .readUserState(0);
+ assertThat(readPus3.getDistractionFlags(), is(0));
+ }
+
+ private void populateDistractionFlags(Settings settings) {
+ settings.mPackages.clear();
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
final int distractionFlags1 = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
ps1.setDistractionFlags(distractionFlags1, 0);
- settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+ settings.mPackages.put(PACKAGE_NAME_1, ps1);
final int distractionFlags2 = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS
| PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
ps2.setDistractionFlags(distractionFlags2, 0);
- settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+ settings.mPackages.put(PACKAGE_NAME_2, ps2);
final int distractionFlags3 = PackageManager.RESTRICTION_NONE;
ps3.setDistractionFlags(distractionFlags3, 0);
- settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+ settings.mPackages.put(PACKAGE_NAME_3, ps3);
+ }
- settingsUnderTest.writePackageRestrictionsLPr(0);
+ private void verifyDistractionFlags(Settings settings) {
+ final int distractionFlags1 = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ final int distractionFlags2 = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS
+ | PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ final int distractionFlags3 = PackageManager.RESTRICTION_NONE;
- settingsUnderTest.mPackages.clear();
- settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
- settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
- settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
- // now read and verify
- settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
- final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+ final PackageUserState readPus1 = settings.mPackages.get(PACKAGE_NAME_1)
.readUserState(0);
assertThat(readPus1.getDistractionFlags(), is(distractionFlags1));
- final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+ final PackageUserState readPus2 = settings.mPackages.get(PACKAGE_NAME_2)
.readUserState(0);
assertThat(readPus2.getDistractionFlags(), is(distractionFlags2));
- final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+ final PackageUserState readPus3 = settings.mPackages.get(PACKAGE_NAME_3)
.readUserState(0);
assertThat(readPus3.getDistractionFlags(), is(distractionFlags3));
}
@Test
+ public void testReadWritePackageRestrictions_distractionFlags() {
+ final Settings settingsUnderTest = makeSettings();
+
+ populateDistractionFlags(settingsUnderTest);
+ settingsUnderTest.writePackageRestrictionsLPr(0, /*sync=*/true);
+
+ // now read and verify
+ populateDefaultSettings(settingsUnderTest);
+ settingsUnderTest.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsUnderTest);
+ }
+
+ @Test
+ public void testReadWritePackageRestrictionsAsync() {
+ final Settings settingsWrite = makeSettings();
+ final Settings settingsRead = makeSettings();
+ mHandler.clear();
+
+ // Initial empty state.
+ settingsWrite.removeUserLPw(0);
+
+ // Schedule 3 async writes.
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+
+ PriorityQueue<TestHandler.MsgInfo> messages = mHandler.getPendingMessages();
+ assertEquals(3, messages.size());
+ final Runnable asyncWrite1 = (Runnable) messages.poll().message.obj;
+ final Runnable asyncWrite2 = (Runnable) messages.poll().message.obj;
+ final Runnable asyncWrite3 = (Runnable) messages.poll().message.obj;
+ mHandler.clear();
+
+ // First read should read old data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDefaultDistractionFlags(settingsRead);
+
+ // 1st write: with flags.
+ populateDistractionFlags(settingsWrite);
+ asyncWrite1.run();
+
+ // New data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+
+ // 2nd write: without.
+ populateDefaultSettings(settingsWrite);
+ asyncWrite2.run();
+
+ // Default data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDefaultDistractionFlags(settingsRead);
+
+ // 3rd write: with flags.
+ populateDistractionFlags(settingsWrite);
+ asyncWrite3.run();
+
+ // New data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+ }
+
+ @Test
+ public void testReadWritePackageRestrictionsAsyncUserRemoval() {
+ final Settings settingsWrite = makeSettings();
+ final Settings settingsRead = makeSettings();
+ mHandler.clear();
+
+ // Initial empty state.
+ settingsWrite.removeUserLPw(0);
+
+ // 2 async writes.
+ populateDistractionFlags(settingsWrite);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+
+ PriorityQueue<TestHandler.MsgInfo> messages = mHandler.getPendingMessages();
+ assertEquals(2, messages.size());
+ final Runnable asyncWrite1 = (Runnable) messages.poll().message.obj;
+ final Runnable asyncWrite2 = (Runnable) messages.poll().message.obj;
+ mHandler.clear();
+
+ // First read should not read anything.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDefaultDistractionFlags(settingsRead);
+
+ // 1st write.
+ asyncWrite1.run();
+
+ // Second read should read new data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+
+ // Now remove the user.
+ settingsWrite.removeUserLPw(0);
+
+ // 2nd write.
+ asyncWrite2.run();
+
+ // Re-read and verify that nothing was read.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDefaultDistractionFlags(settingsRead);
+ }
+
+ @Test
+ public void testReadWritePackageRestrictionsSyncAfterAsync() {
+ final Settings settingsWrite = makeSettings();
+ final Settings settingsRead = makeSettings();
+ mHandler.clear();
+
+ // Initial state, distraction flags populated.
+ populateDistractionFlags(settingsWrite);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/true);
+
+ // 2 async writes of empty distraction flags.
+ populateDefaultSettings(settingsWrite);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+ settingsWrite.writePackageRestrictionsLPr(0, /*sync=*/false);
+
+ PriorityQueue<TestHandler.MsgInfo> messages = mHandler.getPendingMessages();
+ assertEquals(2, messages.size());
+ final Runnable asyncWrite1 = (Runnable) messages.poll().message.obj;
+ final Runnable asyncWrite2 = (Runnable) messages.poll().message.obj;
+
+ // First read should use read initial data (with flags).
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+
+ // 1st write.
+ asyncWrite1.run();
+
+ // Second read should read updated data.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDefaultDistractionFlags(settingsRead);
+
+ // Sync write with flags - overrides all async writes.
+ populateDistractionFlags(settingsWrite);
+ settingsWrite.writeAllUsersPackageRestrictionsLPr(/*sync=*/true);
+
+ // Expect removeMessages call.
+ assertFalse(mHandler.hasMessages(WRITE_USER_PACKAGE_RESTRICTIONS));
+
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+
+ // 2nd write.
+ asyncWrite2.run();
+
+ // Re-read and verify.
+ populateDefaultSettings(settingsRead);
+ settingsRead.readPackageRestrictionsLPr(0, mOrigFirstInstallTimes);
+ verifyDistractionFlags(settingsRead);
+ }
+
+ @Test
public void testWriteReadUsesStaticLibraries() {
final Settings settingsUnderTest = makeSettings();
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
@@ -473,7 +667,7 @@ public class PackageManagerSettingsTests {
ps2.setUsesStaticLibrariesVersions(new long[] { 34 });
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
- settingsUnderTest.writeLPr(computer);
+ settingsUnderTest.writeLPr(computer, /*sync=*/true);
settingsUnderTest.mPackages.clear();
settingsUnderTest.mDisabledSysPackages.clear();
@@ -538,7 +732,7 @@ public class PackageManagerSettingsTests {
ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 });
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
- settingsUnderTest.writeLPr(computer);
+ settingsUnderTest.writeLPr(computer, /*sync=*/true);
settingsUnderTest.mPackages.clear();
settingsUnderTest.mDisabledSysPackages.clear();
@@ -1548,7 +1742,8 @@ public class PackageManagerSettingsTests {
private Settings makeSettings() {
return new Settings(InstrumentationRegistry.getContext().getFilesDir(),
mRuntimePermissionsPersistence, mPermissionDataProvider,
- mDomainVerificationManager, null, new PackageManagerTracedLock());
+ mDomainVerificationManager, mHandler,
+ new PackageManagerTracedLock());
}
private void verifyKeySetMetaData(Settings settings)
@@ -1610,4 +1805,5 @@ public class PackageManagerSettingsTests {
private AndroidPackage mockAndroidPackage(PackageSetting pkgSetting) {
return PackageImpl.forTesting(pkgSetting.getPackageName()).hideAsParsed().hideAsFinal();
}
+
}