Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f2eaedc authored by beatricemarch's avatar beatricemarch Committed by Beatrice Marchegiani
Browse files

Add a V->U restore allowlist/denylist

A package is eligible for V to U downgrade restore if either:
- The package has restoreAnyVersion set to false and is part of the V to U allowst
- The package has restoreAnyVersion set to true and is not part of the denylist

Bug : 324233962
Test: atest PerformUnifiedRestoreTaskTest
      Manual:check that a package with restoreanyversion=true
      is not restored if in the denylist,
      check that a package with restoreanyversion=false
      is restored if in the allowlist

Change-Id: Id1cf031c593730132ebe24ecab0ffc4a3f87920e
parent ea33379e
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -12481,6 +12481,24 @@ public final class Settings {
        public static void setLocationProviderEnabled(ContentResolver cr,
                String provider, boolean enabled) {
        }
        /**
         * List of system components that support restore in a  V-> U OS downgrade but do not have
         * RestoreAnyVersion set to true. Value set before system restore.
         * This setting is not B&Rd
         * List is stored as a comma-separated string of package names e.g. "a,b,c"
         * @hide
         */
        public static final String V_TO_U_RESTORE_ALLOWLIST = "v_to_u_restore_allowlist";
        /**
         * List of system components that have RestoreAnyVersion set to true but do not support
         * restore in a  V-> U OS downgrade. Value set before system restore.
         * This setting is not B&Rd
         * List is stored as a comma-separated string of package names e.g. "a,b,c"
         * @hide
         */
        public static final String V_TO_U_RESTORE_DENYLIST = "v_to_u_restore_denylist";
    }
    /**
+3 −1
Original line number Diff line number Diff line
@@ -807,7 +807,9 @@ public class SettingsBackupTest {
                 Settings.Secure.UI_TRANSLATION_ENABLED,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_EDGE_HAPTIC_ENABLED,
                 Settings.Secure.DND_CONFIGS_MIGRATED,
                 Settings.Secure.NAVIGATION_MODE_RESTORE);
                 Settings.Secure.NAVIGATION_MODE_RESTORE,
                 Settings.Secure.V_TO_U_RESTORE_ALLOWLIST,
                 Settings.Secure.V_TO_U_RESTORE_DENYLIST);

    @Test
    public void systemSettingsBackedUpOrDenied() {
+9 −0
Original line number Diff line number Diff line
@@ -34,6 +34,15 @@ flag {
    is_fixed_read_only: true
}

flag {
    name: "enable_v_to_u_restore_for_system_components_in_allowlist"
    namespace: "onboarding"
    description: "Enables system components to opt in to support restore in V to U downgrade "
            "scenario without opting in for restoreAnyVersion."
    bug: "324233962"
    is_fixed_read_only: true
}

flag {
    name: "enable_increase_datatypes_for_agent_logging"
    namespace: "onboarding"
+4 −0
Original line number Diff line number Diff line
@@ -177,6 +177,10 @@ public class PackageManagerBackupAgent extends BackupAgent {
        return mHasMetadata;
    }

    public int getSourceSdk() {
        return mStoredSdkVersion;
    }

    public Metadata getRestoredMetadata(String packageName) {
        if (mRestoredSignatures == null) {
            Slog.w(TAG, "getRestoredMetadata() before metadata read!");
+128 −53
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -51,6 +52,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;

@@ -82,6 +84,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -158,6 +161,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
    // When finished call listener
    private final OnTaskFinishedListener mListener;

    // List of packages that support  V-> U downgrade but do not have RestoreAnyVersion set to true.
    private List<String> mVToUAllowlist;

    // List of packages that have RestoreAnyVersion set to true but do not support  V-> U downgrade.
    private List<String> mVToUDenylist;

    // Key/value: bookkeeping about staged data and files for agent access
    private File mBackupDataName;
    private File mStageName;
@@ -172,7 +181,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
    @VisibleForTesting
    PerformUnifiedRestoreTask(
            UserBackupManagerService backupManagerService,
            TransportConnection transportConnection) {
            TransportConnection transportConnection,
            String vToUAllowlist, String vToUDenyList) {
        mListener = null;
        mAgentTimeoutParameters = null;
        mOperationStorage = null;
@@ -183,6 +193,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
        mBackupEligibilityRules = null;
        this.backupManagerService = backupManagerService;
        mBackupManagerMonitorEventSender = new BackupManagerMonitorEventSender(/* monitor= */ null);
        mVToUAllowlist = createVToUList(vToUAllowlist);
        mVToUDenylist = createVToUList(vToUDenyList);
    }

    // This task can assume that the wakelock is properly held for it and doesn't have to worry
