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

Commit 3360b8ce authored by Ebru Kurnaz's avatar Ebru Kurnaz Committed by Android (Google) Code Review
Browse files

Merge "Add BackupHelper for DisplayWindowSettings." into main

parents 822a1130 244795ca
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -76,6 +76,9 @@ public enum DesktopExperienceFlags {
            Flags.FLAG_ENABLE_APP_TO_WEB_EDUCATION_ANIMATION),
    ENABLE_AUTO_RESTART_ON_DISPLAY_MOVE(Flags::enableAutoRestartOnDisplayMove, false,
            Flags.FLAG_ENABLE_AUTO_RESTART_ON_DISPLAY_MOVE),
    ENABLE_BACKUP_AND_RESTORE_DISPLAY_WINDOW_SETTINGS(
            Flags::enableBackupAndRestoreDisplayWindowSettings, false,
            Flags.FLAG_ENABLE_BACKUP_AND_RESTORE_DISPLAY_WINDOW_SETTINGS),
    ENABLE_BLOCK_NON_DESKTOP_DISPLAY_WINDOW_DRAG_BUGFIX(
            Flags::enableBlockNonDesktopDisplayWindowDragBugfix, false,
            Flags.FLAG_ENABLE_BLOCK_NON_DESKTOP_DISPLAY_WINDOW_DRAG_BUGFIX),
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.backup;

import android.app.backup.BlobBackupHelper;
import android.util.Slog;

import com.android.server.LocalServices;
import com.android.server.display.utils.DebugUtils;
import com.android.server.wm.WindowManagerInternal;

public class DisplayWindowSettingsBackupHelper extends BlobBackupHelper {
    private static final String TAG = "DWSBackupHelper";

    // current schema of the backup state blob
    private static final int BLOB_VERSION = 1;

    // key under which the data blob is committed to back up
    private static final String KEY_DISPLAY = "display_window";

    // To enable these logs, run:
    // adb shell setprop persist.log.tag.DWSBackupHelper DEBUG
    // adb reboot
    private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);

    private final int mUserId;

    public DisplayWindowSettingsBackupHelper(int userId) {
        super(BLOB_VERSION, KEY_DISPLAY);
        mUserId = userId;
    }

    @Override
    protected byte[] getBackupPayload(String key) {
        Slog.i(TAG, "getBackupPayload for " + key + " user " + mUserId);
        if (!KEY_DISPLAY.equals(key)) {
            return null;
        }

        WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class);
        if (DEBUG) {
            Slog.d(TAG, "Handling backup of " + key);
        }
        return wmInternal.backupDisplayWindowSettings(mUserId);
    }

    @Override
    protected void applyRestoredPayload(String key, byte[] payload) {
        Slog.i(TAG, "applyRestoredPayload for " + key + " user " + mUserId);
        if (!KEY_DISPLAY.equals(key)) {
            return;
        }

        WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class);
        if (DEBUG) {
            Slog.d(TAG, "Handling restore of " + key);
        }
        wmInternal.restoreDisplayWindowSettings(mUserId, payload);
    }
}
+8 −2
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.window.DesktopExperienceFlags;

import com.android.server.display.DisplayBackupHelper;
import com.android.server.notification.NotificationBackupHelper;
@@ -70,6 +71,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String DISPLAY_HELPER = "display";
    private static final String INPUT_HELPER = "input";
    private static final String WEAR_BACKUP_HELPER = "wear";
    private static final String DISPLAY_WINDOW_HELPER = "display_window";

    // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
    // are also used in the full-backup file format, so must not change unless steps are
@@ -108,7 +110,8 @@ public class SystemBackupAgent extends BackupAgentHelper {
                    COMPANION_HELPER,
                    APP_GENDER_HELPER,
                    SYSTEM_GENDER_HELPER,
                    DISPLAY_HELPER);
                    DISPLAY_HELPER,
                    DISPLAY_WINDOW_HELPER);

    /** Helpers that are enabled for full, non-system users. */
    private static final Set<String> sEligibleHelpersForNonSystemUser =
