Merge "Fix wakelock"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4464ab9..f296f43 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2935,9 +2935,14 @@
         private boolean writeFileLocked() {
             // Rename the current file so it may be used as a backup during the next read
             if (mFile.exists()) {
-                if (!mFile.renameTo(mBackupFile)) {
-                    Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile);
-                    return false;
+                if (!mBackupFile.exists()) {
+                    if (!mFile.renameTo(mBackupFile)) {
+                        Log.e(TAG, "Couldn't rename file " + mFile
+                                + " to backup file " + mBackupFile);
+                        return false;
+                    }
+                } else {
+                    mFile.delete();
                 }
             }
             
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 4780cf3..a17b7fe 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -115,6 +115,9 @@
      */
     public static boolean copyToFile(InputStream inputStream, File destFile) {
         try {
+            if (destFile.exists()) {
+                destFile.delete();
+            }
             OutputStream out = new FileOutputStream(destFile);
             try {
                 byte[] buffer = new byte[4096];
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8311bdc..2b5489c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -546,6 +546,9 @@
         recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
         recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
         try {
+            if (recyclerDump.exists()) {
+                recyclerDump.delete();
+            }
             final FileOutputStream file = new FileOutputStream(recyclerDump);
             final DataOutputStream out = new DataOutputStream(file);
 
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 9e4b606..b436363 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -105,6 +105,9 @@
                         + " key64=" + base64Key);
 
                 if (dataSize >= 0) {
+                    if (entityFile.exists()) {
+                        entityFile.delete();
+                    }
                     FileOutputStream entity = new FileOutputStream(entityFile);
 
                     if (dataSize > bufSize) {
diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java
index ca0345f..e675ef0 100644
--- a/core/java/com/android/internal/os/AtomicFile.java
+++ b/core/java/com/android/internal/os/AtomicFile.java
@@ -45,12 +45,13 @@
     public FileOutputStream startWrite() throws IOException {
         // Rename the current file so it may be used as a backup during the next read
         if (mBaseName.exists()) {
-            if (!mBaseName.renameTo(mBackupName)) {
-                mBackupName.delete();
+            if (!mBackupName.exists()) {
                 if (!mBaseName.renameTo(mBackupName)) {
                     Log.w("AtomicFile", "Couldn't rename file " + mBaseName
                             + " to backup file " + mBackupName);
                 }
+            } else {
+                mBaseName.delete();
             }
         }
         FileOutputStream str = null;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 71ccb3b..46769ce 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.os;
 
+import com.android.internal.util.JournaledFile;
+
 import android.bluetooth.BluetoothHeadset;
 import android.net.TrafficStats;
 import android.os.BatteryStats;
@@ -30,6 +32,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import java.io.BufferedReader;
@@ -57,7 +60,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 42;
+    private static final int VERSION = 43;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -68,8 +71,7 @@
     
     private static int sNumSpeedSteps;
 
-    private final File mFile;
-    private final File mBackupFile;
+    private final JournaledFile mFile;
 
     /**
      * The statistics we have collected organized by uids.
@@ -216,7 +218,7 @@
     
     // For debugging
     public BatteryStatsImpl() {
-        mFile = mBackupFile = null;
+        mFile = null;
     }
 
     public static interface Unpluggable {
@@ -2704,8 +2706,7 @@
     }
 
     public BatteryStatsImpl(String filename) {
-        mFile = new File(filename);
-        mBackupFile = new File(filename + ".bak");
+        mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
         mStartCount++;
         mScreenOnTimer = new StopwatchTimer(-1, null, mUnpluggables);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -2736,7 +2737,7 @@
     }
 
     public BatteryStatsImpl(Parcel p) {
-        mFile = mBackupFile = null;
+        mFile = null;
         readFromParcel(p);
     }
 
@@ -2799,7 +2800,7 @@
         
         if (m == null) {
             // Not crashing might make board bringup easier.
-            Log.w(TAG, "Couldn't get kernel wake lock stats");
+            Slog.w(TAG, "Couldn't get kernel wake lock stats");
             return;
         }
 
@@ -3047,26 +3048,19 @@
         return u.getServiceStatsLocked(pkg, name);
     }
 
+    private static JournaledFile makeJournaledFile() {
+        final String base = "/data/system/device_policies.xml";
+        return new JournaledFile(new File(base), new File(base + ".tmp"));
+    }
+
     public void writeLocked() {
-        if ((mFile == null) || (mBackupFile == null)) {
-            Log.w("BatteryStats", "writeLocked: no file associated with this instance");
+        if (mFile == null) {
+            Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
             return;
         }
 
-        // Keep the old file around until we know the new one has
-        // been successfully written.
-        if (mFile.exists()) {
-            if (mBackupFile.exists()) {
-                mBackupFile.delete();
-            }
-            if (!mFile.renameTo(mBackupFile)) {
-                Log.w("BatteryStats", "Failed to back up file before writing new stats");
-                return;
-            }
-        }
-
         try {
-            FileOutputStream stream = new FileOutputStream(mFile);
+            FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
             Parcel out = Parcel.obtain();
             writeSummaryToParcel(out);
             stream.write(out.marshall());
@@ -3074,18 +3068,14 @@
 
             stream.flush();
             stream.close();
-            mBackupFile.delete();
+            mFile.commit();
 
             mLastWriteTime = SystemClock.elapsedRealtime();
             return;
         } catch (IOException e) {
-            Log.w("BatteryStats", "Error writing battery statistics", e);
+            Slog.w("BatteryStats", "Error writing battery statistics", e);
         }
-        if (mFile.exists()) {
-            if (!mFile.delete()) {
-                Log.w(TAG, "Failed to delete mangled file " + mFile);
-            }
-        }
+        mFile.rollback();
     }
 
     static byte[] readFully(FileInputStream stream) throws java.io.IOException {
@@ -3112,29 +3102,19 @@
     }
 
     public void readLocked() {
-        if ((mFile == null) || (mBackupFile == null)) {
-            Log.w("BatteryStats", "readLocked: no file associated with this instance");
+        if (mFile == null) {
+            Slog.w("BatteryStats", "readLocked: no file associated with this instance");
             return;
         }
 
         mUidStats.clear();
 
-        FileInputStream stream = null;
-        if (mBackupFile.exists()) {
-            try {
-                stream = new FileInputStream(mBackupFile);
-            } catch (java.io.IOException e) {
-                // We'll try for the normal settings file.
-            }
-        }
-
         try {
-            if (stream == null) {
-                if (!mFile.exists()) {
-                    return;
-                }
-                stream = new FileInputStream(mFile);
+            File file = mFile.chooseForRead();
+            if (!file.exists()) {
+                return;
             }
+            FileInputStream stream = new FileInputStream(file);
 
             byte[] raw = readFully(stream);
             Parcel in = Parcel.obtain();
@@ -3144,7 +3124,7 @@
 
             readSummaryFromParcel(in);
         } catch(java.io.IOException e) {
-            Log.e("BatteryStats", "Error reading battery statistics", e);
+            Slog.e("BatteryStats", "Error reading battery statistics", e);
         }
     }
 
@@ -3155,7 +3135,7 @@
     private void readSummaryFromParcel(Parcel in) {
         final int version = in.readInt();
         if (version != VERSION) {
-            Log.w("BatteryStats", "readFromParcel: version got " + version
+            Slog.w("BatteryStats", "readFromParcel: version got " + version
                 + ", expected " + VERSION + "; erasing old stats");
             return;
         }
@@ -3197,6 +3177,10 @@
         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
 
         int NKW = in.readInt();
+        if (NKW > 10000) {
+            Slog.w(TAG, "File corrupt: too many kernel wake locks " + NKW);
+            return;
+        }
         for (int ikw = 0; ikw < NKW; ikw++) {
             if (in.readInt() != 0) {
                 String kwltName = in.readString();
@@ -3207,6 +3191,10 @@
         sNumSpeedSteps = in.readInt();
 
         final int NU = in.readInt();
+        if (NU > 10000) {
+            Slog.w(TAG, "File corrupt: too many uids " + NU);
+            return;
+        }
         for (int iu = 0; iu < NU; iu++) {
             int uid = in.readInt();
             Uid u = new Uid(uid);
@@ -3235,6 +3223,10 @@
             }
             
             int NW = in.readInt();
+            if (NW > 10000) {
+                Slog.w(TAG, "File corrupt: too many wake locks " + NW);
+                return;
+            }
             for (int iw = 0; iw < NW; iw++) {
                 String wlName = in.readString();
                 if (in.readInt() != 0) {
@@ -3249,6 +3241,10 @@
             }
 
             int NP = in.readInt();
+            if (NP > 10000) {
+                Slog.w(TAG, "File corrupt: too many sensors " + NP);
+                return;
+            }
             for (int is = 0; is < NP; is++) {
                 int seNumber = in.readInt();
                 if (in.readInt() != 0) {
@@ -3258,6 +3254,10 @@
             }
 
             NP = in.readInt();
+            if (NP > 10000) {
+                Slog.w(TAG, "File corrupt: too many processes " + NP);
+                return;
+            }
             for (int ip = 0; ip < NP; ip++) {
                 String procName = in.readString();
                 Uid.Proc p = u.getProcessStatsLocked(procName);
@@ -3270,6 +3270,10 @@
             }
 
             NP = in.readInt();
+            if (NP > 10000) {
+                Slog.w(TAG, "File corrupt: too many packages " + NP);
+                return;
+            }
             for (int ip = 0; ip < NP; ip++) {
                 String pkgName = in.readString();
                 Uid.Pkg p = u.getPackageStatsLocked(pkgName);
diff --git a/services/java/com/android/server/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
similarity index 98%
rename from services/java/com/android/server/JournaledFile.java
rename to core/java/com/android/internal/util/JournaledFile.java
index 3d1f52d..af0c6c6 100644
--- a/services/java/com/android/server/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.internal.util;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index ee2fc12..f487a16 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -60,6 +60,7 @@
     
     public PointerLocationView(Context c) {
         super(c);
+        setFocusable(true);
         mVC = ViewConfiguration.get(c);
         mTextPaint = new Paint();
         mTextPaint.setAntiAlias(true);
@@ -350,4 +351,11 @@
         addTouchEvent(event);
         return true;
     }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent event) {
+        Log.i("Pointer", "Trackball: " + event);
+        return super.onTrackballEvent(event);
+    }
+    
 }
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/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 8cd9578..f30346b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -839,8 +839,6 @@
                                         addLocked(di, curTimeNano, ev.flags,
                                                 RawInputEvent.CLASS_TRACKBALL, me);
                                     }
-                                    
-                                    ms.finish();
                                 }
                             }
                         }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 05558d4..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");
                 }
             }
@@ -9552,6 +9553,8 @@
                    // Scan the package
                    if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
                        synchronized (mPackages) {
+                           updatePermissionsLP(pkg.packageName, pkg,
+                                   pkg.permissions.size() > 0, false);
                            retCode = PackageManager.INSTALL_SUCCEEDED;
                            pkgList.add(pkg.packageName);
                            // Post process args
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();
                 }
             }
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index b581192..dd7a169 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -2156,6 +2156,33 @@
         }
     }
 
+    /*
+     * Ensure that permissions are properly declared.
+     */
+    public void testInstallOnSdPermissionsUnmount() {
+        InstallParams ip = null;
+        boolean origMediaState = getMediaState();
+        try {
+            // **: Upon installing a package, are its declared permissions published?
+            int iFlags = PackageManager.INSTALL_INTERNAL;
+            int iApk = R.raw.install_decl_perm;
+            ip = installFromRawResource("install.apk", iApk,
+                    iFlags, false,
+                    false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+            assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
+            assertPermissions(BASE_PERMISSIONS_DEFINED);
+            // Unmount media here
+            assertTrue(unmountMedia());
+            // Mount media again
+            mountMedia();
+            //Check permissions now
+            assertPermissions(BASE_PERMISSIONS_DEFINED);
+        } finally {
+            if (ip != null) {
+                cleanUpInstall(ip);
+            }
+        }
+    }
     /*---------- Recommended install location tests ----*/
     /*
      * TODO's