Merge changes Ia95ff014,Ib31708c3

* changes:
  MTP: Add debug code for printing names of MTP format and property codes.
  MTP: Fix some typos
diff --git a/core/java/android/util/Finalizers.java b/core/java/android/util/Finalizers.java
new file mode 100644
index 0000000..671f2d4
--- /dev/null
+++ b/core/java/android/util/Finalizers.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 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 android.util;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+
+/**
+ * This class can be used to implement reliable finalizers.
+ * 
+ * @hide
+ */
+public final class Finalizers {
+    private static final String LOG_TAG = "Finalizers";
+    
+    private static final Object[] sLock = new Object[0];
+    private static boolean sInit;
+    private static Reclaimer sReclaimer;
+
+    /**
+     * Subclass of PhantomReference used to reclaim resources.
+     */
+    public static abstract class ReclaimableReference<T> extends PhantomReference<T> {
+        public ReclaimableReference(T r, ReferenceQueue<Object> q) {
+            super(r, q);
+        }
+        
+        public abstract void reclaim();
+    }
+
+    /**
+     * Returns the queue used to reclaim ReclaimableReferences.
+     * 
+     * @return A reference queue or null before initialization
+     */
+    public static ReferenceQueue<Object> getQueue() {
+        synchronized (sLock) {
+            if (!sInit) {
+                return null;
+            }
+            if (!sReclaimer.isRunning()) {
+                sReclaimer = new Reclaimer(sReclaimer.mQueue);
+                sReclaimer.start();
+            }
+            return sReclaimer.mQueue;
+        }
+    }
+
+    /**
+     * Invoked by Zygote. Don't touch!
+     */
+    public static void init() {
+        synchronized (sLock) {
+            if (!sInit && sReclaimer == null) {
+                sReclaimer = new Reclaimer();
+                sReclaimer.start();
+                sInit = true;
+            }
+        }
+    }
+    
+    private static class Reclaimer extends Thread {
+        ReferenceQueue<Object> mQueue;
+
+        private volatile boolean mRunning = false;
+
+        Reclaimer() {
+            this(new ReferenceQueue<Object>());
+        }
+
+        Reclaimer(ReferenceQueue<Object> queue) {
+            super("Reclaimer");
+            setDaemon(true);
+            mQueue = queue;            
+        }
+
+        @Override
+        public void start() {
+            mRunning = true;
+            super.start();
+        }
+
+        boolean isRunning() {
+            return mRunning;
+        }
+
+        @SuppressWarnings({"InfiniteLoopStatement"})
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    try {
+                        cleanUp(mQueue.remove());
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Reclaimer thread exiting: ", e);
+            } finally {
+                mRunning = false;
+            }
+        }
+
+        private void cleanUp(Reference<?> reference) {
+            do {
+                reference.clear();
+                ((ReclaimableReference<?>) reference).reclaim();
+            } while ((reference = mQueue.poll()) != null);
+        }
+    }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7c644e4..735b35a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1828,8 +1828,8 @@
 
     private int[] mDrawableState = null;
 
-    private SoftReference<Bitmap> mDrawingCache;
-    private SoftReference<Bitmap> mUnscaledDrawingCache;
+    private Bitmap mDrawingCache;
+    private Bitmap mUnscaledDrawingCache;
 
     /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -6916,8 +6916,7 @@
         if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
             buildDrawingCache(autoScale);
         }
-        return autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
-                (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
+        return autoScale ? mDrawingCache : mUnscaledDrawingCache;
     }
 
     /**
@@ -6932,13 +6931,11 @@
      */
     public void destroyDrawingCache() {
         if (mDrawingCache != null) {
-            final Bitmap bitmap = mDrawingCache.get();
-            if (bitmap != null) bitmap.recycle();
+            mDrawingCache.recycle();
             mDrawingCache = null;
         }
         if (mUnscaledDrawingCache != null) {
-            final Bitmap bitmap = mUnscaledDrawingCache.get();
-            if (bitmap != null) bitmap.recycle();
+            mUnscaledDrawingCache.recycle();
             mUnscaledDrawingCache = null;
         }
     }
@@ -6999,8 +6996,7 @@
      */
     public void buildDrawingCache(boolean autoScale) {
         if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
-                (mDrawingCache == null || mDrawingCache.get() == null) :
-                (mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) {
+                mDrawingCache == null : mUnscaledDrawingCache == null)) {
 
             if (ViewDebug.TRACE_HIERARCHY) {
                 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
@@ -7033,8 +7029,7 @@
             }
 
             boolean clear = true;
-            Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
-                    (mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
+            Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;
 
             if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
                 Bitmap.Config quality;
@@ -7066,9 +7061,9 @@
                     bitmap = Bitmap.createBitmap(width, height, quality);
                     bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
                     if (autoScale) {
-                        mDrawingCache = new SoftReference<Bitmap>(bitmap);
+                        mDrawingCache = bitmap;
                     } else {
-                        mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
+                        mUnscaledDrawingCache = bitmap;
                     }
                     if (opaque && translucentWindow) bitmap.setHasAlpha(false);
                 } catch (OutOfMemoryError e) {
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 59600dc..5767832 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -24,6 +24,7 @@
 import android.os.Process;
 import android.os.SystemProperties;
 import android.util.Config;
+import android.util.Finalizers;
 import android.util.Log;
 import android.util.Slog;
 
@@ -141,6 +142,12 @@
             Debug.enableEmulatorTraceOutput();
         }
 
+        /**
+         * Initialize the thread used to reclaim resources without
+         * going through finalizers.
+         */
+        Finalizers.init();
+
         initialized = true;
     }
 
@@ -331,9 +338,6 @@
         }
     }
 
-    /** Counter used to prevent reentrancy in {@link #reportException}. */
-    private static final AtomicInteger sInReportException = new AtomicInteger();
-
     /**
      * Set the object identifying this application/process, for reporting VM
      * errors.
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 537dd3a..d9ee3ec 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -19,12 +19,16 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.DisplayMetrics;
+import android.util.Finalizers;
 
 import java.io.OutputStream;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 public final class Bitmap implements Parcelable {
     /**
@@ -55,7 +59,7 @@
     private static volatile Matrix sScaleMatrix;
 
     private static volatile int sDefaultDensity = -1;
-    
+
     /**
      * For backwards compatibility, allows the app layer to change the default
      * density when running old apps.
@@ -81,8 +85,7 @@
 
         This can be called from JNI code.
     */
-    private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk,
-            int density) {
+    private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk, int density) {
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
         }
@@ -94,6 +97,13 @@
         if (density >= 0) {
             mDensity = density;
         }
+
+        // If the finalizers queue is null, we are running in zygote and the
+        // bitmap will never be reclaimed, so we don't need to run our native
+        // destructor
+        if (Finalizers.getQueue() != null) {
+            new BitmapFinalizer(this);
+        }
     }
 
     /**
@@ -1016,12 +1026,22 @@
         nativePrepareToDraw(mNativeBitmap);
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
+    private static class BitmapFinalizer extends Finalizers.ReclaimableReference<Bitmap> {
+        private static final Set<BitmapFinalizer> sFinalizers = Collections.synchronizedSet(
+                new HashSet<BitmapFinalizer>());
+
+        private int mNativeBitmap;
+
+        BitmapFinalizer(Bitmap b) {
+            super(b, Finalizers.getQueue());
+            mNativeBitmap = b.mNativeBitmap;
+            sFinalizers.add(this);
+        }
+
+        @Override
+        public void reclaim() {
             nativeDestructor(mNativeBitmap);
-        } finally {
-            super.finalize();
+            sFinalizers.remove(this);
         }
     }