am 9073dc69: am 9756a70b: Merge change 23582 into eclair

Merge commit '9073dc69b110cbd0d4bebd128ed6cc2b24a16695'

* commit '9073dc69b110cbd0d4bebd128ed6cc2b24a16695':
  Expand apps' control over the settings restore process
This commit is contained in:
Christopher Tate
2009-09-01 21:05:10 -07:00
committed by Android Git Automerger
14 changed files with 192 additions and 12 deletions

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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;
}
}
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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>

View File

@@ -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"

View File

@@ -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);
}
}
}

View File

@@ -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,