summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorSergey Poromov <poromov@google.com>2015-12-15 16:26:23 +0100
committerSergey Poromov <poromov@google.com>2016-01-21 19:15:33 +0100
commitfe06bf64d204c459699b0bf6465f9fb69208345e (patch)
tree9c17b7068072e9117c1b665db5d02f6b4cb17097 /core/java/android
parentb325061b196e8bb849356c1beb09de9d18bbe97b (diff)
Introduce BackupManager#requestBackup & BackupObserver API
Introduces a way to request immediate backup for list of packages and receive callbacks on backup progress. Bug: 25688526 Change-Id: Ib826933d44f4ebf2b981f8be366215b2d37847e2
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/backup/BackupManager.java155
-rw-r--r--core/java/android/app/backup/BackupObserver.java59
-rw-r--r--core/java/android/app/backup/BackupProgress.aidl19
-rw-r--r--core/java/android/app/backup/BackupProgress.java69
-rw-r--r--core/java/android/app/backup/BackupTransport.java38
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl16
-rw-r--r--core/java/android/app/backup/IBackupObserver.aidl55
-rw-r--r--core/java/android/app/backup/RestoreSet.java1
8 files changed, 399 insertions, 13 deletions
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 8b7930590126..193a0b2c768d 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -17,13 +17,13 @@
package android.app.backup;
import android.annotation.SystemApi;
-import android.app.backup.RestoreSession;
-import android.app.backup.IBackupManager;
-import android.app.backup.IRestoreSession;
import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.Pair;
/**
* The interface through which an application interacts with the Android backup service to
@@ -59,6 +59,65 @@ import android.util.Log;
public class BackupManager {
private static final String TAG = "BackupManager";
+ // BackupObserver status codes
+ /**
+ * Indicates that backup succeeded.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int SUCCESS = 0;
+
+ /**
+ * Indicates that backup is either not enabled at all or
+ * backup for the package was rejected by backup service
+ * or backup transport,
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_BACKUP_NOT_ALLOWED = -2001;
+
+ /**
+ * The requested app is not installed on the device.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_PACKAGE_NOT_FOUND = -2002;
+
+ /**
+ * The transport for some reason was not in a good state and
+ * aborted the entire backup request. This is a transient
+ * failure and should not be retried immediately.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_TRANSPORT_ABORTED = BackupTransport.TRANSPORT_ERROR;
+
+ /**
+ * Returned when the transport was unable to process the
+ * backup request for a given package, for example if the
+ * transport hit a transient network failure. The remaining
+ * packages provided to {@link #requestBackup(String[], BackupObserver)}
+ * will still be attempted.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_TRANSPORT_PACKAGE_REJECTED =
+ BackupTransport.TRANSPORT_PACKAGE_REJECTED;
+
+ /**
+ * The {@link BackupAgent} for the requested package failed for some reason
+ * and didn't provide appropriate backup data.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
+
private Context mContext;
private static IBackupManager sService;
@@ -365,4 +424,94 @@ public class BackupManager {
}
return 0;
}
+
+ /**
+ * Request an immediate backup, providing an observer to which results of the backup operation
+ * will be published. The Android backup system will decide for each package whether it will
+ * be full app data backup or key/value-pair-based backup.
+ *
+ * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
+ * provided packages using the remote transport.
+ *
+ * @param packages List of package names to backup.
+ * @param observer The {@link BackupObserver} to receive callbacks during the backup
+ * operation.
+ * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
+ * @exception IllegalArgumentException on null or empty {@code packages} param.
+ *
+ * @hide
+ */
+ @SystemApi
+ public int requestBackup(String[] packages, BackupObserver observer) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ BackupObserverWrapper observerWrapper =
+ new BackupObserverWrapper(mContext, observer);
+ return sService.requestBackup(packages, observerWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "requestBackup() couldn't connect");
+ }
+ }
+ return -1;
+ }
+
+ /*
+ * We wrap incoming binder calls with a private class implementation that
+ * redirects them into main-thread actions. This serializes the backup
+ * progress callbacks nicely within the usual main-thread lifecycle pattern.
+ */
+ @SystemApi
+ private class BackupObserverWrapper extends IBackupObserver.Stub {
+ final Handler mHandler;
+ final BackupObserver mObserver;
+
+ static final int MSG_UPDATE = 1;
+ static final int MSG_RESULT = 2;
+ static final int MSG_FINISHED = 3;
+
+ BackupObserverWrapper(Context context, BackupObserver observer) {
+ mHandler = new Handler(context.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE:
+ Pair<String, BackupProgress> obj =
+ (Pair<String, BackupProgress>) msg.obj;
+ mObserver.onUpdate(obj.first, obj.second);
+ break;
+ case MSG_RESULT:
+ mObserver.onResult((String)msg.obj, msg.arg1);
+ break;
+ case MSG_FINISHED:
+ mObserver.backupFinished(msg.arg1);
+ break;
+ default:
+ Log.w(TAG, "Unknown message: " + msg);
+ break;
+ }
+ }
+ };
+ mObserver = observer;
+ }
+
+ // Binder calls into this object just enqueue on the main-thread handler
+ @Override
+ public void onUpdate(String currentPackage, BackupProgress backupProgress) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
+ }
+
+ @Override
+ public void onResult(String currentPackage, int status) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_FINISHED, status, 0, currentPackage));
+ }
+
+ @Override
+ public void backupFinished(int status) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_FINISHED, status, 0));
+ }
+ }
}
diff --git a/core/java/android/app/backup/BackupObserver.java b/core/java/android/app/backup/BackupObserver.java
new file mode 100644
index 000000000000..0dd071e9cc99
--- /dev/null
+++ b/core/java/android/app/backup/BackupObserver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.SystemApi;
+
+/**
+ * Callback class for receiving progress reports during a backup operation. These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class BackupObserver {
+ /**
+ * This method could be called several times for packages with full data backup.
+ * It will tell how much of backup data is already saved and how much is expected.
+ *
+ * @param currentBackupPackage The name of the package that now being backuped.
+ * @param backupProgress Current progress of backup for the package.
+ */
+ public void onUpdate(String currentBackupPackage, BackupProgress backupProgress) {
+ }
+
+ /**
+ * The backup of single package has completed. This method will be called at most one time
+ * for each package and could be not called if backup is failed before and
+ * backupFinished() is called.
+ *
+ * @param currentBackupPackage The name of the package that was backuped.
+ * @param status Zero on success; a nonzero error code if the backup operation failed.
+ */
+ public void onResult(String currentBackupPackage, int status) {
+ }
+
+ /**
+ * The backup process has completed. This method will always be called,
+ * even if no individual package backup operations were attempted.
+ *
+ * @param status Zero on success; a nonzero error code if the backup operation
+ * as a whole failed.
+ */
+ public void backupFinished(int status) {
+ }
+}
diff --git a/core/java/android/app/backup/BackupProgress.aidl b/core/java/android/app/backup/BackupProgress.aidl
new file mode 100644
index 000000000000..c10b9a20f933
--- /dev/null
+++ b/core/java/android/app/backup/BackupProgress.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 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;
+
+parcelable BackupProgress; \ No newline at end of file
diff --git a/core/java/android/app/backup/BackupProgress.java b/core/java/android/app/backup/BackupProgress.java
new file mode 100644
index 000000000000..32e62126a6db
--- /dev/null
+++ b/core/java/android/app/backup/BackupProgress.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about current progress of full data backup
+ * Used in {@link BackupObserver#onUpdate(String, BackupProgress)}
+ *
+ * @hide
+ */
+@SystemApi
+public class BackupProgress implements Parcelable {
+
+ /**
+ * Expected size of data in full backup.
+ */
+ public final long bytesExpected;
+ /**
+ * Amount of backup data that is already saved in backup.
+ */
+ public final long bytesTransferred;
+
+ public BackupProgress(long _bytesExpected, long _bytesTransferred) {
+ bytesExpected = _bytesExpected;
+ bytesTransferred = _bytesTransferred;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(bytesExpected);
+ out.writeLong(bytesTransferred);
+ }
+
+ public static final Creator<BackupProgress> CREATOR = new Creator<BackupProgress>() {
+ public BackupProgress createFromParcel(Parcel in) {
+ return new BackupProgress(in);
+ }
+
+ public BackupProgress[] newArray(int size) {
+ return new BackupProgress[size];
+ }
+ };
+
+ private BackupProgress(Parcel in) {
+ bytesExpected = in.readLong();
+ bytesTransferred = in.readLong();
+ }
+}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 954ccef93b44..4363604cba92 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -50,6 +50,10 @@ public class BackupTransport {
public static final int AGENT_ERROR = -1003;
public static final int AGENT_UNKNOWN = -1004;
+ // Indicates that operation was initiated by user, not a scheduled one.
+ // Transport should ignore its own moratoriums for call with this flag set.
+ public static final int FLAG_USER_INITIATED = 1;
+
IBackupTransport mBinderImpl = new TransportImpl();
public IBinder getBinder() {
@@ -228,13 +232,10 @@ public class BackupTransport {
*
* @param packageInfo The identity of the application whose data is being backed up.
* This specifically includes the signature list for the package.
- * @param data The data stream that resulted from invoking the application's
+ * @param inFd Descriptor of file with data that resulted from invoking the application's
* BackupService.doBackup() method. This may be a pipe rather than a file on
* persistent media, so it may not be seekable.
- * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
- * must be erased prior to the storage of the data provided here. The purpose of this
- * is to provide a guarantee that no stale data exists in the restore set when the
- * device begins providing incremental backups.
+ * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0.
* @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far),
* {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this
* specific package, but allow others to proceed),
@@ -242,6 +243,14 @@ public class BackupTransport {
* {@link BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
* become lost due to inactivity purge or some other reason and needs re-initializing)
*/
+ public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags) {
+ return performBackup(packageInfo, inFd);
+ }
+
+ /**
+ * Legacy version of {@link #performBackup(PackageInfo, ParcelFileDescriptor, int)} that
+ * doesn't use flags parameter.
+ */
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) {
return BackupTransport.TRANSPORT_ERROR;
}
@@ -392,11 +401,21 @@ public class BackupTransport {
* close this file descriptor now; otherwise it should be cached for use during
* succeeding calls to {@link #sendBackupData(int)}, and closed in response to
* {@link #finishBackup()}.
+ * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0.
* @return TRANSPORT_PACKAGE_REJECTED to indicate that the stated application is not
* to be backed up; TRANSPORT_OK to indicate that the OS may proceed with delivering
* backup data; TRANSPORT_ERROR to indicate a fatal error condition that precludes
* performing a backup at this time.
*/
+ public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
+ int flags) {
+ return performFullBackup(targetPackage, socket);
+ }
+
+ /**
+ * Legacy version of {@link #performFullBackup(PackageInfo, ParcelFileDescriptor, int)} that
+ * doesn't use flags parameter.
+ */
public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
return BackupTransport.TRANSPORT_PACKAGE_REJECTED;
}
@@ -568,9 +587,9 @@ public class BackupTransport {
}
@Override
- public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd)
+ public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
throws RemoteException {
- return BackupTransport.this.performBackup(packageInfo, inFd);
+ return BackupTransport.this.performBackup(packageInfo, inFd, flags);
}
@Override
@@ -619,8 +638,9 @@ public class BackupTransport {
}
@Override
- public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
- return BackupTransport.this.performFullBackup(targetPackage, socket);
+ public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
+ int flags) throws RemoteException {
+ return BackupTransport.this.performFullBackup(targetPackage, socket, flags);
}
@Override
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 87e4ef120730..2a1c00f9adc4 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreSession;
import android.os.ParcelFileDescriptor;
@@ -326,4 +327,19 @@ interface IBackupManager {
* no suitable data is available.
*/
long getAvailableRestoreToken(String packageName);
+
+ /**
+ * Request an immediate backup, providing an observer to which results of the backup operation
+ * will be published. The Android backup system will decide for each package whether it will
+ * be full app data backup or key/value-pair-based backup.
+ *
+ * <p>If this method returns zero (meaning success), the OS will attempt to backup all provided
+ * packages using the remote transport.
+ *
+ * @param observer The {@link BackupObserver} to receive callbacks during the backup
+ * operation.
+ *
+ * @return Zero on success; nonzero on error.
+ */
+ int requestBackup(in String[] packages, IBackupObserver observer);
}
diff --git a/core/java/android/app/backup/IBackupObserver.aidl b/core/java/android/app/backup/IBackupObserver.aidl
new file mode 100644
index 000000000000..821a58946311
--- /dev/null
+++ b/core/java/android/app/backup/IBackupObserver.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 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.app.backup.BackupProgress;
+
+/**
+ * Callback class for receiving progress reports during a backup operation. These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+oneway interface IBackupObserver {
+ /**
+ * This method could be called several times for packages with full data backup.
+ * It will tell how much of backup data is already saved and how much is expected.
+ *
+ * @param currentBackupPackage The name of the package that now being backuped.
+ * @param backupProgress Current progress of backup for the package.
+ */
+ void onUpdate(String currentPackage, in BackupProgress backupProgress);
+
+ /**
+ * The backup of single package has completed. This method will be called at most one time
+ * for each package and could be not called if backup is failed before and
+ * backupFinished() is called.
+ *
+ * @param currentBackupPackage The name of the package that was backuped.
+ * @param status Zero on success; a nonzero error code if the backup operation failed.
+ */
+ void onResult(String currentPackage, int status);
+
+ /**
+ * The backup process has completed. This method will always be called,
+ * even if no individual package backup operations were attempted.
+ *
+ * @param status Zero on success; a nonzero error code if the backup operation
+ * as a whole failed.
+ */
+ void backupFinished(int status);
+}
diff --git a/core/java/android/app/backup/RestoreSet.java b/core/java/android/app/backup/RestoreSet.java
index aacaf7cda50b..4a6316c58715 100644
--- a/core/java/android/app/backup/RestoreSet.java
+++ b/core/java/android/app/backup/RestoreSet.java
@@ -58,7 +58,6 @@ public class RestoreSet implements Parcelable {
token = _token;
}
-
// Parcelable implementation
public int describeContents() {
return 0;