Offload IO to Handler thread.
Bug: 252961134 Test: atest PackageManagerSettingsTests Change-Id: I11de05fe3bc0d79892a45d45412aca266394c548
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -2900,9 +2931,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3966,7 +3997,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6865,9 +6896,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
|
||||
|
||||
@@ -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;
|
||||
@@ -375,6 +375,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)
|
||||
@@ -1469,31 +1476,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));
|
||||
}
|
||||
|
||||
// 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(getUserSystemDirectory(userId), "package-restrictions-backup.xml");
|
||||
}
|
||||
|
||||
private File getUserRuntimePermissionsFile(int userId) {
|
||||
// TODO: Implement a cleaner solution when adding tests.
|
||||
// This instead of Environment.getUserSystemDirectory(userId) to support testing.
|
||||
File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
|
||||
return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
|
||||
}
|
||||
|
||||
private File getUserPackagesStateBackupFile(int userId) {
|
||||
return new File(Environment.getUserSystemDirectory(userId),
|
||||
"package-restrictions-backup.xml");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1684,63 +1706,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;
|
||||
@@ -2063,179 +2097,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());
|
||||
}
|
||||
|
||||
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());
|
||||
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());
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
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.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());
|
||||
}
|
||||
serializer.endTag(null, TAG_DISABLED_COMPONENTS);
|
||||
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_PACKAGE);
|
||||
}
|
||||
|
||||
serializer.endTag(null, TAG_PACKAGE);
|
||||
writePreferredActivitiesLPr(serializer, userId, true);
|
||||
writePersistentPreferredActivitiesLPr(serializer, userId);
|
||||
writeCrossProfileIntentFiltersLPr(serializer, userId);
|
||||
writeDefaultAppsLPr(serializer, userId);
|
||||
writeBlockUninstallPackagesLPr(serializer, userId);
|
||||
|
||||
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
|
||||
|
||||
serializer.endDocument();
|
||||
}
|
||||
|
||||
writePreferredActivitiesLPr(serializer, userId, true);
|
||||
writePersistentPreferredActivitiesLPr(serializer, userId);
|
||||
writeCrossProfileIntentFiltersLPr(serializer, userId);
|
||||
writeDefaultAppsLPr(serializer, userId);
|
||||
writeBlockUninstallPackagesLPr(serializer, userId);
|
||||
|
||||
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
|
||||
|
||||
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);
|
||||
@@ -2446,7 +2548,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();
|
||||
@@ -2569,7 +2671,7 @@ public final class Settings implements Watchable, Snappable {
|
||||
|
||||
writeKernelMappingLPr();
|
||||
writePackageListLPr();
|
||||
writeAllUsersPackageRestrictionsLPr();
|
||||
writeAllUsersPackageRestrictionsLPr(sync);
|
||||
writeAllRuntimePermissionsLPr();
|
||||
com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
|
||||
"package", SystemClock.uptimeMillis() - startTime);
|
||||
@@ -3200,7 +3302,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);
|
||||
@@ -4271,10 +4373,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);
|
||||
@@ -4319,7 +4426,7 @@ public final class Settings implements Watchable, Snappable {
|
||||
if (mVerifierDeviceIdentity == null) {
|
||||
mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
|
||||
|
||||
writeLPr(computer);
|
||||
writeLPr(computer, /*sync=*/false);
|
||||
}
|
||||
|
||||
return mVerifierDeviceIdentity;
|
||||
|
||||
@@ -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,47 +417,231 @@ 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();
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user