diff options
author | Christopher Tate <ctate@google.com> | 2014-07-15 12:37:38 -0700 |
---|---|---|
committer | Christopher Tate <ctate@android.com> | 2014-07-17 17:43:24 +0000 |
commit | 2e40d115ca4332d88424d1b591fdd8d5f78d1831 (patch) | |
tree | 43ff38544c1b7301ce72dde50cff3bd5dcd84964 /core/java/android | |
parent | 738177caf6a755a59ca6b17bb968be0aa4e8e10f (diff) | |
download | frameworks_base-2e40d115ca4332d88424d1b591fdd8d5f78d1831.zip frameworks_base-2e40d115ca4332d88424d1b591fdd8d5f78d1831.tar.gz frameworks_base-2e40d115ca4332d88424d1b591fdd8d5f78d1831.tar.bz2 |
Add BackupAgent.onRestoreFinished() callback
The agent's onRestoreFinished() method is called after all available
data has been delivered to the app, whether via the key/value restore
API or the full-data file-at-a-time API. This gives the app a stable
opportunity to do any postprocessing that might be appropriate.
Also fixes a lingering bug in the framework's handling of backup
agent lifetimes. In cases where an existing agent instances was
being rebound, the framework was forgetting to notify the dependent
that the agent was available. This was causing timeouts and restore
failure.
Bug 16241004
Change-Id: I3f52b299312d30d38b0cba63a2cfaeb934991ef2
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 55 | ||||
-rw-r--r-- | core/java/android/app/IBackupAgent.aidl | 15 | ||||
-rw-r--r-- | core/java/android/app/backup/BackupAgent.java | 37 |
3 files changed, 77 insertions, 30 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 15f3a75..48954f4 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2610,15 +2610,7 @@ public final class ActivityThread { return; } - if (mBackupAgents.get(packageName) != null) { - Slog.d(TAG, "BackupAgent " + " for " + packageName - + " already exists"); - return; - } - - BackupAgent agent = null; String classname = data.appInfo.backupAgentName; - // full backup operation but no app-supplied agent? use the default implementation if (classname == null && (data.backupMode == IApplicationThread.BACKUP_MODE_FULL || data.backupMode == IApplicationThread.BACKUP_MODE_RESTORE_FULL)) { @@ -2627,29 +2619,38 @@ public final class ActivityThread { try { IBinder binder = null; - try { - if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname); + BackupAgent agent = mBackupAgents.get(packageName); + if (agent != null) { + // reusing the existing instance + if (DEBUG_BACKUP) { + Slog.v(TAG, "Reusing existing agent instance"); + } + binder = agent.onBind(); + } else { + try { + if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname); - java.lang.ClassLoader cl = packageInfo.getClassLoader(); - agent = (BackupAgent) cl.loadClass(classname).newInstance(); + java.lang.ClassLoader cl = packageInfo.getClassLoader(); + agent = (BackupAgent) cl.loadClass(classname).newInstance(); - // set up the agent's context - ContextImpl context = ContextImpl.createAppContext(this, packageInfo); - context.setOuterContext(agent); - agent.attach(context); + // set up the agent's context + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); + context.setOuterContext(agent); + agent.attach(context); - agent.onCreate(); - binder = agent.onBind(); - mBackupAgents.put(packageName, agent); - } catch (Exception e) { - // If this is during restore, fail silently; otherwise go - // ahead and let the user see the crash. - Slog.e(TAG, "Agent threw during creation: " + e); - if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE - && data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE_FULL) { - throw e; + agent.onCreate(); + binder = agent.onBind(); + mBackupAgents.put(packageName, agent); + } catch (Exception e) { + // If this is during restore, fail silently; otherwise go + // ahead and let the user see the crash. + Slog.e(TAG, "Agent threw during creation: " + e); + if (data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE + && data.backupMode != IApplicationThread.BACKUP_MODE_RESTORE_FULL) { + throw e; + } + // falling through with 'binder' still null } - // falling through with 'binder' still null } // tell the OS that we're live now diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl index 7036aea..451af99 100644 --- a/core/java/android/app/IBackupAgent.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -125,6 +125,21 @@ oneway interface IBackupAgent { int token, IBackupManager callbackBinder); /** + * Provide the app with a canonical "all data has been delivered" end-of-restore + * callback so that it can do any postprocessing of the restored data that might + * be appropriate. This is issued after both key/value and full data restore + * operations have completed. + * + * @param token Opaque token identifying this transaction. This must + * be echoed back to the backup service binder once the agent is + * finished restoring the application based on the restore data + * contents. + * @param callbackBinder Binder on which to indicate operation completion, + * passed here as a convenience to the agent. + */ + void doRestoreFinished(int token, IBackupManager callbackBinder); + + /** * Out of band: instruct the agent to crash within the client process. This is used * when the backup infrastructure detects a semantic error post-hoc and needs to * pass the problem back to the app. diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index e2a86e8..87d785a 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -209,7 +209,7 @@ public abstract class BackupAgent extends ContextWrapper { * output stream. */ public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, - ParcelFileDescriptor newState) throws IOException; + ParcelFileDescriptor newState) throws IOException; /** * The application is being restored from backup and should replace any @@ -243,8 +243,7 @@ public abstract class BackupAgent extends ContextWrapper { * When a full-backup dataset is being restored, this will be <code>null</code>. */ public abstract void onRestore(BackupDataInput data, int appVersionCode, - ParcelFileDescriptor newState) - throws IOException; + ParcelFileDescriptor newState) throws IOException; /** * The application is having its entire file system contents backed up. {@code data} @@ -575,6 +574,20 @@ public abstract class BackupAgent extends ContextWrapper { FullBackup.restoreFile(data, size, type, mode, mtime, null); } + /** + * The application's restore operation has completed. This method is called after + * all available data has been delivered to the application for restore (via either + * the {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} or + * {@link #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long) onRestoreFile()} + * callbacks). This provides the app with a stable end-of-restore opportunity to + * perform any appropriate post-processing on the data that was just delivered. + * + * @see #onRestore(BackupDataInput, int, ParcelFileDescriptor) + * @see #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long) + */ + public void onRestoreFinished() { + } + // ----- Core implementation ----- /** @hide */ @@ -723,6 +736,24 @@ public abstract class BackupAgent extends ContextWrapper { } @Override + public void doRestoreFinished(int token, IBackupManager callbackBinder) { + long ident = Binder.clearCallingIdentity(); + try { + BackupAgent.this.onRestoreFinished(); + } finally { + // Ensure that any side-effect SharedPreferences writes have landed + waitForSharedPrefs(); + + Binder.restoreCallingIdentity(ident); + try { + callbackBinder.opComplete(token); + } catch (RemoteException e) { + // we'll time out anyway, so we're safe + } + } + } + + @Override public void fail(String message) { getHandler().post(new FailRunnable(message)); } |