diff options
-rw-r--r-- | api/current.xml | 22 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 23 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 13 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 17 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 2 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 2 | ||||
-rw-r--r-- | core/java/android/content/pm/ApplicationInfo.java | 27 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 14 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | core/res/res/values/attrs_manifest.xml | 11 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 5 | ||||
-rw-r--r-- | packages/SettingsProvider/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 37 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 29 |
14 files changed, 192 insertions, 12 deletions
diff --git a/api/current.xml b/api/current.xml index 8fad213..ef7c3d2 100644 --- a/api/current.xml +++ b/api/current.xml @@ -4695,6 +4695,17 @@ visibility="public" > </field> +<field name="killAfterRestore" + type="int" + transient="false" + volatile="false" + value="16843416" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="label" type="int" transient="false" @@ -6477,6 +6488,17 @@ visibility="public" > </field> +<field name="restoreNeedsApplication" + type="int" + transient="false" + volatile="false" + value="16843417" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="right" type="int" transient="false" diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1bb21b9..52d6891 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1118,6 +1118,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM mi.writeToParcel(reply, 0); return true; } + + case KILL_APPLICATION_PROCESS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String processName = data.readString(); + int uid = data.readInt(); + killApplicationProcess(processName, uid); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2448,6 +2457,18 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + + public void killApplicationProcess(String processName, int uid) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(processName); + data.writeInt(uid); + mRemote.transact(KILL_APPLICATION_PROCESS_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b4e57e0..8a26aba 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1463,6 +1463,10 @@ public final class ActivityThread { queueOrSendMessage(H.EXIT_APPLICATION, null); } + public final void scheduleSuicide() { + queueOrSendMessage(H.SUICIDE, null); + } + public void requestThumbnail(IBinder token) { queueOrSendMessage(H.REQUEST_THUMBNAIL, token); } @@ -1752,7 +1756,8 @@ public final class ActivityThread { public static final int RELAUNCH_ACTIVITY = 126; public static final int PROFILER_CONTROL = 127; public static final int CREATE_BACKUP_AGENT = 128; - public static final int DESTROY_BACKUP_AGENT = 129; + public static final int DESTROY_BACKUP_AGENT = 129; + public static final int SUICIDE = 130; String codeToString(int code) { if (localLOGV) { switch (code) { @@ -1786,6 +1791,7 @@ public final class ActivityThread { case PROFILER_CONTROL: return "PROFILER_CONTROL"; case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT"; case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT"; + case SUICIDE: return "SUICIDE"; } } return "(unknown)"; @@ -1894,6 +1900,11 @@ public final class ActivityThread { case DESTROY_BACKUP_AGENT: handleDestroyBackupAgent((CreateBackupAgentData)msg.obj); break; + case SUICIDE: + { + Process.killProcess(Process.myPid()); + } + break; } } } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 15bf9ed..928981d 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -258,6 +258,13 @@ public abstract class ApplicationThreadNative extends Binder return true; } + case SCHEDULE_SUICIDE_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + scheduleSuicide(); + return true; + } + case REQUEST_THUMBNAIL_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); @@ -652,7 +659,15 @@ class ApplicationThreadProxy implements IApplicationThread { IBinder.FLAG_ONEWAY); data.recycle(); } - + + public final void scheduleSuicide() throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + mRemote.transact(SCHEDULE_SUICIDE_TRANSACTION, data, null, + IBinder.FLAG_ONEWAY); + data.recycle(); + } + public final void requestThumbnail(IBinder token) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 64daea9..98a8481 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -158,6 +158,7 @@ public interface IActivityManager extends IInterface { throws RemoteException; public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException; public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException; + public void killApplicationProcess(String processName, int uid) throws RemoteException; public boolean startInstrumentation(ComponentName className, String profileFile, int flags, Bundle arguments, IInstrumentationWatcher watcher) @@ -433,4 +434,5 @@ public interface IActivityManager extends IInterface { int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95; int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96; int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97; + int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index da9a957..8dda898 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -83,6 +83,7 @@ public interface IApplicationThread extends IInterface { IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, Map<String, IBinder> services) throws RemoteException; void scheduleExit() throws RemoteException; + void scheduleSuicide() throws RemoteException; void requestThumbnail(IBinder token) throws RemoteException; void scheduleConfigurationChanged(Configuration config) throws RemoteException; void updateTimeZone() throws RemoteException; @@ -133,4 +134,5 @@ public interface IApplicationThread extends IInterface { int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29; int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30; int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31; + int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 0a42a6f..8839f95 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -184,7 +184,29 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@hide} */ public static final int FLAG_ALLOW_BACKUP = 1<<14; - + + /** + * Value for {@link #flags}: this is false if the application has set + * its android:killAfterRestore to false, true otherwise. + * + * <p>If android:allowBackup is set to false or no android:backupAgent + * is specified, this flag will be ignored. + * + * {@hide} + */ + public static final int FLAG_KILL_AFTER_RESTORE = 1<<15; + + /** + * Value for {@link #flags}: this is true if the application has set + * its android:restoreNeedsApplication to true, false otherwise. + * + * <p>If android:allowBackup is set to false or no android:backupAgent + * is specified, this flag will be ignored. + * + * {@hide} + */ + public static final int FLAG_RESTORE_NEEDS_APPLICATION = 1<<16; + /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, @@ -193,7 +215,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP}, * {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS}, * {@link #FLAG_SUPPORTS_NORMAL_SCREENS}, - * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS}. + * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS}, + * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}. */ public int flags = 0; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4399df4..b4a6fee 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1296,12 +1296,26 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); if (allowBackup) { ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; + + // backupAgent, killAfterRestore, and restoreNeedsApplication are only relevant + // if backup is possible for the given application. String backupAgent = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestApplication_backupAgent); if (backupAgent != null) { ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); Log.v(TAG, "android:backupAgent = " + ai.backupAgentName + " from " + pkgName + "+" + backupAgent); + + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, + true)) { + ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; + } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_restoreNeedsApplication, + false)) { + ai.flags |= ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION; + } } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1ea5fa3..53e0125 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1113,6 +1113,7 @@ android:label="@string/android_system_label" android:allowClearUserData="false" android:backupAgent="com.android.server.SystemBackupAgent" + android:killAfterRestore="false" android:icon="@drawable/ic_launcher_android"> <activity android:name="com.android.internal.app.ChooserActivity" android:theme="@style/Theme.Dialog.Alert" diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index ce421db..7aaf218 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -580,6 +580,15 @@ <!-- This is not the attribute you are looking for. --> <attr name="allowBackup" format="boolean" /> + <!-- Whether the application in question should be terminated after its + settings have been restored. The default is to do so. --> + <attr name="killAfterRestore" format="boolean" /> + + <!-- Whether the application needs to have its own Application subclass + active during restore. The default is to run restore with a minimal + Application class to avoid interference with application logic. --> + <attr name="restoreNeedsApplication" format="boolean" /> + <!-- The <code>manifest</code> tag is the root of an <code>AndroidManifest.xml</code> file, describing the contents of an Android package (.apk) file. One @@ -656,6 +665,8 @@ <attr name="testOnly" /> <attr name="backupAgent" /> <attr name="allowBackup" /> + <attr name="killAfterRestore" /> + <attr name="restoreNeedsApplication" /> </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 0fba0f6..1a362f7 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1155,10 +1155,11 @@ <public type="attr" name="wallpaperActivityOpenExitAnimation" /> <public type="attr" name="wallpaperActivityCloseEnterAnimation" /> <public type="attr" name="wallpaperActivityCloseExitAnimation" /> + <public type="attr" name="supportsUploading" /> + <public type="attr" name="killAfterRestore" /> + <public type="attr" name="restoreNeedsApplication" /> <public type="style" name="Theme.Wallpaper" /> <public type="style" name="Theme.Wallpaper.NoTitleBar" /> <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" /> - - <public type="attr" name="supportsUploading" /> </resources> diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml index af0a1bd..1e1d729 100644 --- a/packages/SettingsProvider/AndroidManifest.xml +++ b/packages/SettingsProvider/AndroidManifest.xml @@ -8,6 +8,7 @@ android:label="@string/app_label" android:process="system" android:backupAgent="SettingsBackupAgent" + android:killAfterRestore="false" android:icon="@drawable/ic_launcher_settings"> <provider android:name="SettingsProvider" android:authorities="settings" 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, |