diff options
| author | 2022-11-22 00:12:28 +0000 | |
|---|---|---|
| committer | 2022-11-22 00:12:28 +0000 | |
| commit | 1d0f68c5a65c0420c539a986ac0815f87542150f (patch) | |
| tree | 6e9e29e6fbdccc58f41cb24c48190103e7585958 | |
| parent | 0153dd58d9269ad017ba1ef5e36fbb9d33151f96 (diff) | |
| parent | 3ddd1a4289896dddb20caaa792285cd018c1b137 (diff) | |
Merge "Offload IO to Handler thread."
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(); } + } |