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

Commit 9a277a00 authored by Joël Stemmer's avatar Joël Stemmer Committed by Android (Google) Code Review
Browse files

Merge "Add `onRestoreFile` overload that takes a `FullRestoreDataInput` param" into main

parents 103b4288 9d703935
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -9287,6 +9287,7 @@ package android.app.backup {
    method public void onQuotaExceeded(long, long);
    method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
    method public void onRestore(android.app.backup.BackupDataInput, long, android.os.ParcelFileDescriptor) throws java.io.IOException;
    method @FlaggedApi("com.android.server.backup.enable_cross_platform_transfer") public void onRestoreFile(@NonNull android.app.backup.FullRestoreDataInput) throws java.io.IOException;
    method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
    method public void onRestoreFinished();
    field public static final int FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED = 1; // 0x1
@@ -9350,6 +9351,18 @@ package android.app.backup {
    method public int getTransportFlags();
  }
  @FlaggedApi("com.android.server.backup.enable_cross_platform_transfer") public class FullRestoreDataInput {
    method public long getAppVersionCode();
    method @NonNull public String getContentVersion();
    method @NonNull public android.os.ParcelFileDescriptor getData();
    method @NonNull public java.io.File getDestination();
    method public long getMode();
    method public long getModificationTimeSeconds();
    method public long getSize();
    method public int getTransportFlags();
    method public int getType();
  }
  public abstract class RestoreObserver {
    ctor public RestoreObserver();
    method public void onUpdate(int, String);
+58 −18
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app.backup;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.QueuedWork;
@@ -159,23 +160,25 @@ public abstract class BackupAgent extends ContextWrapper {
    /** @hide */
    public static final int TYPE_SYMLINK = 3;

    /** @hide */
    @IntDef(
            prefix = {"TYPE_"},
            value = {TYPE_EOF, TYPE_FILE, TYPE_DIRECTORY, TYPE_SYMLINK})
    @Retention(RetentionPolicy.SOURCE)
    public @interface BackupFileSystemObjectType {}

    /**
     * Flag for {@link BackupDataOutput#getTransportFlags()}, {@link
     * FullBackupDataOutput#getTransportFlags()} and {@link #onMeasureFullBackup(long, int)} only.
     *
     * <p>The transport has client-side encryption enabled. i.e., the user's backup has been
     * encrypted with a key known only to the device, and not to the remote storage solution. Even
     * if an attacker had root access to the remote storage provider they should not be able to
     * decrypt the user's backup data.
     * Transport flag indicating that the transport has client-side encryption enabled. i.e., the
     * user's backup has been encrypted with a key known only to the device, and not to the remote
     * storage solution. Even if an attacker had root access to the remote storage provider they
     * should not be able to decrypt the user's backup data.
     */
    public static final int FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED = 1;

    /**
     * Flag for {@link BackupDataOutput#getTransportFlags()}, {@link
     * FullBackupDataOutput#getTransportFlags()} and {@link #onMeasureFullBackup(long, int)} only.
     *
     * <p>The transport is for a device-to-device transfer. There is no third party or intermediate
     * storage. The user's backup data is sent directly to another device over e.g., USB or WiFi.
     * Transport flag indicating that the transport is used for a device-to-device transfer. There
     * is no third party or intermediate storage. The user's backup data is sent directly to another
     * device over e.g., USB or WiFi.
     */
    public static final int FLAG_DEVICE_TO_DEVICE_TRANSFER = 2;

@@ -188,11 +191,8 @@ public abstract class BackupAgent extends ContextWrapper {
    public static final int FLAG_SKIP_RESTORE_FOR_LAUNCHED_APPS = 1 << 2;

    /**
     * Flag for {@link BackupDataOutput#getTransportFlags()} and {@link
     * FullBackupDataOutput#getTransportFlags()} only.
     *
     * <p>Indicates this is a cross-platform transfer to or from iOS. The user's backup data is sent
     * directly to another device over e.g. USB or WiFi.
     * Transport flag indicating that the transport is used for a cross-platform transfer to or from
     * iOS. The user's backup data is sent directly to another device over e.g. USB or WiFi.
     */
    @FlaggedApi(Flags.FLAG_ENABLE_CROSS_PLATFORM_TRANSFER)
    public static final int FLAG_CROSS_PLATFORM_DATA_TRANSFER_IOS = 1 << 3;
@@ -970,6 +970,32 @@ public abstract class BackupAgent extends ContextWrapper {
        return false;
    }

    /**
     * Handle the data delivered via the given file descriptor during a full restore operation. The
     * agent is given the path to the file's original location as well as its size and metadata.
     *
     * <p>The file descriptor can only be read for {@code size} bytes; attempting to read more data
     * has undefined behavior.
     *
     * <p>The default implementation creates the destination file/directory and populates it with
     * the data from the file descriptor, then sets the file's access mode and modification time to
     * match the restore arguments.
     *
     * @param data A structured wrapper containing the details of the file that's being restored and
     *     additional metadata from the backup.
     * @throws IOException
     */
    @FlaggedApi(Flags.FLAG_ENABLE_CROSS_PLATFORM_TRANSFER)
    public void onRestoreFile(@NonNull FullRestoreDataInput data) throws IOException {
        onRestoreFile(
                data.getData(),
                data.getSize(),
                data.getDestination(),
                data.getType(),
                data.getMode(),
                data.getModificationTimeSeconds());
    }

    /**
     * Handle the data delivered via the given file descriptor during a full restore operation. The
     * agent is given the path to the file's original location as well as its size and metadata.
@@ -1121,7 +1147,21 @@ public abstract class BackupAgent extends ContextWrapper {
            String outPath = outFile.getCanonicalPath();
            if (outPath.startsWith(basePath + File.separatorChar)) {
                if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outPath);
                if (Flags.enableCrossPlatformTransfer()) {
                    onRestoreFile(
                            new FullRestoreDataInput(
                                    data,
                                    size,
                                    outFile,
                                    type,
                                    mode,
                                    mtime,
                                    /* appVersionCode= */ 0,
                                    /* transportFlags= */ 0,
                                    /* contentVersion= */ ""));
                } else {
                    onRestoreFile(data, size, outFile, type, mode, mtime);
                }
                return;
            } else {
                // Attempt to restore to a path outside the file's nominal domain.
+133 −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 android.app.backup;

import android.annotation.CurrentTimeSecondsLong;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.app.backup.BackupAgent.BackupFileSystemObjectType;
import android.app.backup.BackupAgent.BackupTransportFlags;
import android.os.ParcelFileDescriptor;

import com.android.server.backup.Flags;

import java.io.File;

/**
 * Provides the interface through which a {@link BackupAgent} reads entire files from a full backup
 * data set, via its {@link BackupAgent#onRestoreFile(FullRestoreDataInput)} method.
 */
@FlaggedApi(Flags.FLAG_ENABLE_CROSS_PLATFORM_TRANSFER)
public class FullRestoreDataInput {
    private final ParcelFileDescriptor mData;
    private final long mSize;
    private final File mDestination;
    private final int mType;
    private final long mMode;
    private final long mModificationTime;
    private final long mAppVersionCode;
    private final int mTransportFlags;
    private final String mContentVersion;

    /** @hide */
    public FullRestoreDataInput(
            ParcelFileDescriptor data,
            long size,
            File destination,
            @BackupFileSystemObjectType int type,
            long mode,
            long mtime,
            long appVersionCode,
            @BackupTransportFlags int transportFlags,
            String contentVersion) {
        this.mData = data;
        this.mSize = size;
        this.mDestination = destination;
        this.mType = type;
        this.mMode = mode;
        this.mModificationTime = mtime;
        this.mAppVersionCode = appVersionCode;
        this.mTransportFlags = transportFlags;
        this.mContentVersion = contentVersion;
    }

    /** Read-only file descriptor containing the file data. */
    @NonNull
    public ParcelFileDescriptor getData() {
        return mData;
    }

    /** Size of the file in bytes. */
    public long getSize() {
        return mSize;
    }

    /** The file on disk to be restored with the given data. */
    @NonNull
    public File getDestination() {
        return mDestination;
    }

    /**
     * The kind of file system object being restored. This will be either {@link
     * BackupAgent#TYPE_FILE} or {@link BackupAgent#TYPE_DIRECTORY}.
     */
    @BackupFileSystemObjectType
    public int getType() {
        return mType;
    }

    /**
     * The access mode to be assigned to the destination after its data is written. This is in the
     * standard format used by {@code chmod()}.
     */
    public long getMode() {
        return mMode;
    }

    /**
     * A timestamp in the standard Unix epoch that represents the last modification time of the file
     * when it was backed up, suitable to be assigned to the file after its data is written.
     */
    @CurrentTimeSecondsLong
    public long getModificationTimeSeconds() {
        return mModificationTime;
    }

    /** The version code of the app that created the backup. */
    public long getAppVersionCode() {
        return mAppVersionCode;
    }

    /**
     * Flags with additional information about the transport. The transport flags that can be set
     * are defined in {@link BackupAgent}.
     */
    @BackupTransportFlags
    public int getTransportFlags() {
        return mTransportFlags;
    }

    /**
     * Content version set by the source device during a cross-platform transfer. Empty string if
     * the source device did not provide a content version.
     */
    @NonNull
    public String getContentVersion() {
        return mContentVersion;
    }
}