diff options
author | Christopher Tate <ctate@google.com> | 2009-05-14 11:12:14 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2009-05-31 13:10:03 -0700 |
commit | 181fafaf48208978b8ba2022683ffa78aaeddde1 (patch) | |
tree | 7c062847d418415e28813e70aac53c8c47e4ff69 /core/java | |
parent | c01159bb00f7273f9b051dfbbe6bc10d54d3a846 (diff) | |
download | frameworks_base-181fafaf48208978b8ba2022683ffa78aaeddde1.zip frameworks_base-181fafaf48208978b8ba2022683ffa78aaeddde1.tar.gz frameworks_base-181fafaf48208978b8ba2022683ffa78aaeddde1.tar.bz2 |
Retool the backup process to use a new 'BackupAgent' class
Backups will be handled by launching the application in a special
mode under which no activities or services will be started, only
the BackupAgent subclass named in the app's android:backupAgent
manifest property. This takes the place of the BackupService class
used earlier during development.
In the cases of *full* backup or restore, an application that does
not supply its own BackupAgent will be launched in a restricted
manner; in particular, it will be using the default Application
class rather than any manifest-declared one. This ensures that the
app is not running any code that may try to manipulate its data
while the backup system reads/writes its data set.
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 65 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 135 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 35 | ||||
-rw-r--r-- | core/java/android/app/BackupAgent.java (renamed from core/java/android/backup/BackupService.java) | 75 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 9 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 11 | ||||
-rw-r--r-- | core/java/android/app/IBackupAgent.aidl (renamed from core/java/android/backup/IBackupService.aidl) | 6 | ||||
-rw-r--r-- | core/java/android/backup/IBackupManager.aidl | 16 | ||||
-rw-r--r-- | core/java/android/content/pm/ApplicationInfo.java | 25 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 13 |
10 files changed, 331 insertions, 59 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 16f0a30..3d3d7d5 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.res.Configuration; @@ -1021,6 +1022,33 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeStrongBinder(binder); return true; } + + case START_BACKUP_AGENT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); + int backupRestoreMode = data.readInt(); + boolean success = bindBackupAgent(info, backupRestoreMode); + reply.writeNoException(); + reply.writeInt(success ? 1 : 0); + return true; + } + + case BACKUP_AGENT_CREATED_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String packageName = data.readString(); + IBinder agent = data.readStrongBinder(); + backupAgentCreated(packageName, agent); + reply.writeNoException(); + return true; + } + + case UNBIND_BACKUP_AGENT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); + unbindBackupAgent(info); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1681,6 +1709,43 @@ class ActivityManagerProxy implements IActivityManager return binder; } + public boolean bindBackupAgent(ApplicationInfo app, int backupRestoreMode) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + app.writeToParcel(data, 0); + data.writeInt(backupRestoreMode); + mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0); + reply.readException(); + boolean success = reply.readInt() != 0; + reply.recycle(); + data.recycle(); + return success; + } + + public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(packageName); + data.writeStrongBinder(agent); + mRemote.transact(BACKUP_AGENT_CREATED_TRANSACTION, data, reply, 0); + reply.recycle(); + data.recycle(); + } + + public void unbindBackupAgent(ApplicationInfo app) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + app.writeToParcel(data, 0); + mRemote.transact(UNBIND_BACKUP_AGENT_TRANSACTION, data, reply, 0); + reply.readException(); + reply.recycle(); + data.recycle(); + } + public boolean startInstrumentation(ComponentName className, String profileFile, int flags, Bundle arguments, IInstrumentationWatcher watcher) throws RemoteException { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 06e0a45..29e57cd 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -115,6 +115,7 @@ public final class ActivityThread { private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; private static final boolean DEBUG_BROADCAST = false; private static final boolean DEBUG_RESULTS = false; + private static final boolean DEBUG_BACKUP = true; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";"); private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003; @@ -499,7 +500,7 @@ public final class ActivityThread { return mResources; } - public Application makeApplication() { + public Application makeApplication(boolean forceDefaultAppClass) { if (mApplication != null) { return mApplication; } @@ -507,7 +508,7 @@ public final class ActivityThread { Application app = null; String appClass = mApplicationInfo.className; - if (appClass == null) { + if (forceDefaultAppClass || (appClass == null)) { appClass = "android.app.Application"; } @@ -1199,6 +1200,16 @@ public final class ActivityThread { } } + private static final class CreateBackupAgentData { + ApplicationInfo appInfo; + int backupMode; + public String toString() { + return "CreateBackupAgentData{appInfo=" + appInfo + + " backupAgent=" + appInfo.backupAgentName + + " mode=" + backupMode + "}"; + } + } + private static final class CreateServiceData { IBinder token; ServiceInfo info; @@ -1239,6 +1250,7 @@ public final class ActivityThread { Bundle instrumentationArgs; IInstrumentationWatcher instrumentationWatcher; int debugMode; + boolean restrictedBackupMode; Configuration config; boolean handlingProfiling; public String toString() { @@ -1374,6 +1386,21 @@ public final class ActivityThread { queueOrSendMessage(H.RECEIVER, r); } + public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) { + CreateBackupAgentData d = new CreateBackupAgentData(); + d.appInfo = app; + d.backupMode = backupMode; + + queueOrSendMessage(H.CREATE_BACKUP_AGENT, d); + } + + public final void scheduleDestroyBackupAgent(ApplicationInfo app) { + CreateBackupAgentData d = new CreateBackupAgentData(); + d.appInfo = app; + + queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d); + } + public final void scheduleCreateService(IBinder token, ServiceInfo info) { CreateServiceData s = new CreateServiceData(); @@ -1419,7 +1446,7 @@ public final class ActivityThread { ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, String profileFile, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, - int debugMode, Configuration config, + int debugMode, boolean isRestrictedBackupMode, Configuration config, Map<String, IBinder> services) { Process.setArgV0(processName); @@ -1437,6 +1464,7 @@ public final class ActivityThread { data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.debugMode = debugMode; + data.restrictedBackupMode = isRestrictedBackupMode; data.config = config; queueOrSendMessage(H.BIND_APPLICATION, data); } @@ -1718,6 +1746,8 @@ public final class ActivityThread { public static final int ACTIVITY_CONFIGURATION_CHANGED = 125; 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; String codeToString(int code) { if (localLOGV) { switch (code) { @@ -1749,6 +1779,8 @@ public final class ActivityThread { case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED"; case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY"; case PROFILER_CONTROL: return "PROFILER_CONTROL"; + case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT"; + case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT"; } } return "(unknown)"; @@ -1851,6 +1883,12 @@ public final class ActivityThread { case PROFILER_CONTROL: handleProfilerControl(msg.arg1 != 0, (String)msg.obj); break; + case CREATE_BACKUP_AGENT: + handleCreateBackupAgent((CreateBackupAgentData)msg.obj); + break; + case DESTROY_BACKUP_AGENT: + handleDestroyBackupAgent((CreateBackupAgentData)msg.obj); + break; } } } @@ -1908,6 +1946,8 @@ public final class ActivityThread { Application mInitialApplication; final ArrayList<Application> mAllApplications = new ArrayList<Application>(); + // set of instantiated backup agents, keyed by package name + final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>(); static final ThreadLocal sThreadLocal = new ThreadLocal(); Instrumentation mInstrumentation; String mInstrumentationAppDir = null; @@ -2269,7 +2309,7 @@ public final class ActivityThread { } try { - Application app = r.packageInfo.makeApplication(); + Application app = r.packageInfo.makeApplication(false); if (localLOGV) Log.v(TAG, "Performing launch of " + r); if (localLOGV) Log.v( @@ -2464,7 +2504,7 @@ public final class ActivityThread { } try { - Application app = packageInfo.makeApplication(); + Application app = packageInfo.makeApplication(false); if (localLOGV) Log.v( TAG, "Performing receive of " + data.intent @@ -2507,6 +2547,85 @@ public final class ActivityThread { } } + // Instantiate a BackupAgent and tell it that it's alive + private final void handleCreateBackupAgent(CreateBackupAgentData data) { + if (DEBUG_BACKUP) Log.v(TAG, "handleCreateBackupAgent: " + data); + + // no longer idle; we have backup work to do + unscheduleGcIdler(); + + // instantiate the BackupAgent class named in the manifest + PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo); + String packageName = packageInfo.mPackageName; + if (mBackupAgents.get(packageName) != null) { + Log.d(TAG, "BackupAgent " + " for " + packageName + + " already exists"); + return; + } + + BackupAgent agent = null; + String classname = data.appInfo.backupAgentName; + if (classname == null) { + if (data.backupMode == IApplicationThread.BACKUP_MODE_INCREMENTAL) { + Log.e(TAG, "Attempted incremental backup but no defined agent for " + + packageName); + return; + } + classname = "android.app.FullBackupAgent"; + } + try { + java.lang.ClassLoader cl = packageInfo.getClassLoader(); + agent = (BackupAgent) cl.loadClass(data.appInfo.backupAgentName).newInstance(); + } catch (Exception e) { + throw new RuntimeException("Unable to instantiate backup agent " + + data.appInfo.backupAgentName + ": " + e.toString(), e); + } + + // set up the agent's context + try { + if (DEBUG_BACKUP) Log.v(TAG, "Initializing BackupAgent " + + data.appInfo.backupAgentName); + + ApplicationContext context = new ApplicationContext(); + context.init(packageInfo, null, this); + context.setOuterContext(agent); + agent.attach(context); + agent.onCreate(); + + // tell the OS that we're live now + IBinder binder = agent.onBind(); + try { + ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder); + } catch (RemoteException e) { + // nothing to do. + } + mBackupAgents.put(packageName, agent); + } catch (Exception e) { + throw new RuntimeException("Unable to create BackupAgent " + + data.appInfo.backupAgentName + ": " + e.toString(), e); + } + } + + // Tear down a BackupAgent + private final void handleDestroyBackupAgent(CreateBackupAgentData data) { + if (DEBUG_BACKUP) Log.v(TAG, "handleDestroyBackupAgent: " + data); + + PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo); + String packageName = packageInfo.mPackageName; + BackupAgent agent = mBackupAgents.get(packageName); + if (agent != null) { + try { + agent.onDestroy(); + } catch (Exception e) { + Log.w(TAG, "Exception thrown in onDestroy by backup agent of " + data.appInfo); + e.printStackTrace(); + } + mBackupAgents.remove(packageName); + } else { + Log.w(TAG, "Attempt to destroy unknown backup agent " + data); + } + } + private final void handleCreateService(CreateServiceData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. @@ -2532,7 +2651,7 @@ public final class ActivityThread { ApplicationContext context = new ApplicationContext(); context.init(packageInfo, null, this); - Application app = packageInfo.makeApplication(); + Application app = packageInfo.makeApplication(false); context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); @@ -3694,7 +3813,9 @@ public final class ActivityThread { mInstrumentation = new Instrumentation(); } - Application app = data.info.makeApplication(); + // If the app is being launched for full backup or restore, bring it up in + // a restricted environment with the base application class. + Application app = data.info.makeApplication(data.restrictedBackupMode); mInitialApplication = app; List<ProviderInfo> providers = data.providers; diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index f243185..e28fd0f 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -230,11 +230,13 @@ public abstract class ApplicationThreadNative extends Binder IBinder binder = data.readStrongBinder(); IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder); int testMode = data.readInt(); + boolean restrictedBackupMode = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); HashMap<String, IBinder> services = data.readHashMap(null); bindApplication(packageName, info, providers, testName, profileName, - testArgs, testWatcher, testMode, config, services); + testArgs, testWatcher, testMode, restrictedBackupMode, + config, services); return true; } @@ -339,6 +341,15 @@ public abstract class ApplicationThreadNative extends Binder setSchedulingGroup(group); return true; } + + case SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data); + int backupMode = data.readInt(); + scheduleCreateBackupAgent(appInfo, backupMode); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -492,6 +503,24 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } + public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) + throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + app.writeToParcel(data, 0); + data.writeInt(backupMode); + mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null, 0); + data.recycle(); + } + + public final void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + app.writeToParcel(data, 0); + mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null, 0); + data.recycle(); + } + public final void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException { Parcel data = Parcel.obtain(); @@ -551,7 +580,8 @@ class ApplicationThreadProxy implements IApplicationThread { public final void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, - Configuration config, Map<String, IBinder> services) throws RemoteException { + boolean restrictedBackupMode, Configuration config, + Map<String, IBinder> services) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeString(packageName); @@ -567,6 +597,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeBundle(testArgs); data.writeStrongInterface(testWatcher); data.writeInt(debugMode); + data.writeInt(restrictedBackupMode ? 1 : 0); config.writeToParcel(data, 0); data.writeMap(services); mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, diff --git a/core/java/android/backup/BackupService.java b/core/java/android/app/BackupAgent.java index 50a5921..997bfdc 100644 --- a/core/java/android/backup/BackupService.java +++ b/core/java/android/app/BackupAgent.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package android.backup; +package android.app; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.app.Service; -import android.backup.IBackupService; -import android.content.Intent; +import android.app.IBackupAgent; +import android.backup.BackupDataOutput; +import android.content.Context; +import android.content.ContextWrapper; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -30,31 +29,18 @@ import android.util.Log; * This is the central interface between an application and Android's * settings backup mechanism. * - * In order to use the backup service, your application must implement a - * subclass of BackupService, and declare an intent filter - * in the application manifest specifying that your BackupService subclass - * handles the {@link BackupService#SERVICE_ACTION} intent action. For example: - * - * <pre class="prettyprint"> - * <!-- Use the class "MyBackupService" to perform backups for my app --> - * <service android:name=".MyBackupService"> - * <intent-filter> - * <action android:name="android.backup.BackupService.SERVICE" /> - * </intent-filter> - * </service></pre> - * * @hide pending API solidification */ +public abstract class BackupAgent extends ContextWrapper { + public BackupAgent() { + super(null); + } -public abstract class BackupService extends Service { - /** - * Service Action: Participate in the backup infrastructure. Applications - * that wish to use the Android backup mechanism must provide an exported - * subclass of BackupService and give it an {@link android.content.IntentFilter - * IntentFilter} that accepts this action. - */ - @SdkConstant(SdkConstantType.SERVICE_ACTION) - public static final String SERVICE_ACTION = "android.backup.BackupService.SERVICE"; + public void onCreate() { + } + + public void onDestroy() { + } /** * The application is being asked to write any data changed since the @@ -91,7 +77,8 @@ public abstract class BackupService extends Service { * file. The application should record the final backup state * here after restoring its data from dataFd. */ - public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data, ParcelFileDescriptor newState); + public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data, + ParcelFileDescriptor newState); // ----- Core implementation ----- @@ -100,29 +87,33 @@ public abstract class BackupService extends Service { * Returns the private interface called by the backup system. Applications will * not typically override this. */ - public IBinder onBind(Intent intent) { - if (intent.getAction().equals(SERVICE_ACTION)) { - return mBinder; - } - return null; + public IBinder onBind() { + return mBinder; } private final IBinder mBinder = new BackupServiceBinder().asBinder(); + /** @hide */ + public void attach(Context context) { + attachBaseContext(context); + } + // ----- IBackupService binder interface ----- - private class BackupServiceBinder extends IBackupService.Stub { + private class BackupServiceBinder extends IBackupAgent.Stub { + private static final String TAG = "BackupServiceBinder"; + public void doBackup(ParcelFileDescriptor oldState, ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly - Log.v("BackupServiceBinder", "doBackup() invoked"); - BackupDataOutput output = new BackupDataOutput(BackupService.this, + Log.v(TAG, "doBackup() invoked"); + BackupDataOutput output = new BackupDataOutput(BackupAgent.this, data.getFileDescriptor()); try { - BackupService.this.onBackup(oldState, output, newState); + BackupAgent.this.onBackup(oldState, output, newState); } catch (RuntimeException ex) { - Log.d("BackupService", "onBackup (" - + BackupService.this.getClass().getName() + ") threw", ex); + Log.d("BackupAgent", "onBackup (" + + BackupAgent.this.getClass().getName() + ") threw", ex); throw ex; } } @@ -130,8 +121,8 @@ public abstract class BackupService extends Service { public void doRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) throws RemoteException { // !!! TODO - real implementation; for now just invoke the callbacks directly - Log.v("BackupServiceBinder", "doRestore() invoked"); - BackupService.this.onRestore(data, newState); + Log.v(TAG, "doRestore() invoked"); + BackupAgent.this.onRestore(data, newState); } } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index d15a154..c948aec 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -21,6 +21,7 @@ import android.content.ContentProviderNative; import android.content.IContentProvider; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.ProviderInfo; @@ -149,6 +150,11 @@ public interface IActivityManager extends IInterface { public void serviceDoneExecuting(IBinder token) throws RemoteException; public IBinder peekService(Intent service, String resolvedType) throws RemoteException; + public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode) + throws RemoteException; + public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException; + public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException; + public boolean startInstrumentation(ComponentName className, String profileFile, int flags, Bundle arguments, IInstrumentationWatcher watcher) throws RemoteException; @@ -397,4 +403,7 @@ public interface IActivityManager extends IInterface { int SHUTDOWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+86; int STOP_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+87; int RESUME_APP_SWITCHES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+88; + int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89; + int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90; + int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index ec03d3a..bca1fea 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -59,6 +59,11 @@ public interface IApplicationThread extends IInterface { int configChanges) throws RemoteException; void scheduleReceiver(Intent intent, ActivityInfo info, int resultCode, String data, Bundle extras, boolean sync) throws RemoteException; + static final int BACKUP_MODE_INCREMENTAL = 0; + static final int BACKUP_MODE_FULL = 1; + static final int BACKUP_MODE_RESTORE = 2; + void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) throws RemoteException; + void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException; void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException; void scheduleBindService(IBinder token, Intent intent, boolean rebind) throws RemoteException; @@ -71,8 +76,8 @@ public interface IApplicationThread extends IInterface { static final int DEBUG_WAIT = 2; void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArguments, - IInstrumentationWatcher testWatcher, int debugMode, Configuration config, Map<String, - IBinder> services) throws RemoteException; + IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, + Configuration config, Map<String, IBinder> services) throws RemoteException; void scheduleExit() throws RemoteException; void requestThumbnail(IBinder token) throws RemoteException; void scheduleConfigurationChanged(Configuration config) throws RemoteException; @@ -119,4 +124,6 @@ public interface IApplicationThread extends IInterface { int REQUEST_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26; int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27; int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28; + int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29; + int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30; } diff --git a/core/java/android/backup/IBackupService.aidl b/core/java/android/app/IBackupAgent.aidl index 1bde8ea..bb9f008 100644 --- a/core/java/android/backup/IBackupService.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -14,18 +14,18 @@ * limitations under the License. */ -package android.backup; +package android.app; import android.os.ParcelFileDescriptor; /** * Interface presented by applications being asked to participate in the * backup & restore mechanism. End user code does not typically implement - * this interface; they subclass BackupService instead. + * this interface; they subclass BackupAgent instead. * * {@hide} */ -interface IBackupService { +interface IBackupAgent { /** * Request that the app perform an incremental backup. * diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl index cf22798..3468d70 100644 --- a/core/java/android/backup/IBackupManager.aidl +++ b/core/java/android/backup/IBackupManager.aidl @@ -34,8 +34,22 @@ interface IBackupManager { oneway void dataChanged(String packageName); /** + * Notifies the Backup Manager Service that an agent has become available. This + * method is only invoked by the Activity Manager. + * !!! TODO: permission + */ + oneway void agentConnected(String packageName, IBinder agent); + + /** + * Notify the Backup Manager Service that an agent has unexpectedly gone away. + * This method is only invoked by the Activity Manager. + * !!! TODO: permission + */ + oneway void agentDisconnected(String packageName); + + /** * Schedule a full backup of the given package. - * !!! TODO: protect with a signature-or-system permission? + * !!! TODO: permission */ oneway void scheduleFullBackup(String packageName); } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index ad022e7..f16eb74 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -58,11 +58,22 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * Class implementing the Application's manage space * functionality. From the "manageSpaceActivity" * attribute. This is an optional attribute and will be null if - * application's dont specify it in their manifest + * applications don't specify it in their manifest */ public String manageSpaceActivityName; /** + * Class implementing the Application's backup functionality. From + * the "backupAgent" attribute. This is an optional attribute and + * will be null if the application does not specify it in its manifest. + * + * <p>If android:allowBackup is set to false, this attribute is ignored. + * + * {@hide} + */ + public String backupAgentName; + + /** * Value for {@link #flags}: if set, this application is installed in the * device's system image. */ @@ -93,7 +104,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_PERSISTENT = 1<<3; /** - * Value for {@link #flags}: set to true iif this application holds the + * Value for {@link #flags}: set to true if this application holds the * {@link android.Manifest.permission#FACTORY_TEST} permission and the * device is running in factory test mode. */ @@ -126,6 +137,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_TEST_ONLY = 1<<8; /** + * Value for {@link #flags}: this is false if the application has set + * its android:allowBackup to false, true otherwise. + * + * {@hide} + */ + public static final int FLAG_ALLOW_BACKUP = 1<<10; + + /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and @@ -285,6 +304,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(targetSdkVersion); dest.writeInt(enabled ? 1 : 0); dest.writeString(manageSpaceActivityName); + dest.writeString(backupAgentName); dest.writeInt(descriptionRes); dest.writeIntArray(supportsDensities); } @@ -315,6 +335,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { targetSdkVersion = source.readInt(); enabled = source.readInt() != 0; manageSpaceActivityName = source.readString(); + backupAgentName = source.readString(); descriptionRes = source.readInt(); supportsDensities = source.createIntArray(); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ee20aee..36d154e 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1176,6 +1176,19 @@ public class PackageParser { outError); } + boolean allowBackup = sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); + if (allowBackup) { + ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; + 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); + } + } + TypedValue v = sa.peekValue( com.android.internal.R.styleable.AndroidManifestApplication_label); if (v != null && (ai.labelRes=v.resourceId) == 0) { |