Loading services/core/java/com/android/server/pm/Settings.java +94 −35 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.IndentingPrintWriter; Loading Loading @@ -370,6 +371,8 @@ public final class Settings implements Watchable, Snappable { // Current settings file. private final File mSettingsFilename; // Reserve copy of the current settings file. private final File mSettingsReserveCopyFilename; // Previous settings file. // Removed when the current settings file successfully stored. private final File mPreviousSettingsFilename; Loading Loading @@ -640,6 +643,7 @@ public final class Settings implements Watchable, Snappable { mRuntimePermissionsPersistence = null; mPermissionDataProvider = null; mSettingsFilename = null; mSettingsReserveCopyFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -711,6 +715,7 @@ public final class Settings implements Watchable, Snappable { |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); mSettingsFilename = new File(mSystemDir, "packages.xml"); mSettingsReserveCopyFilename = new File(mSystemDir, "packages.xml.reservecopy"); mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID); Loading Loading @@ -752,6 +757,7 @@ public final class Settings implements Watchable, Snappable { mLock = null; mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence; mSettingsFilename = null; mSettingsReserveCopyFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -2681,12 +2687,25 @@ public final class Settings implements Watchable, Snappable { // New settings successfully written, old ones are no longer needed. mPreviousSettingsFilename.delete(); mSettingsReserveCopyFilename.delete(); FileUtils.setPermissions(mSettingsFilename.toString(), FileUtils.S_IRUSR|FileUtils.S_IWUSR |FileUtils.S_IRGRP|FileUtils.S_IWGRP, FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); try { FileUtils.copy(mSettingsFilename, mSettingsReserveCopyFilename); } catch (IOException e) { Slog.e(TAG, "Failed to backup settings", e); } try { VerityUtils.setUpFsverity(mSettingsFilename.getAbsolutePath()); VerityUtils.setUpFsverity(mSettingsReserveCopyFilename.getAbsolutePath()); } catch (IOException e) { Slog.e(TAG, "Failed to verity-protect settings", e); } writeKernelMappingLPr(); writePackageListLPr(); writeAllUsersPackageRestrictionsLPr(sync); Loading Loading @@ -3117,11 +3136,23 @@ public final class Settings implements Watchable, Snappable { } } boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) { boolean readSettingsLPw(@NonNull Computer computer, @NonNull List<UserInfo> users, ArrayMap<String, Long> originalFirstInstallTimes) { mPendingPackages.clear(); mPastSignatures.clear(); mKeySetRefs.clear(); mInstallerPackages.clear(); originalFirstInstallTimes.clear(); File file = null; FileInputStream str = null; try { // Check if the previous write was incomplete. if (mPreviousSettingsFilename.exists()) { try { str = new FileInputStream(mPreviousSettingsFilename); file = mPreviousSettingsFilename; str = new FileInputStream(file); mReadMessages.append("Reading from backup settings file\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup settings file"); Loading @@ -3132,35 +3163,36 @@ public final class Settings implements Watchable, Snappable { + mSettingsFilename); mSettingsFilename.delete(); } // Ignore reserve copy as well. mSettingsReserveCopyFilename.delete(); } catch (java.io.IOException e) { // We'll try for the normal settings file. } } mPendingPackages.clear(); mPastSignatures.clear(); mKeySetRefs.clear(); mInstallerPackages.clear(); // If any user state doesn't have a first install time, e.g., after an OTA, // use the pre OTA firstInstallTime timestamp. This is because we migrated from per package // firstInstallTime to per user-state. Without this, OTA can cause this info to be lost. final ArrayMap<String, Long> originalFirstInstallTimes = new ArrayMap<>(); try { if (str == null) { if (!mSettingsFilename.exists()) { if (mSettingsFilename.exists()) { // Using packages.xml. file = mSettingsFilename; str = new FileInputStream(file); } else if (mSettingsReserveCopyFilename.exists()) { // Using reserve copy. file = mSettingsReserveCopyFilename; str = new FileInputStream(file); mReadMessages.append("Reading from reserve copy settings file\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from reserve copy settings file"); } } if (str == null) { // No available data sources. mReadMessages.append("No settings file found\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "No settings file; creating initial state"); // It's enough to just touch version details to create them // with default values // Not necessary, but will avoid wtf-s in the "finally" section. findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); return false; } str = new FileInputStream(mSettingsFilename); } final TypedXmlPullParser parser = Xml.resolvePullParser(str); int type; Loading Loading @@ -3280,6 +3312,33 @@ public final class Settings implements Watchable, Snappable { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); // Remove corrupted file and retry. Slog.e(TAG, "Error reading package manager settings, removing " + file + " and retrying.", e); file.delete(); // Ignore the result to not mark this as a "first boot". readSettingsLPw(computer, users, originalFirstInstallTimes); } return true; } /** * @return false if settings file is missing (i.e. during first boot), true otherwise */ boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) { // If any user state doesn't have a first install time, e.g., after an OTA, // use the pre OTA firstInstallTime timestamp. This is because we migrated from per package // firstInstallTime to per user-state. Without this, OTA can cause this info to be lost. final ArrayMap<String, Long> originalFirstInstallTimes = new ArrayMap<>(); try { if (!readSettingsLPw(computer, users, originalFirstInstallTimes)) { return false; } } finally { if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) { Slog.wtf(PackageManagerService.TAG, Loading services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +79 −4 Original line number Diff line number Diff line Loading @@ -92,8 +92,11 @@ import org.mockito.MockitoAnnotations; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.security.PublicKey; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.PriorityQueue; Loading Loading @@ -141,8 +144,7 @@ public class PackageManagerSettingsTests { /** make sure our initialized KeySetManagerService metadata matches packages.xml */ @Test public void testReadKeySetSettings() throws ReflectiveOperationException, IllegalAccessException { public void testReadKeySetSettings() throws Exception { /* write out files and read */ writeOldFiles(); Settings settings = makeSettings(); Loading @@ -150,6 +152,29 @@ public class PackageManagerSettingsTests { verifyKeySetMetaData(settings); } // Same as above but use the reserve copy. @Test public void testReadReserveCopyKeySetSettings() throws Exception { /* write out files and read */ writeReserveCopyOldFiles(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } // Same as above but packages.xml is malformed. @Test public void testReadMalformedPackagesXmlKeySetSettings() throws Exception { // write out files writeReserveCopyOldFiles(); // write corrupted packages.xml writeCorruptedPackagesXml(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } /** read in data, write it out, and read it back in. Verify same. */ @Test public void testWriteKeySetSettings() Loading @@ -165,6 +190,39 @@ public class PackageManagerSettingsTests { verifyKeySetMetaData(settings); } // Same as above, but corrupt the primary.xml in process. @Test public void testWriteCorruptReadKeySetSettings() throws Exception { // write out files and read writeOldFiles(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); // write out settings.writeLPr(computer, /*sync=*/true); File filesDir = InstrumentationRegistry.getContext().getFilesDir(); File packageXml = new File(filesDir, "system/packages.xml"); File packagesReserveCopyXml = new File(filesDir, "system/packages.xml.reservecopy"); // Primary. assertTrue(packageXml.exists()); // Reserve copy. assertTrue(packagesReserveCopyXml.exists()); // Temporary backup. assertFalse(new File(filesDir, "packages-backup.xml").exists()); // compare two copies, make sure they are the same assertTrue(Arrays.equals(Files.readAllBytes(Path.of(packageXml.getAbsolutePath())), Files.readAllBytes(Path.of(packagesReserveCopyXml.getAbsolutePath())))); // write corrupted packages.xml writeCorruptedPackagesXml(); // read back in and verify the same assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } @Test public void testSettingsReadOld() { // Write delegateshellthe package files and make sure they're parsed properly the first time Loading Loading @@ -1572,8 +1630,18 @@ public class PackageManagerSettingsTests { } } private void writePackagesXml() { private void writeCorruptedPackagesXml() { writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.xml"), ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" + "<packages>" + "<last-platform-version internal=\"15\" external=\"0\" />" + "<permission-trees>" + "<item name=\"com.google.android.permtree\"" ).getBytes()); } private void writePackagesXml(String fileName) { writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), fileName), ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" + "<packages>" + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />" Loading Loading @@ -1715,7 +1783,14 @@ public class PackageManagerSettingsTests { private void writeOldFiles() { deleteSystemFolder(); writePackagesXml(); writePackagesXml("system/packages.xml"); writeStoppedPackagesXml(); writePackagesList(); } private void writeReserveCopyOldFiles() { deleteSystemFolder(); writePackagesXml("system/packages.xml.reservecopy"); writeStoppedPackagesXml(); writePackagesList(); } Loading Loading
services/core/java/com/android/server/pm/Settings.java +94 −35 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.IndentingPrintWriter; Loading Loading @@ -370,6 +371,8 @@ public final class Settings implements Watchable, Snappable { // Current settings file. private final File mSettingsFilename; // Reserve copy of the current settings file. private final File mSettingsReserveCopyFilename; // Previous settings file. // Removed when the current settings file successfully stored. private final File mPreviousSettingsFilename; Loading Loading @@ -640,6 +643,7 @@ public final class Settings implements Watchable, Snappable { mRuntimePermissionsPersistence = null; mPermissionDataProvider = null; mSettingsFilename = null; mSettingsReserveCopyFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -711,6 +715,7 @@ public final class Settings implements Watchable, Snappable { |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); mSettingsFilename = new File(mSystemDir, "packages.xml"); mSettingsReserveCopyFilename = new File(mSystemDir, "packages.xml.reservecopy"); mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID); Loading Loading @@ -752,6 +757,7 @@ public final class Settings implements Watchable, Snappable { mLock = null; mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence; mSettingsFilename = null; mSettingsReserveCopyFilename = null; mPreviousSettingsFilename = null; mPackageListFilename = null; mStoppedPackagesFilename = null; Loading Loading @@ -2681,12 +2687,25 @@ public final class Settings implements Watchable, Snappable { // New settings successfully written, old ones are no longer needed. mPreviousSettingsFilename.delete(); mSettingsReserveCopyFilename.delete(); FileUtils.setPermissions(mSettingsFilename.toString(), FileUtils.S_IRUSR|FileUtils.S_IWUSR |FileUtils.S_IRGRP|FileUtils.S_IWGRP, FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP, -1, -1); try { FileUtils.copy(mSettingsFilename, mSettingsReserveCopyFilename); } catch (IOException e) { Slog.e(TAG, "Failed to backup settings", e); } try { VerityUtils.setUpFsverity(mSettingsFilename.getAbsolutePath()); VerityUtils.setUpFsverity(mSettingsReserveCopyFilename.getAbsolutePath()); } catch (IOException e) { Slog.e(TAG, "Failed to verity-protect settings", e); } writeKernelMappingLPr(); writePackageListLPr(); writeAllUsersPackageRestrictionsLPr(sync); Loading Loading @@ -3117,11 +3136,23 @@ public final class Settings implements Watchable, Snappable { } } boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) { boolean readSettingsLPw(@NonNull Computer computer, @NonNull List<UserInfo> users, ArrayMap<String, Long> originalFirstInstallTimes) { mPendingPackages.clear(); mPastSignatures.clear(); mKeySetRefs.clear(); mInstallerPackages.clear(); originalFirstInstallTimes.clear(); File file = null; FileInputStream str = null; try { // Check if the previous write was incomplete. if (mPreviousSettingsFilename.exists()) { try { str = new FileInputStream(mPreviousSettingsFilename); file = mPreviousSettingsFilename; str = new FileInputStream(file); mReadMessages.append("Reading from backup settings file\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup settings file"); Loading @@ -3132,35 +3163,36 @@ public final class Settings implements Watchable, Snappable { + mSettingsFilename); mSettingsFilename.delete(); } // Ignore reserve copy as well. mSettingsReserveCopyFilename.delete(); } catch (java.io.IOException e) { // We'll try for the normal settings file. } } mPendingPackages.clear(); mPastSignatures.clear(); mKeySetRefs.clear(); mInstallerPackages.clear(); // If any user state doesn't have a first install time, e.g., after an OTA, // use the pre OTA firstInstallTime timestamp. This is because we migrated from per package // firstInstallTime to per user-state. Without this, OTA can cause this info to be lost. final ArrayMap<String, Long> originalFirstInstallTimes = new ArrayMap<>(); try { if (str == null) { if (!mSettingsFilename.exists()) { if (mSettingsFilename.exists()) { // Using packages.xml. file = mSettingsFilename; str = new FileInputStream(file); } else if (mSettingsReserveCopyFilename.exists()) { // Using reserve copy. file = mSettingsReserveCopyFilename; str = new FileInputStream(file); mReadMessages.append("Reading from reserve copy settings file\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from reserve copy settings file"); } } if (str == null) { // No available data sources. mReadMessages.append("No settings file found\n"); PackageManagerService.reportSettingsProblem(Log.INFO, "No settings file; creating initial state"); // It's enough to just touch version details to create them // with default values // Not necessary, but will avoid wtf-s in the "finally" section. findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); return false; } str = new FileInputStream(mSettingsFilename); } final TypedXmlPullParser parser = Xml.resolvePullParser(str); int type; Loading Loading @@ -3280,6 +3312,33 @@ public final class Settings implements Watchable, Snappable { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); // Remove corrupted file and retry. Slog.e(TAG, "Error reading package manager settings, removing " + file + " and retrying.", e); file.delete(); // Ignore the result to not mark this as a "first boot". readSettingsLPw(computer, users, originalFirstInstallTimes); } return true; } /** * @return false if settings file is missing (i.e. during first boot), true otherwise */ boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) { // If any user state doesn't have a first install time, e.g., after an OTA, // use the pre OTA firstInstallTime timestamp. This is because we migrated from per package // firstInstallTime to per user-state. Without this, OTA can cause this info to be lost. final ArrayMap<String, Long> originalFirstInstallTimes = new ArrayMap<>(); try { if (!readSettingsLPw(computer, users, originalFirstInstallTimes)) { return false; } } finally { if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) { Slog.wtf(PackageManagerService.TAG, Loading
services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +79 −4 Original line number Diff line number Diff line Loading @@ -92,8 +92,11 @@ import org.mockito.MockitoAnnotations; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.security.PublicKey; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.PriorityQueue; Loading Loading @@ -141,8 +144,7 @@ public class PackageManagerSettingsTests { /** make sure our initialized KeySetManagerService metadata matches packages.xml */ @Test public void testReadKeySetSettings() throws ReflectiveOperationException, IllegalAccessException { public void testReadKeySetSettings() throws Exception { /* write out files and read */ writeOldFiles(); Settings settings = makeSettings(); Loading @@ -150,6 +152,29 @@ public class PackageManagerSettingsTests { verifyKeySetMetaData(settings); } // Same as above but use the reserve copy. @Test public void testReadReserveCopyKeySetSettings() throws Exception { /* write out files and read */ writeReserveCopyOldFiles(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } // Same as above but packages.xml is malformed. @Test public void testReadMalformedPackagesXmlKeySetSettings() throws Exception { // write out files writeReserveCopyOldFiles(); // write corrupted packages.xml writeCorruptedPackagesXml(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } /** read in data, write it out, and read it back in. Verify same. */ @Test public void testWriteKeySetSettings() Loading @@ -165,6 +190,39 @@ public class PackageManagerSettingsTests { verifyKeySetMetaData(settings); } // Same as above, but corrupt the primary.xml in process. @Test public void testWriteCorruptReadKeySetSettings() throws Exception { // write out files and read writeOldFiles(); Settings settings = makeSettings(); assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); // write out settings.writeLPr(computer, /*sync=*/true); File filesDir = InstrumentationRegistry.getContext().getFilesDir(); File packageXml = new File(filesDir, "system/packages.xml"); File packagesReserveCopyXml = new File(filesDir, "system/packages.xml.reservecopy"); // Primary. assertTrue(packageXml.exists()); // Reserve copy. assertTrue(packagesReserveCopyXml.exists()); // Temporary backup. assertFalse(new File(filesDir, "packages-backup.xml").exists()); // compare two copies, make sure they are the same assertTrue(Arrays.equals(Files.readAllBytes(Path.of(packageXml.getAbsolutePath())), Files.readAllBytes(Path.of(packagesReserveCopyXml.getAbsolutePath())))); // write corrupted packages.xml writeCorruptedPackagesXml(); // read back in and verify the same assertThat(settings.readLPw(computer, createFakeUsers()), is(true)); verifyKeySetMetaData(settings); } @Test public void testSettingsReadOld() { // Write delegateshellthe package files and make sure they're parsed properly the first time Loading Loading @@ -1572,8 +1630,18 @@ public class PackageManagerSettingsTests { } } private void writePackagesXml() { private void writeCorruptedPackagesXml() { writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.xml"), ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" + "<packages>" + "<last-platform-version internal=\"15\" external=\"0\" />" + "<permission-trees>" + "<item name=\"com.google.android.permtree\"" ).getBytes()); } private void writePackagesXml(String fileName) { writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), fileName), ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" + "<packages>" + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />" Loading Loading @@ -1715,7 +1783,14 @@ public class PackageManagerSettingsTests { private void writeOldFiles() { deleteSystemFolder(); writePackagesXml(); writePackagesXml("system/packages.xml"); writeStoppedPackagesXml(); writePackagesList(); } private void writeReserveCopyOldFiles() { deleteSystemFolder(); writePackagesXml("system/packages.xml.reservecopy"); writeStoppedPackagesXml(); writePackagesList(); } Loading