summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorChristopher Tate <ctate@android.com>2009-09-01 20:32:49 -0700
committerChristopher Tate <ctate@android.com>2009-09-01 20:59:36 -0700
commit5e1ab335e6e8fbfa19c64d53880a22f472010953 (patch)
tree4da429b3833ff29256d23f9e2e7f1b3a41715b65 /services
parentc937b5ce4ff2f39fd9c60f718f98550a932b62f0 (diff)
downloadframeworks_base-5e1ab335e6e8fbfa19c64d53880a22f472010953.zip
frameworks_base-5e1ab335e6e8fbfa19c64d53880a22f472010953.tar.gz
frameworks_base-5e1ab335e6e8fbfa19c64d53880a22f472010953.tar.bz2
Expand apps' control over the settings restore process
Applications can now specify two more aspects of the restore process: whether they need to run with their own custom Application subclass rather than being launched in the usual restricted mode during restore, and whether it's okay for the backup manager to kill the app process once restore has completed. The new manifest attributes for these are, respectively, android:restoreNeedsApplication and android:killAfterRestore. If unspecified in the manifest, restoreNeedsApplication is false, and killAfterRestore is true. In order to support kill-after-restore cleanly, this change also adds a new system-process-only interface to the Activity Manager, which will schedule a "commit suicide" event on the target app's main thread looper. The framework backup agents have been given the appropriate new backup attributes as well.
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/BackupManagerService.java37
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java29
2 files changed, 61 insertions, 5 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4eed7fe..0e60dd6 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -557,7 +557,12 @@ class BackupManagerService extends IBackupManager.Stub {
Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
for (PackageInfo p : targetPkgs) {
Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
- + " uid=" + p.applicationInfo.uid);
+ + " uid=" + p.applicationInfo.uid
+ + " killAfterRestore="
+ + (((p.applicationInfo.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) ? "true" : "false")
+ + " restoreNeedsApplication="
+ + (((p.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION) != 0) ? "true" : "false")
+ );
}
}
@@ -1244,11 +1249,21 @@ class BackupManagerService extends IBackupManager.Stub {
+ "] is compatible with installed version ["
+ packageInfo.versionCode + "]");
- // Now perform the actual restore
+ // Now perform the actual restore: first clear the app's data
+ // if appropriate
clearApplicationDataSynchronous(packageName);
+
+ // Then set up and bind the agent (with a restricted Application object
+ // unless the application says otherwise)
+ boolean useRealApp = (packageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION) != 0;
+ if (DEBUG && useRealApp) {
+ Log.v(TAG, "agent requires real Application subclass for restore");
+ }
IBackupAgent agent = bindToAgentSynchronous(
packageInfo.applicationInfo,
- IApplicationThread.BACKUP_MODE_RESTORE);
+ (useRealApp ? IApplicationThread.BACKUP_MODE_INCREMENTAL
+ : IApplicationThread.BACKUP_MODE_RESTORE));
if (agent == null) {
Log.w(TAG, "Can't find backup agent for " + packageName);
EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
@@ -1256,12 +1271,26 @@ class BackupManagerService extends IBackupManager.Stub {
continue;
}
+ // And then finally run the restore on this agent
try {
processOneRestore(packageInfo, metaInfo.versionCode, agent);
++count;
} finally {
- // unbind even on timeout or failure, just in case
+ // unbind and tidy up even on timeout or failure, just in case
mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
+
+ // The agent was probably running with a stub Application object,
+ // which isn't a valid run mode for the main app logic. Shut
+ // down the app so that next time it's launched, it gets the
+ // usual full initialization.
+ if ((packageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
+ if (DEBUG) Log.d(TAG, "Restore complete, killing host process of "
+ + packageInfo.applicationInfo.processName);
+ mActivityManager.killApplicationProcess(
+ packageInfo.applicationInfo.processName,
+ packageInfo.applicationInfo.uid);
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c9452d3..38add94 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4914,7 +4914,34 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
thread.getMemoryInfo(mi);
}
-
+
+ public void killApplicationProcess(String processName, int uid) {
+ if (processName == null) {
+ return;
+ }
+
+ int callerUid = Binder.getCallingUid();
+ // Only the system server can kill an application
+ if (callerUid == Process.SYSTEM_UID) {
+ synchronized (this) {
+ ProcessRecord app = getProcessRecordLocked(processName, uid);
+ if (app != null) {
+ try {
+ app.thread.scheduleSuicide();
+ } catch (RemoteException e) {
+ // If the other end already died, then our work here is done.
+ }
+ } else {
+ Log.w(TAG, "Process/uid not found attempting kill of "
+ + processName + " / " + uid);
+ }
+ }
+ } else {
+ throw new SecurityException(callerUid + " cannot kill app process: " +
+ processName);
+ }
+ }
+
private void restartPackageLocked(final String packageName, int uid) {
uninstallPackageLocked(packageName, uid, false);
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,