Maybe fix issue #2457218: Corrupt batterystats.bin file preventing phone boot - LIBtt68127

No steps to repro, but makes the code more robust by using the standard
JournaledFile class and doing sanity checks on the input it reads.

This required moving the JournaledFile class in to the framework (and
we really should get rid of either it or AtomicFile, but they have
different recovery semantics so that is tough).  Also went through and
cleaned up the file management in various places.

Change-Id: Ieb7268d8435e77dff66b6e67bb63b62e5dea572e
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index a555244..1d71577 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 
diff --git a/services/java/com/android/server/JournaledFile.java b/services/java/com/android/server/JournaledFile.java
deleted file mode 100644
index 3d1f52d..0000000
--- a/services/java/com/android/server/JournaledFile.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import java.io.File;
-import java.io.IOException;
-
-public class JournaledFile {
-    File mReal;
-    File mTemp;
-    boolean mWriting;
-
-    public JournaledFile(File real, File temp) {
-        mReal = real;
-        mTemp = temp;
-    }
-
-    /** Returns the file for you to read.
-     * @more
-     * Prefers the real file.  If it doesn't exist, uses the temp one, and then copies
-     * it to the real one.  If there is both a real file and a temp one, assumes that the
-     * temp one isn't fully written and deletes it.
-     */
-    public File chooseForRead() {
-        File result;
-        if (mReal.exists()) {
-            result = mReal;
-            if (mTemp.exists()) {
-                mTemp.delete();
-            }
-        } else if (mTemp.exists()) {
-            result = mTemp;
-            mTemp.renameTo(mReal);
-        } else {
-            return mReal;
-        }
-        return result;
-    }
-
-    /**
-     * Returns a file for you to write.
-     * @more
-     * If a write is already happening, throws.  In other words, you must provide your
-     * own locking.
-     * <p>
-     * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes.
-     */
-    public File chooseForWrite() {
-        if (mWriting) {
-            throw new IllegalStateException("uncommitted write already in progress");
-        }
-        if (!mReal.exists()) {
-            // If the real one doesn't exist, it's either because this is the first time
-            // or because something went wrong while copying them.  In this case, we can't
-            // trust anything that's in temp.  In order to have the chooseForRead code not
-            // use the temporary one until it's fully written, create an empty file
-            // for real, which will we'll shortly delete.
-            try {
-                mReal.createNewFile();
-            } catch (IOException e) {
-                // Ignore
-            }
-        }
-
-        if (mTemp.exists()) {
-            mTemp.delete();
-        }
-        mWriting = true;
-        return mTemp;
-    }
-
-    /**
-     * Commit changes.
-     */
-    public void commit() {
-        if (!mWriting) {
-            throw new IllegalStateException("no file to commit");
-        }
-        mWriting = false;
-        mTemp.renameTo(mReal);
-    }
-
-    /**
-     * Roll back changes.
-     */
-    public void rollback() {
-        if (!mWriting) {
-            throw new IllegalStateException("no file to roll back");
-        }
-        mWriting = false;
-        mTemp.delete();
-    }
-}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 677ff4a..48b3fbb 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -20,8 +20,8 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
-import com.android.server.JournaledFile;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -8280,6 +8280,7 @@
                         return;
                     }
                 } else {
+                    mSettingsFilename.delete();
                     Slog.w(TAG, "Preserving older settings backup");
                 }
             }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index f4bdd1f..124da4e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -68,6 +68,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.service.wallpaper.ImageWallpaper;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
 import com.android.server.DevicePolicyManagerService.ActiveAdmin;
 import com.android.server.DevicePolicyManagerService.MyPackageMonitor;
 
@@ -804,6 +805,9 @@
                     }
 
                     res = r.openRawResource(resId);
+                    if (WALLPAPER_FILE.exists()) {
+                        WALLPAPER_FILE.delete();
+                    }
                     fos = new FileOutputStream(WALLPAPER_FILE);
 
                     byte[] buffer = new byte[32768];
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index d170b02..1b9e1c7 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -383,9 +383,13 @@
             File backupFile = null;
             if (mFile != null && mFile.exists()) {
                 backupFile = new File(mFile.getPath() + ".bak");
-                if (!mFile.renameTo(backupFile)) {
-                    Slog.w(TAG, "Failed to persist new stats");
-                    return;
+                if (!backupFile.exists()) {
+                    if (!mFile.renameTo(backupFile)) {
+                        Slog.w(TAG, "Failed to persist new stats");
+                        return;
+                    }
+                } else {
+                    mFile.delete();
                 }
             }