diff options
author | 2024-05-23 09:34:20 +0000 | |
---|---|---|
committer | 2024-05-26 14:26:25 +0000 | |
commit | 6b046e87217dcb498a07c47cbd8979ff257bf1ff (patch) | |
tree | 865610249e7ac877b6c33bfa8e45d6bf3ce024a4 | |
parent | 9800d7c279a78477e80c0e64fe38157493c0fef3 (diff) |
Fix downgrade wallpaper restore bug
Add a check in TarBackupReader to enable the restore of packages in the V_To_U_Allowlist in the V to U downgrade scenario
Bug: 341732443
Test: atest -v TarBackupReaderTest, manual test (details: https://b.corp.google.com/issues/341732443#comment18)
Change-Id: I12a1f272b17a12abb532a98c0d93f0a9854fcb51
3 files changed, 199 insertions, 4 deletions
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index b414b252cc37..2d99c96452da 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -270,7 +270,8 @@ public class FullRestoreEngine extends RestoreEngine { PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( mBackupManagerService.getPackageManager(), allowApks, info, signatures, - pmi, mUserId, mBackupEligibilityRules); + pmi, mUserId, mBackupEligibilityRules, + mBackupManagerService.getContext()); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index 78a9952d066d..4860a274cfa8 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -31,6 +31,7 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; @@ -53,17 +54,22 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; +import android.os.Build; import android.os.Bundle; import android.os.UserHandle; +import android.provider.Settings; import android.util.Slog; import com.android.server.backup.FileMetadata; +import com.android.server.backup.Flags; import com.android.server.backup.restore.RestorePolicy; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; +import java.util.List; /** * Utility methods to read backup tar file. @@ -390,7 +396,7 @@ public class TarBackupReader { boolean allowApks, FileMetadata info, Signature[] signatures, PackageManagerInternal pmi, int userId, Context context) { return chooseRestorePolicy(packageManager, allowApks, info, signatures, pmi, userId, - BackupEligibilityRules.forBackup(packageManager, pmi, userId, context)); + BackupEligibilityRules.forBackup(packageManager, pmi, userId, context), context); } /** @@ -406,7 +412,8 @@ public class TarBackupReader { */ public RestorePolicy chooseRestorePolicy(PackageManager packageManager, boolean allowApks, FileMetadata info, Signature[] signatures, - PackageManagerInternal pmi, int userId, BackupEligibilityRules eligibilityRules) { + PackageManagerInternal pmi, int userId, BackupEligibilityRules eligibilityRules, + Context context) { if (signatures == null) { return RestorePolicy.IGNORE; } @@ -448,6 +455,16 @@ public class TarBackupReader { pkgInfo, LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); + } else if (isAllowlistedForVToURestore(info, pkgInfo, userId, context)) { + Slog.i(TAG, "Performing a V to U downgrade; package: " + + info.packageName + + " is allowlisted"); + policy = RestorePolicy.ACCEPT; + mBackupManagerMonitorEventSender.monitorEvent( + LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE, + pkgInfo, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); } else { // The data is from a newer version of the app than // is presently installed. That means we can only @@ -751,6 +768,36 @@ public class TarBackupReader { return true; } + // checks the sdk of the target/source device for a B&R operation. + // system components can opt in of V->U restore via allowlist. + @SuppressWarnings("AndroidFrameworkCompatChange") + private boolean isAllowlistedForVToURestore(FileMetadata backupFileInfo, + PackageInfo installedPackageInfo, + int userId, Context context) { + // We assume that the package version matches the sdk (e.g. version 35 means V). + // This is true for most of the system components ( and it is specifically true for those + // that are in the allowlist) + // In order to check if this is a V to U transfer we check if the package version from the + // backup is 35 and on the target is 34. + // We don't need to check the V to U denylist here since a package can only make it + // to TarBackupReader if allowed and not denied (from PerformUnifiedRestoreTask) + + String vToUAllowlist = getVToUAllowlist(context, userId); + List<String> mVToUAllowlist = Arrays.asList(vToUAllowlist.split(",")); + return Flags.enableVToURestoreForSystemComponentsInAllowlist() + && (installedPackageInfo.getLongVersionCode() + == Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + && (backupFileInfo.version > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + && (mVToUAllowlist.contains(installedPackageInfo.packageName)); + } + + private String getVToUAllowlist(Context context, int userId) { + return Settings.Secure.getStringForUser( + context.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, + userId); + } + private static long extractRadix(byte[] data, int offset, int maxChars, int radix) throws IOException { long value = 0; diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java index 33995653870e..396f4da75172 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java @@ -25,6 +25,7 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_V import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE; import static com.google.common.truth.Truth.assertThat; @@ -42,17 +43,23 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.content.pm.SigningDetails; import android.content.pm.SigningInfo; +import android.os.Build; import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; +import android.testing.TestableContext; import androidx.test.InstrumentationRegistry; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.mockingservicestests.R; import com.android.server.backup.FileMetadata; +import com.android.server.backup.Flags; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.restore.PerformAdbRestoreTask; import com.android.server.backup.restore.RestorePolicy; @@ -61,6 +68,7 @@ import com.android.server.backup.testutils.PackageManagerStub; import com.google.common.hash.Hashing; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -86,6 +94,8 @@ public class TarBackupReaderTest { @Mock private BytesReadListener mBytesReadListenerMock; @Mock private IBackupManagerMonitor mBackupManagerMonitorMock; @Mock private PackageManagerInternal mMockPackageManagerInternal; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final PackageManagerStub mPackageManagerStub = new PackageManagerStub(); private Context mContext; @@ -95,7 +105,7 @@ public class TarBackupReaderTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getContext(); + mContext = new TestableContext(ApplicationProvider.getApplicationContext()); mUserId = UserHandle.USER_SYSTEM; } @@ -515,6 +525,107 @@ public class TarBackupReaderTest { @Test public void + chooseRestorePolicy_flagOnNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsIgnore() + throws Exception { + + mSetFlagsRule.enableFlags( + Flags.FLAG_ENABLE_V_TO_U_RESTORE_FOR_SYSTEM_COMPONENTS_IN_ALLOWLIST); + + TarBackupReader tarBackupReader = createTarBackupReader(); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, "test"); + + Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; + FileMetadata info = new FileMetadata(); + info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1; + + PackageInfo packageInfo = createNonRestoreAnyVersionUPackage(); + PackageManagerStub.sPackageInfo = packageInfo; + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); + RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, + false /* allowApks */, info, signatures, mMockPackageManagerInternal, + mUserId, mContext); + + assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mBackupManagerMonitorMock).onEvent(bundleCaptor.capture()); + assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo( + LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE); + } + + + @Test + public void + chooseRestorePolicy_flagOffNotRestoreAnyVersionVToURestoreAndInAllowlist_returnsAccept() + throws Exception { + + mSetFlagsRule.disableFlags( + Flags.FLAG_ENABLE_V_TO_U_RESTORE_FOR_SYSTEM_COMPONENTS_IN_ALLOWLIST); + + TarBackupReader tarBackupReader = createTarBackupReader(); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, "test"); + + Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; + FileMetadata info = new FileMetadata(); + info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1; + + PackageInfo packageInfo = createNonRestoreAnyVersionUPackage(); + PackageManagerStub.sPackageInfo = packageInfo; + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); + RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, + false /* allowApks */, info, signatures, mMockPackageManagerInternal, + mUserId, mContext); + + assertThat(policy).isEqualTo(RestorePolicy.IGNORE); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mBackupManagerMonitorMock).onEvent(bundleCaptor.capture()); + assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo( + LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER); + + } + + @Test + public void + chooseRestorePolicy_flagOnNotRestoreAnyVersionVToURestoreAndNotInAllowlist_returnsIgnore() + throws Exception { + + mSetFlagsRule.enableFlags( + Flags.FLAG_ENABLE_V_TO_U_RESTORE_FOR_SYSTEM_COMPONENTS_IN_ALLOWLIST); + + TarBackupReader tarBackupReader = createTarBackupReader(); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, "pkg"); + + Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; + FileMetadata info = new FileMetadata(); + info.version = Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1; + + PackageInfo packageInfo = createNonRestoreAnyVersionUPackage(); + PackageManagerStub.sPackageInfo = packageInfo; + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); + RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, + false /* allowApks */, info, signatures, mMockPackageManagerInternal, + mUserId, mContext); + + assertThat(policy).isEqualTo(RestorePolicy.IGNORE); + ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mBackupManagerMonitorMock).onEvent(bundleCaptor.capture()); + assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo( + LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER); + } + + @Test + public void chooseRestorePolicy_notRestoreAnyVersionAndVersionMismatchButAllowApksAndHasApk_returnsAcceptIfApk() throws Exception { InputStream inputStream = mContext.getResources().openRawResource( @@ -523,6 +634,10 @@ public class TarBackupReaderTest { inputStream, null); TarBackupReader tarBackupReader = new TarBackupReader(tarInputStream, mBytesReadListenerMock, mBackupManagerMonitorMock); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, "pkg"); + Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; FileMetadata info = new FileMetadata(); info.version = 2; @@ -564,6 +679,10 @@ public class TarBackupReaderTest { inputStream, null); TarBackupReader tarBackupReader = new TarBackupReader(tarInputStream, mBytesReadListenerMock, mBackupManagerMonitorMock); + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, "pkg"); + Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; FileMetadata info = new FileMetadata(); info.version = 2; @@ -596,5 +715,33 @@ public class TarBackupReaderTest { assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo( LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER); } + + private TarBackupReader createTarBackupReader() throws Exception { + InputStream inputStream = mContext.getResources().openRawResource( + R.raw.backup_telephony_no_password); + InputStream tarInputStream = PerformAdbRestoreTask.parseBackupFileHeaderAndReturnTarStream( + inputStream, null); + TarBackupReader tarBackupReader = new TarBackupReader(tarInputStream, + mBytesReadListenerMock, mBackupManagerMonitorMock); + return tarBackupReader; + } + + private PackageInfo createNonRestoreAnyVersionUPackage(){ + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; + packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; + packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; + packageInfo.applicationInfo.backupAgentName = null; + packageInfo.signingInfo = new SigningInfo( + new SigningDetails( + new Signature[]{FAKE_SIGNATURE_1}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, + null, + null)); + packageInfo.versionCode = Build.VERSION_CODES.UPSIDE_DOWN_CAKE; + return packageInfo; + } } |