diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 498ff811cc742..b6f1567568c29 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -19,6 +19,8 @@ package android.app.usage; import android.content.ComponentName; import android.content.res.Configuration; +import java.io.IOException; + /** * UsageStatsManager local system service interface. * @@ -109,4 +111,9 @@ public abstract class UsageStatsManagerInternal { public abstract void onParoleStateChanged(boolean isParoleOn); } + /* Backup/Restore API */ + public abstract byte[] getBackupPayload(int user, String key); + + public abstract void applyRestoredPayload(int user, String key, byte[] payload); + } diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java index 3f76e13eb70c6..cee98b8248e91 100644 --- a/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/core/java/com/android/server/backup/SystemBackupAgent.java @@ -47,6 +47,7 @@ public class SystemBackupAgent extends BackupAgentHelper { private static final String PREFERRED_HELPER = "preferred_activities"; private static final String NOTIFICATION_HELPER = "notifications"; private static final String PERMISSION_HELPER = "permissions"; + private static final String USAGE_STATS_HELPER = "usage_stats"; // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME // are also used in the full-backup file format, so must not change unless steps are @@ -96,7 +97,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper()); addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); - + addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); super.onBackup(oldState, data, newState); } @@ -131,6 +132,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper()); addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); + addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); try { super.onRestore(data, appVersionCode, newState); @@ -183,7 +185,7 @@ public class SystemBackupAgent extends BackupAgentHelper { if (restoredWallpaper) { IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService( - Context.WALLPAPER_SERVICE); + Context.WALLPAPER_SERVICE); if (wallpaper != null) { try { wallpaper.settingsRestored(); diff --git a/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/core/java/com/android/server/backup/UsageStatsBackupHelper.java new file mode 100644 index 0000000000000..bde2396780625 --- /dev/null +++ b/core/java/com/android/server/backup/UsageStatsBackupHelper.java @@ -0,0 +1,70 @@ +package com.android.server.backup; + + +import android.app.backup.BlobBackupHelper; +import android.app.usage.IUsageStatsManager; +import android.app.usage.UsageStatsManagerInternal; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.Log; + +import com.android.server.LocalServices; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class UsageStatsBackupHelper extends BlobBackupHelper { + static final String TAG = "UsgStatsBackupHelper"; // must be < 23 chars + static final boolean DEBUG = false; + + // Current version of the blob schema + static final int BLOB_VERSION = 1; + + // Key under which the payload blob is stored + // same as UsageStatsBackupHelperAssistant.KEY_USAGE_STATS + static final String KEY_USAGE_STATS = "usage_stats"; + + public UsageStatsBackupHelper(Context context) { + super(BLOB_VERSION, KEY_USAGE_STATS); + } + + @Override + protected byte[] getBackupPayload(String key) { + if(KEY_USAGE_STATS.equals(key)) { + UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + try{ + out.writeInt(UserHandle.USER_SYSTEM); + out.write(localUsageStatsManager.getBackupPayload(UserHandle.USER_SYSTEM, key)); + } catch (IOException ioe){ + if (DEBUG) Log.e(TAG, "Failed to backup Usage Stats", ioe); + baos.reset(); + } + return baos.toByteArray(); + } + return null; + } + + + @Override + protected void applyRestoredPayload(String key, byte[] payload) { + if (KEY_USAGE_STATS.equals(key)) { + UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload)); + try{ + int user = in.readInt(); + byte[] restoreData = new byte[payload.length - 4]; + in.read(restoreData, 0, payload.length-4); + localUsageStatsManager.applyRestoredPayload(user, key, restoreData); + } catch (IOException ioe){ + if (DEBUG) Log.e(TAG, "Failed to restore Usage Stats", ioe); + } + } + } +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index 0ca4bd8c6c046..87c5ba00fb922 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -17,6 +17,7 @@ package com.android.server.usage; import android.app.usage.TimeSparseArray; +import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.os.Build; import android.util.AtomicFile; @@ -25,6 +26,10 @@ import android.util.TimeUtils; import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileReader; import java.io.FileWriter; @@ -39,6 +44,14 @@ import java.util.List; class UsageStatsDatabase { private static final int CURRENT_VERSION = 3; + // Current version of the backup schema + static final int BACKUP_STATE_VERSION = 1; + + // Key under which the payload blob is stored + // same as UsageStatsBackupHelper.KEY_USAGE_STATS + static final String KEY_USAGE_STATS = "usage_stats"; + + private static final String TAG = "UsageStatsDatabase"; private static final boolean DEBUG = UsageStatsService.DEBUG; private static final String BAK_SUFFIX = ".bak"; @@ -539,4 +552,186 @@ class UsageStatsDatabase { stats.lastTimeSaved = f.getLastModifiedTime(); } } + + + /* Backup/Restore Code */ + protected byte[] getBackupPayload(String key){ + synchronized (mLock) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (KEY_USAGE_STATS.equals(key)) { + prune(System.currentTimeMillis()); + DataOutputStream out = new DataOutputStream(baos); + try { + out.writeInt(BACKUP_STATE_VERSION); + + out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size()); + for(int i = 0; i