Loading core/java/android/app/ActivityThread.java +42 −20 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ public final class ActivityThread { } WeakReference<Resources> wr = mActiveResources.get(key); r = wr != null ? wr.get() : null; //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); if (r != null && r.getAssets().isUpToDate()) { if (false) { Slog.w(TAG, "Returning cached resources " + r + " " + resDir Loading Loading @@ -1752,6 +1753,10 @@ public final class ActivityThread { Debug.getMemoryInfo(outInfo); } public void dispatchPackageBroadcast(int cmd, String[] packages) { queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { long nativeMax = Debug.getNativeHeapSize() / 1024; Loading Loading @@ -1976,6 +1981,7 @@ public final class ActivityThread { public static final int SUICIDE = 130; public static final int REMOVE_PROVIDER = 131; public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; String codeToString(int code) { if (localLOGV) { switch (code) { Loading Loading @@ -2012,6 +2018,7 @@ public final class ActivityThread { case SUICIDE: return "SUICIDE"; case REMOVE_PROVIDER: return "REMOVE_PROVIDER"; case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; } } return "(unknown)"; Loading Loading @@ -2132,6 +2139,9 @@ public final class ActivityThread { case ENABLE_JIT: ensureJitEnabled(); break; case DISPATCH_PACKAGE_BROADCAST: handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj); break; } } Loading Loading @@ -2244,7 +2254,7 @@ public final class ActivityThread { = new HashMap<String, WeakReference<PackageInfo>>(); Display mDisplay = null; DisplayMetrics mDisplayMetrics = null; HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new HashMap<ResourcesKey, WeakReference<Resources> >(); final ArrayList<ActivityRecord> mRelaunchingActivities = new ArrayList<ActivityRecord>(); Loading @@ -2271,6 +2281,8 @@ public final class ActivityThread { } PackageInfo packageInfo = ref != null ? ref.get() : null; //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo); //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir // + ": " + packageInfo.mResources.getAssets().isUpToDate()); if (packageInfo != null && (packageInfo.mResources == null || packageInfo.mResources.getAssets().isUpToDate())) { if (packageInfo.isSecurityViolation() Loading Loading @@ -2358,21 +2370,6 @@ public final class ActivityThread { } } public final boolean hasPackageInfo(String packageName) { synchronized (mPackages) { WeakReference<PackageInfo> ref; ref = mPackages.get(packageName); if (ref != null && ref.get() != null) { return true; } ref = mResourcePackages.get(packageName); if (ref != null && ref.get() != null) { return true; } return false; } } ActivityThread() { } Loading Loading @@ -4054,6 +4051,31 @@ public final class ActivityThread { } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { boolean hasPkgInfo = false; if (packages != null) { for (int i=packages.length-1; i>=0; i--) { //Slog.i(TAG, "Cleaning old package: " + packages[i]); if (!hasPkgInfo) { WeakReference<PackageInfo> ref; ref = mPackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; } else { ref = mResourcePackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; } } } mPackages.remove(packages[i]); mResourcePackages.remove(packages[i]); } } ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo); } final void handleLowMemory() { ArrayList<ComponentCallbacks> callbacks = new ArrayList<ComponentCallbacks>(); Loading core/java/android/app/ApplicationThreadNative.java +20 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,15 @@ public abstract class ApplicationThreadNative extends Binder mi.writeToParcel(reply, 0); return true; } case DISPATCH_PACKAGE_BROADCAST_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); int cmd = data.readInt(); String[] packages = data.readStringArray(); dispatchPackageBroadcast(cmd, packages); return true; } } return super.onTransact(code, data, reply, flags); Loading Loading @@ -806,5 +815,16 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); reply.recycle(); } public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeInt(cmd); data.writeStringArray(packages); mRemote.transact(DISPATCH_PACKAGE_BROADCAST_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } } core/java/android/app/ContextImpl.java +22 −65 Original line number Diff line number Diff line Loading @@ -2244,33 +2244,7 @@ class ContextImpl extends Context { return null; } private void establishPackageRemovedReceiver() { // mContext.registerReceiverInternal() winds up acquiring the // main ActivityManagerService.this lock. If we hold our usual // sSync global lock at the same time, we impose a required ordering // on those two locks, which is not good for deadlock prevention. // Use a dedicated lock around initialization of // sPackageRemovedReceiver to avoid this. synchronized (sPackageRemovedSync) { if (sPackageRemovedReceiver == null) { sPackageRemovedReceiver = new PackageRemovedReceiver(); IntentFilter filter = new IntentFilter( Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiverInternal(sPackageRemovedReceiver, filter, null, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiverInternal(sPackageRemovedReceiver, sdFilter, null, null, null); } } } private void putCachedIcon(ResourceName name, Drawable dr) { establishPackageRemovedReceiver(); synchronized (sSync) { sIconCache.put(name, new WeakReference<Drawable>(dr)); if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for " Loading @@ -2278,29 +2252,17 @@ class ContextImpl extends Context { } } private static final class PackageRemovedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String pkgList[] = null; String action = intent.getAction(); static final void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) { boolean immediateGc = false; if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) { immediateGc = true; } else { Uri data = intent.getData(); if (data != null) { String ssp = data.getSchemeSpecificPart(); if (ssp != null) { pkgList = new String[] { ssp }; } } } if (pkgList != null && (pkgList.length > 0)) { boolean needCleanup = false; boolean hasPkgInfo = false; for (String ssp : pkgList) { synchronized (sSync) { if (sIconCache.size() > 0) { Iterator<ResourceName> it = sIconCache.keySet().iterator(); while (it.hasNext()) { ResourceName nm = it.next(); Loading @@ -2310,7 +2272,9 @@ class ContextImpl extends Context { needCleanup = true; } } it = sStringCache.keySet().iterator(); } if (sStringCache.size() > 0) { Iterator<ResourceName> it = sStringCache.keySet().iterator(); while (it.hasNext()) { ResourceName nm = it.next(); if (nm.packageName.equals(ssp)) { Loading @@ -2320,8 +2284,6 @@ class ContextImpl extends Context { } } } if (!hasPkgInfo) { hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp); } } if (needCleanup || hasPkgInfo) { Loading @@ -2334,7 +2296,6 @@ class ContextImpl extends Context { } } } } private static final class ResourceName { final String packageName; Loading Loading @@ -2400,8 +2361,6 @@ class ContextImpl extends Context { } private void putCachedString(ResourceName name, CharSequence cs) { establishPackageRemovedReceiver(); synchronized (sSync) { sStringCache.put(name, new WeakReference<CharSequence>(cs)); } Loading Loading @@ -2665,8 +2624,6 @@ class ContextImpl extends Context { private final IPackageManager mPM; private static final Object sSync = new Object(); private static final Object sPackageRemovedSync = new Object(); private static BroadcastReceiver sPackageRemovedReceiver; private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache = new HashMap<ResourceName, WeakReference<Drawable> >(); private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache Loading core/java/android/app/IApplicationThread.java +4 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,9 @@ public interface IApplicationThread extends IInterface { throws RemoteException; void setSchedulingGroup(int group) throws RemoteException; void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException; static final int PACKAGE_REMOVED = 0; static final int EXTERNAL_STORAGE_UNAVAILABLE = 1; void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException; String descriptor = "android.app.IApplicationThread"; Loading Loading @@ -135,4 +138,5 @@ public interface IApplicationThread extends IInterface { 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; int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33; } core/java/android/app/backup/BackupAgent.java +20 −18 Original line number Diff line number Diff line Loading @@ -29,42 +29,44 @@ import android.util.Log; import java.io.IOException; /** * {@link android.app.backup.BackupAgent} is the central interface between an * Provides the central interface between an * application and Android's data backup infrastructure. An application that wishes * to participate in the backup and restore mechanism will declare a subclass of * {@link android.app.backup.BackupAgent}, implement the * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} methods, * and provide the name of its agent class in the AndroidManifest.xml file via * the <application> tag's android:backupAgent attribute. * <p> * <b>Basic Operation</b> * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods, * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via * the <code><a * href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> * tag's {@code android:backupAgent} attribute. * <h3>Basic Operation</h3> * <p> * When the application makes changes to data that it wishes to keep backed up, * it should call the * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method. * This notifies the Android backup manager that the application needs an opportunity * to update its backup image. The backup manager, in turn, will then schedule a * This notifies the Android Backup Manager that the application needs an opportunity * to update its backup image. The Backup Manager, in turn, schedules a * backup pass to be performed at an opportune time. * <p> * Restore operations are typically only performed when applications are first * Restore operations are typically performed only when applications are first * installed on a device. At that time, the operating system checks to see whether * there is a previously-saved data set available for the application, and if so, * begins an immediate restore pass to deliver that data as part of the installation * there is a previously-saved data set available for the application being installed, and if so, * begins an immediate restore pass to deliver the backup data as part of the installation * process. * <p> * When a backup or restore pass is run, the application's process will be launched * (if not already running), the manifest-declared agent class instantiated within * that process, and the agent's {@link #onCreate()} method invoked. This prepares the * When a backup or restore pass is run, the application's process is launched * (if not already running), the manifest-declared backup agent class (in the {@code * android:backupAgent} attribute) is instantiated within * that process, and the agent's {@link #onCreate()} method is invoked. This prepares the * agent instance to run the actual backup or restore logic. At this point the * agent's * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be * invoked as appropriate for the operation being performed. * <p> * A backup data set consists of one or more "entities," flattened binary data records * that are each identified with a key string unique within the data set. Adding a * record to the active data set, or updating an existing record, are done by simply * A backup data set consists of one or more "entities," flattened binary data * records that are each identified with a key string unique within the data set. Adding a * record to the active data set or updating an existing record is done by simply * writing new entity data under the desired key. Deleting an entity from the data set * is done by writing an entity under that key with header specifying a negative data * size, and no actual entity data. Loading Loading
core/java/android/app/ActivityThread.java +42 −20 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ public final class ActivityThread { } WeakReference<Resources> wr = mActiveResources.get(key); r = wr != null ? wr.get() : null; //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); if (r != null && r.getAssets().isUpToDate()) { if (false) { Slog.w(TAG, "Returning cached resources " + r + " " + resDir Loading Loading @@ -1752,6 +1753,10 @@ public final class ActivityThread { Debug.getMemoryInfo(outInfo); } public void dispatchPackageBroadcast(int cmd, String[] packages) { queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { long nativeMax = Debug.getNativeHeapSize() / 1024; Loading Loading @@ -1976,6 +1981,7 @@ public final class ActivityThread { public static final int SUICIDE = 130; public static final int REMOVE_PROVIDER = 131; public static final int ENABLE_JIT = 132; public static final int DISPATCH_PACKAGE_BROADCAST = 133; String codeToString(int code) { if (localLOGV) { switch (code) { Loading Loading @@ -2012,6 +2018,7 @@ public final class ActivityThread { case SUICIDE: return "SUICIDE"; case REMOVE_PROVIDER: return "REMOVE_PROVIDER"; case ENABLE_JIT: return "ENABLE_JIT"; case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; } } return "(unknown)"; Loading Loading @@ -2132,6 +2139,9 @@ public final class ActivityThread { case ENABLE_JIT: ensureJitEnabled(); break; case DISPATCH_PACKAGE_BROADCAST: handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj); break; } } Loading Loading @@ -2244,7 +2254,7 @@ public final class ActivityThread { = new HashMap<String, WeakReference<PackageInfo>>(); Display mDisplay = null; DisplayMetrics mDisplayMetrics = null; HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new HashMap<ResourcesKey, WeakReference<Resources> >(); final ArrayList<ActivityRecord> mRelaunchingActivities = new ArrayList<ActivityRecord>(); Loading @@ -2271,6 +2281,8 @@ public final class ActivityThread { } PackageInfo packageInfo = ref != null ? ref.get() : null; //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo); //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir // + ": " + packageInfo.mResources.getAssets().isUpToDate()); if (packageInfo != null && (packageInfo.mResources == null || packageInfo.mResources.getAssets().isUpToDate())) { if (packageInfo.isSecurityViolation() Loading Loading @@ -2358,21 +2370,6 @@ public final class ActivityThread { } } public final boolean hasPackageInfo(String packageName) { synchronized (mPackages) { WeakReference<PackageInfo> ref; ref = mPackages.get(packageName); if (ref != null && ref.get() != null) { return true; } ref = mResourcePackages.get(packageName); if (ref != null && ref.get() != null) { return true; } return false; } } ActivityThread() { } Loading Loading @@ -4054,6 +4051,31 @@ public final class ActivityThread { } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { boolean hasPkgInfo = false; if (packages != null) { for (int i=packages.length-1; i>=0; i--) { //Slog.i(TAG, "Cleaning old package: " + packages[i]); if (!hasPkgInfo) { WeakReference<PackageInfo> ref; ref = mPackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; } else { ref = mResourcePackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; } } } mPackages.remove(packages[i]); mResourcePackages.remove(packages[i]); } } ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo); } final void handleLowMemory() { ArrayList<ComponentCallbacks> callbacks = new ArrayList<ComponentCallbacks>(); Loading
core/java/android/app/ApplicationThreadNative.java +20 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,15 @@ public abstract class ApplicationThreadNative extends Binder mi.writeToParcel(reply, 0); return true; } case DISPATCH_PACKAGE_BROADCAST_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); int cmd = data.readInt(); String[] packages = data.readStringArray(); dispatchPackageBroadcast(cmd, packages); return true; } } return super.onTransact(code, data, reply, flags); Loading Loading @@ -806,5 +815,16 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); reply.recycle(); } public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeInt(cmd); data.writeStringArray(packages); mRemote.transact(DISPATCH_PACKAGE_BROADCAST_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } }
core/java/android/app/ContextImpl.java +22 −65 Original line number Diff line number Diff line Loading @@ -2244,33 +2244,7 @@ class ContextImpl extends Context { return null; } private void establishPackageRemovedReceiver() { // mContext.registerReceiverInternal() winds up acquiring the // main ActivityManagerService.this lock. If we hold our usual // sSync global lock at the same time, we impose a required ordering // on those two locks, which is not good for deadlock prevention. // Use a dedicated lock around initialization of // sPackageRemovedReceiver to avoid this. synchronized (sPackageRemovedSync) { if (sPackageRemovedReceiver == null) { sPackageRemovedReceiver = new PackageRemovedReceiver(); IntentFilter filter = new IntentFilter( Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiverInternal(sPackageRemovedReceiver, filter, null, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiverInternal(sPackageRemovedReceiver, sdFilter, null, null, null); } } } private void putCachedIcon(ResourceName name, Drawable dr) { establishPackageRemovedReceiver(); synchronized (sSync) { sIconCache.put(name, new WeakReference<Drawable>(dr)); if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for " Loading @@ -2278,29 +2252,17 @@ class ContextImpl extends Context { } } private static final class PackageRemovedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String pkgList[] = null; String action = intent.getAction(); static final void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) { boolean immediateGc = false; if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) { immediateGc = true; } else { Uri data = intent.getData(); if (data != null) { String ssp = data.getSchemeSpecificPart(); if (ssp != null) { pkgList = new String[] { ssp }; } } } if (pkgList != null && (pkgList.length > 0)) { boolean needCleanup = false; boolean hasPkgInfo = false; for (String ssp : pkgList) { synchronized (sSync) { if (sIconCache.size() > 0) { Iterator<ResourceName> it = sIconCache.keySet().iterator(); while (it.hasNext()) { ResourceName nm = it.next(); Loading @@ -2310,7 +2272,9 @@ class ContextImpl extends Context { needCleanup = true; } } it = sStringCache.keySet().iterator(); } if (sStringCache.size() > 0) { Iterator<ResourceName> it = sStringCache.keySet().iterator(); while (it.hasNext()) { ResourceName nm = it.next(); if (nm.packageName.equals(ssp)) { Loading @@ -2320,8 +2284,6 @@ class ContextImpl extends Context { } } } if (!hasPkgInfo) { hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp); } } if (needCleanup || hasPkgInfo) { Loading @@ -2334,7 +2296,6 @@ class ContextImpl extends Context { } } } } private static final class ResourceName { final String packageName; Loading Loading @@ -2400,8 +2361,6 @@ class ContextImpl extends Context { } private void putCachedString(ResourceName name, CharSequence cs) { establishPackageRemovedReceiver(); synchronized (sSync) { sStringCache.put(name, new WeakReference<CharSequence>(cs)); } Loading Loading @@ -2665,8 +2624,6 @@ class ContextImpl extends Context { private final IPackageManager mPM; private static final Object sSync = new Object(); private static final Object sPackageRemovedSync = new Object(); private static BroadcastReceiver sPackageRemovedReceiver; private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache = new HashMap<ResourceName, WeakReference<Drawable> >(); private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache Loading
core/java/android/app/IApplicationThread.java +4 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,9 @@ public interface IApplicationThread extends IInterface { throws RemoteException; void setSchedulingGroup(int group) throws RemoteException; void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException; static final int PACKAGE_REMOVED = 0; static final int EXTERNAL_STORAGE_UNAVAILABLE = 1; void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException; String descriptor = "android.app.IApplicationThread"; Loading Loading @@ -135,4 +138,5 @@ public interface IApplicationThread extends IInterface { 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; int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33; }
core/java/android/app/backup/BackupAgent.java +20 −18 Original line number Diff line number Diff line Loading @@ -29,42 +29,44 @@ import android.util.Log; import java.io.IOException; /** * {@link android.app.backup.BackupAgent} is the central interface between an * Provides the central interface between an * application and Android's data backup infrastructure. An application that wishes * to participate in the backup and restore mechanism will declare a subclass of * {@link android.app.backup.BackupAgent}, implement the * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} methods, * and provide the name of its agent class in the AndroidManifest.xml file via * the <application> tag's android:backupAgent attribute. * <p> * <b>Basic Operation</b> * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods, * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via * the <code><a * href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> * tag's {@code android:backupAgent} attribute. * <h3>Basic Operation</h3> * <p> * When the application makes changes to data that it wishes to keep backed up, * it should call the * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method. * This notifies the Android backup manager that the application needs an opportunity * to update its backup image. The backup manager, in turn, will then schedule a * This notifies the Android Backup Manager that the application needs an opportunity * to update its backup image. The Backup Manager, in turn, schedules a * backup pass to be performed at an opportune time. * <p> * Restore operations are typically only performed when applications are first * Restore operations are typically performed only when applications are first * installed on a device. At that time, the operating system checks to see whether * there is a previously-saved data set available for the application, and if so, * begins an immediate restore pass to deliver that data as part of the installation * there is a previously-saved data set available for the application being installed, and if so, * begins an immediate restore pass to deliver the backup data as part of the installation * process. * <p> * When a backup or restore pass is run, the application's process will be launched * (if not already running), the manifest-declared agent class instantiated within * that process, and the agent's {@link #onCreate()} method invoked. This prepares the * When a backup or restore pass is run, the application's process is launched * (if not already running), the manifest-declared backup agent class (in the {@code * android:backupAgent} attribute) is instantiated within * that process, and the agent's {@link #onCreate()} method is invoked. This prepares the * agent instance to run the actual backup or restore logic. At this point the * agent's * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be * invoked as appropriate for the operation being performed. * <p> * A backup data set consists of one or more "entities," flattened binary data records * that are each identified with a key string unique within the data set. Adding a * record to the active data set, or updating an existing record, are done by simply * A backup data set consists of one or more "entities," flattened binary data * records that are each identified with a key string unique within the data set. Adding a * record to the active data set or updating an existing record is done by simply * writing new entity data under the desired key. Deleting an entity from the data set * is done by writing an entity under that key with header specifying a negative data * size, and no actual entity data. Loading