@@ -154,7 +157,10 @@ public class SystemBackupAgent extends BackupAgentHelper {
        if (com.android.hardware.input.Flags.enableBackupAndRestoreForInputGestures()) {
            addHelperIfEligibleForUser(INPUT_HELPER, new InputBackupHelper(mUserId));
        }

        if (DesktopExperienceFlags.ENABLE_BACKUP_AND_RESTORE_DISPLAY_WINDOW_SETTINGS.isTrue()) {
            addHelperIfEligibleForUser(DISPLAY_WINDOW_HELPER,
                    new DisplayWindowSettingsBackupHelper(mUserId));
        }
        // Add Wear helper only if the device is a watch
        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
            addHelperIfEligibleForUser(WEAR_BACKUP_HELPER, new WearBackupHelper());
+15 −6
Original line number Diff line number Diff line
@@ -19,14 +19,16 @@ package com.android.server.wm;
import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.TYPE_VIRTUAL;

import static com.android.server.wm.DisplayWindowSettingsXmlHelper.DisplayIdentifierType;
import static com.android.server.wm.DisplayWindowSettingsXmlHelper.IDENTIFIER_PORT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.DisplayWindowSettingsXmlHelper.IDENTIFIER_PORT;
import static com.android.server.wm.DisplayWindowSettingsXmlHelper.DisplayIdentifierType;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
import android.content.Context;
import android.os.Environment;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -84,17 +86,22 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
    private ReadableSettings mBaseSettings;
    @NonNull
    private WritableSettings mOverrideSettings;
    @NonNull
    private BackupManager mBackupManager;

    DisplayWindowSettingsProvider() {
    DisplayWindowSettingsProvider(@NonNull Context context) {
        this(new AtomicFileStorage(getVendorSettingsFile()),
                new AtomicFileStorage(getOverrideSettingsFileForUser(USER_SYSTEM)));
                new AtomicFileStorage(getOverrideSettingsFileForUser(USER_SYSTEM)),
                new BackupManager(context));
    }

    @VisibleForTesting
    DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage baseSettingsStorage,
            @NonNull WritableSettingsStorage overrideSettingsStorage) {
            @NonNull WritableSettingsStorage overrideSettingsStorage,
            @NonNull BackupManager backupManager) {
        mBaseSettings = new ReadableSettings(baseSettingsStorage);
        mOverrideSettings = new WritableSettings(overrideSettingsStorage);
        mBackupManager = backupManager;
    }

    /**
@@ -169,6 +176,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
    public void updateOverrideSettings(@NonNull DisplayInfo info,
            @NonNull SettingsEntry overrides) {
        mOverrideSettings.updateSettingsEntry(info, overrides);
        mBackupManager.dataChanged();
    }

    @Override
@@ -179,6 +187,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
    @Override
    public void clearDisplaySettings(@NonNull DisplayInfo info) {
        mOverrideSettings.clearDisplaySettings(info);
        mBackupManager.dataChanged();
    }

    @VisibleForTesting
@@ -366,7 +375,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
    }

    @NonNull
    public static AtomicFile getOverrideSettingsFileForUser(@UserIdInt int userId) {
    static AtomicFile getOverrideSettingsFileForUser(@UserIdInt int userId) {
        final File directory = (userId == USER_SYSTEM)
                ? Environment.getDataDirectory()
                : Environment.getDataSystemCeDirectory(userId);
+20 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntr
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -162,6 +163,25 @@ class DisplayWindowSettingsXmlHelper {
        return success;
    }

    /**
     * Reads display window settings from an {@link InputStream}, filters out device-specific
     * attributes that should not be backed up, and returns the result as a byte array.
     * <p>
     * This method is specifically designed for backup operations. It parses the full settings
     * file and then re-serializes it, omitting attributes like forced width, height, and
     * density, which are not suitable for restoration on a different device.
     *
     * @param stream The input stream to read the settings from. This stream is closed by the
     *               method upon completion.
     * @return A byte array containing the filtered XML data, ready for backup.
     */
    public static byte[] readAndFilterSettings(InputStream stream) {
        FileData data = FileData.readSettings(stream);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        writeSettings(byteArrayOutputStream, data, /* forBackup= */ true);
        return byteArrayOutputStream.toByteArray();
    }

    static final class FileData {
        int mIdentifierType;
        @NonNull
Loading