@@ -223,6 +235,18 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
                        backupManagerService.getAgentTimeoutParameters(),
                        "Timeout parameters cannot be null");
        mBackupEligibilityRules = backupEligibilityRules;
        mVToUAllowlist =
            createVToUList(
                Settings.Secure.getStringForUser(
                    backupManagerService.getContext().getContentResolver(),
                    Settings.Secure.V_TO_U_RESTORE_ALLOWLIST,
                    mUserId));
        mVToUDenylist =
            createVToUList(
                Settings.Secure.getStringForUser(
                    backupManagerService.getContext().getContentResolver(),
                    Settings.Secure.V_TO_U_RESTORE_DENYLIST,
                    mUserId));

        if (targetPackage != null) {
            // Single package restore
@@ -636,60 +660,29 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
                // Data is from a "newer" version of the app than we have currently
                // installed.  If the app has not declared that it is prepared to
                // handle this case, we do not attempt the restore.
                if (mIsSystemRestore
                    && isVToUDowngrade(mPmAgent.getSourceSdk(), android.os.Build.VERSION.SDK_INT)) {
                    if (isPackageEligibleForVToURestore(mCurrentPackage)) {
                        Slog.i(TAG, "Package " + pkgName
                                + " is eligible for V to U downgrade scenario");
                    } else {
                        String message = "Package not eligible for V to U downgrade scenario";
                        Slog.i(TAG, pkgName + " : " + message);
                        EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, message);
                        nextState = UnifiedRestoreState.RUNNING_QUEUE;
                        return;
                    }
                } else {
                    if ((mCurrentPackage.applicationInfo.flags
                            & ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
                            == 0) {
                    String message =
                            "Source version "
                                    + metaInfo.versionCode
                                    + " > installed version "
                                    + mCurrentPackage.getLongVersionCode();
                    Slog.w(TAG, "Package " + pkgName + ": " + message);
                    Bundle monitoringExtras =
                            mBackupManagerMonitorEventSender.putMonitoringExtra(
                                    null,
                                    BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
                                    metaInfo.versionCode);
                    monitoringExtras =
                            mBackupManagerMonitorEventSender.putMonitoringExtra(
                                    monitoringExtras,
                                    BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY,
                                    false);
                    monitoringExtras = addRestoreOperationTypeToEvent(monitoringExtras);
                    mBackupManagerMonitorEventSender.monitorEvent(
                            BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
                            mCurrentPackage,
                            BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
                            monitoringExtras);
                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, message);
                        // Downgrade scenario with RestoreAnyVersion flag off
                        logDowngradeScenario(/* isRestoreAnyVersion */ false, metaInfo);
                        nextState = UnifiedRestoreState.RUNNING_QUEUE;
                        return;
                    } else {
                    if (DEBUG) {
                        Slog.v(
                                TAG,
                                "Source version "
                                        + metaInfo.versionCode
                                        + " > installed version "
                                        + mCurrentPackage.getLongVersionCode()
                                        + " but restoreAnyVersion");
                        logDowngradeScenario(/* isRestoreAnyVersion */ true, metaInfo);
                    }
                    Bundle monitoringExtras =
                            mBackupManagerMonitorEventSender.putMonitoringExtra(
                                    null,
                                    BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
                                    metaInfo.versionCode);
                    monitoringExtras =
                            mBackupManagerMonitorEventSender.putMonitoringExtra(
                                    monitoringExtras,
                                    BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY,
                                    true);
                    monitoringExtras = addRestoreOperationTypeToEvent(monitoringExtras);
                    mBackupManagerMonitorEventSender.monitorEvent(
                            BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
                            mCurrentPackage,
                            BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
                            monitoringExtras);
                }
            }

@@ -1673,4 +1666,86 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
        return mBackupManagerMonitorEventSender.putMonitoringExtra(
                extras, BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE, RESTORE);
    }

    // checks the sdk of the target/source device for a B&R operation.
    // system components can opt in/out of V->U restore via allowlists. All other apps are
    // not impacted
    @SuppressWarnings("AndroidFrameworkCompatChange")
    @VisibleForTesting
    protected boolean isVToUDowngrade(int sourceSdk, int targetSdk) {
        // We assume that if the source sdk is greater than U then the source is V.
        return Flags.enableVToURestoreForSystemComponentsInAllowlist()
                && (sourceSdk > Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
                && (targetSdk == Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
    }

    @VisibleForTesting
    protected List<String> createVToUList(@Nullable String listString) {
        // The allowlist/denylist is stored as a comma-separated list of package names
        List<String> list = new ArrayList<>();
        if (listString != null) {
            list = Arrays.asList(listString.split(","));
        }
        return list;
    }

    @VisibleForTesting
    protected boolean isPackageEligibleForVToURestore(PackageInfo mCurrentPackage) {
        // A package is eligible for V to U downgrade restore if either:
        //    - The package has restoreAnyVersion set to false and is part of the V to U allowlist
        //      (and not in the denylist)
        //    - The package has restoreAnyVersion set to true and is not part of the denylist
        if (mVToUDenylist.contains(mCurrentPackage.packageName)){
            return false;
        } else if ((mCurrentPackage.applicationInfo.flags
                & ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
                == 0) {
            // package has restoreAnyVersion set to false
            return mVToUAllowlist.contains(mCurrentPackage.packageName);
        } else {
            // package has restoreAnyVersion set to true and is nor in denylist
            return true;
        }
    }

    private void logDowngradeScenario(boolean isRestoreAnyVersion, Metadata metaInfo) {
        Bundle monitoringExtras =
                mBackupManagerMonitorEventSender.putMonitoringExtra(
                        null,
                        BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
                        metaInfo.versionCode);
        String message;
        if (isRestoreAnyVersion) {
            monitoringExtras =
                    mBackupManagerMonitorEventSender.putMonitoringExtra(
                            monitoringExtras,
                            BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY,
                            true);
            message = "Source version "
                    + metaInfo.versionCode
                    + " > installed version "
                    + mCurrentPackage.getLongVersionCode()
                    + " but restoreAnyVersion";
        } else {
            monitoringExtras =
                    mBackupManagerMonitorEventSender.putMonitoringExtra(
                            monitoringExtras,
                            BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY,
                            false);
            message = "Source version "
                    + metaInfo.versionCode
                    + " > installed version "
                    + mCurrentPackage.getLongVersionCode();
            EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, mCurrentPackage.packageName,
                    message);
        }
        Slog.i(TAG, "Package " + mCurrentPackage.packageName + ": " + message);
        monitoringExtras = addRestoreOperationTypeToEvent(monitoringExtras);
        mBackupManagerMonitorEventSender.monitorEvent(
                BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
                mCurrentPackage,
                BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
                monitoringExtras);
    }

}
Loading