Merge "UsageStatsBackup Bug Fix"
diff --git a/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/core/java/com/android/server/backup/UsageStatsBackupHelper.java
index bde2396..d6a70d3 100644
--- a/core/java/com/android/server/backup/UsageStatsBackupHelper.java
+++ b/core/java/com/android/server/backup/UsageStatsBackupHelper.java
@@ -2,11 +2,8 @@
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;
@@ -26,7 +23,7 @@
static final int BLOB_VERSION = 1;
// Key under which the payload blob is stored
- // same as UsageStatsBackupHelperAssistant.KEY_USAGE_STATS
+ // same as UsageStatsDatabase.KEY_USAGE_STATS
static final String KEY_USAGE_STATS = "usage_stats";
public UsageStatsBackupHelper(Context context) {
@@ -35,14 +32,15 @@
@Override
protected byte[] getBackupPayload(String key) {
- if(KEY_USAGE_STATS.equals(key)) {
- UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class);
+ if (KEY_USAGE_STATS.equals(key)) {
+ UsageStatsManagerInternal localUsageStatsManager =
+ LocalServices.getService(UsageStatsManagerInternal.class);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
- try{
+ try {
out.writeInt(UserHandle.USER_SYSTEM);
out.write(localUsageStatsManager.getBackupPayload(UserHandle.USER_SYSTEM, key));
- } catch (IOException ioe){
+ } catch (IOException ioe) {
if (DEBUG) Log.e(TAG, "Failed to backup Usage Stats", ioe);
baos.reset();
}
@@ -55,14 +53,15 @@
@Override
protected void applyRestoredPayload(String key, byte[] payload) {
if (KEY_USAGE_STATS.equals(key)) {
- UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class);
+ UsageStatsManagerInternal localUsageStatsManager =
+ LocalServices.getService(UsageStatsManagerInternal.class);
DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
- try{
+ try {
int user = in.readInt();
byte[] restoreData = new byte[payload.length - 4];
- in.read(restoreData, 0, payload.length-4);
+ in.read(restoreData, 0, restoreData.length);
localUsageStatsManager.applyRestoredPayload(user, key, restoreData);
- } catch (IOException ioe){
+ } 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 87c5ba0..849262e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -17,7 +17,6 @@
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;
@@ -45,7 +44,7 @@
private static final int CURRENT_VERSION = 3;
// Current version of the backup schema
- static final int BACKUP_STATE_VERSION = 1;
+ static final int BACKUP_VERSION = 1;
// Key under which the payload blob is stored
// same as UsageStatsBackupHelper.KEY_USAGE_STATS
@@ -536,6 +535,7 @@
* Update the stats in the database. They may not be written to disk immediately.
*/
public void putUsageStats(int intervalType, IntervalStats stats) throws IOException {
+ if (stats == null) return;
synchronized (mLock) {
if (intervalType < 0 || intervalType >= mIntervalDirs.length) {
throw new IllegalArgumentException("Bad interval type " + intervalType);
@@ -555,36 +555,44 @@
/* Backup/Restore Code */
- protected byte[] getBackupPayload(String key){
+ 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(BACKUP_VERSION);
out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size());
- for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size(); i++){
- writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].valueAt(i));
+ for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size();
+ i++) {
+ writeIntervalStatsToStream(out,
+ mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].valueAt(i));
}
out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size());
- for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size(); i++){
- writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].valueAt(i));
+ for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size();
+ i++) {
+ writeIntervalStatsToStream(out,
+ mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].valueAt(i));
}
out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size());
- for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size(); i++){
- writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].valueAt(i));
+ for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size();
+ i++) {
+ writeIntervalStatsToStream(out,
+ mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].valueAt(i));
}
out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size());
- for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size(); i++){
- writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].valueAt(i));
+ for (int i = 0; i < mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size();
+ i++) {
+ writeIntervalStatsToStream(out,
+ mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].valueAt(i));
}
if (DEBUG) Slog.i(TAG, "Written " + baos.size() + " bytes of data");
- } catch (IOException ioe){
+ } catch (IOException ioe) {
Slog.d(TAG, "Failed to write data to output stream", ioe);
baos.reset();
}
@@ -594,55 +602,63 @@
}
- protected void applyRestoredPayload(String key, byte[] payload){
+ void applyRestoredPayload(String key, byte[] payload) {
synchronized (mLock) {
if (KEY_USAGE_STATS.equals(key)) {
// Read stats files for the current device configs
- IntervalStats dailyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_DAILY);
- IntervalStats weeklyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_WEEKLY);
- IntervalStats monthlyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_MONTHLY);
- IntervalStats yearlyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_YEARLY);
+ IntervalStats dailyConfigSource =
+ getLatestUsageStats(UsageStatsManager.INTERVAL_DAILY);
+ IntervalStats weeklyConfigSource =
+ getLatestUsageStats(UsageStatsManager.INTERVAL_WEEKLY);
+ IntervalStats monthlyConfigSource =
+ getLatestUsageStats(UsageStatsManager.INTERVAL_MONTHLY);
+ IntervalStats yearlyConfigSource =
+ getLatestUsageStats(UsageStatsManager.INTERVAL_YEARLY);
- // Delete all stats files
- for(int i = 0; i<mIntervalDirs.length; i++){
- deleteDirectoryContents(mIntervalDirs[i]);
- }
try {
DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
- int stateVersion = in.readInt();
+ int backupDataVersion = in.readInt();
+
+ // Can't handle this backup set
+ if (backupDataVersion < 1 || backupDataVersion > BACKUP_VERSION) return;
+
+ // Delete all stats files
+ // Do this after reading version and before actually restoring
+ for (int i = 0; i < mIntervalDirs.length; i++) {
+ deleteDirectoryContents(mIntervalDirs[i]);
+ }
int fileCount = in.readInt();
- for(int i = 0; i<fileCount; i++){
+ for (int i = 0; i < fileCount; i++) {
IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
stats = mergeStats(stats, dailyConfigSource);
putUsageStats(UsageStatsManager.INTERVAL_DAILY, stats);
}
fileCount = in.readInt();
- for(int i = 0; i<fileCount; i++){
+ for (int i = 0; i < fileCount; i++) {
IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
stats = mergeStats(stats, weeklyConfigSource);
putUsageStats(UsageStatsManager.INTERVAL_WEEKLY, stats);
}
fileCount = in.readInt();
- for(int i = 0; i<fileCount; i++){
+ for (int i = 0; i < fileCount; i++) {
IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
stats = mergeStats(stats, monthlyConfigSource);
putUsageStats(UsageStatsManager.INTERVAL_MONTHLY, stats);
}
fileCount = in.readInt();
- for(int i = 0; i<fileCount; i++){
+ for (int i = 0; i < fileCount; i++) {
IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
stats = mergeStats(stats, yearlyConfigSource);
putUsageStats(UsageStatsManager.INTERVAL_YEARLY, stats);
}
if (DEBUG) Slog.i(TAG, "Completed Restoring UsageStats");
- } catch (IOException ioe){
+ } catch (IOException ioe) {
Slog.d(TAG, "Failed to read data from input stream", ioe);
- }
- finally {
+ } finally {
indexFilesLocked();
}
}
@@ -654,13 +670,16 @@
* with the backed up usage statistics.
*/
private IntervalStats mergeStats(IntervalStats beingRestored, IntervalStats onDevice) {
+ if (onDevice == null) return beingRestored;
+ if (beingRestored == null) return null;
beingRestored.activeConfiguration = onDevice.activeConfiguration;
beingRestored.configurations.putAll(onDevice.configurations);
beingRestored.events = onDevice.events;
return beingRestored;
}
- private void writeIntervalStatsToStream(DataOutputStream out, AtomicFile statsFile) throws IOException{
+ private void writeIntervalStatsToStream(DataOutputStream out, AtomicFile statsFile)
+ throws IOException {
IntervalStats stats = new IntervalStats();
try {
UsageStatsXml.read(statsFile, stats);
@@ -716,7 +735,7 @@
return stats;
}
- private static void deleteDirectoryContents(File directory){
+ private static void deleteDirectoryContents(File directory) {
File[] files = directory.listFiles();
for (File file : files) {
deleteDirectory(file);
@@ -725,13 +744,15 @@
private static void deleteDirectory(File directory) {
File[] files = directory.listFiles();
- for (File file : files) {
- if (!file.isDirectory()) {
- file.delete();
- } else {
- deleteDirectory(file);
+ if (files != null) {
+ for (File file : files) {
+ if (!file.isDirectory()) {
+ file.delete();
+ } else {
+ deleteDirectory(file);
+ }
}
}
directory.delete();
}
-}
+}
\ No newline at end of file