Loading core/api/current.txt +13 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); core/java/android/app/backup/BackupAgent.java +58 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. Loading core/java/android/app/backup/FullRestoreDataInput.java 0 → 100644 +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; } } Loading
core/api/current.txt +13 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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);
core/java/android/app/backup/BackupAgent.java +58 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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. Loading
core/java/android/app/backup/FullRestoreDataInput.java 0 → 100644 +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; } }