Add atlas map pointer validation

 Bug: 15425820

 This just prevents the crash, it's still unclear how bad pointers
 are getting into the map in the first place

Change-Id: I3acffaae09548ec48973035b7fcf5f35606bad60
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2bfbd65..166edc2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,21 +16,29 @@
 
 package android.view;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
+import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
 
 /**
  * Hardware renderer that proxies the rendering to a render thread. Most calls
@@ -71,8 +79,8 @@
     private Choreographer mChoreographer;
     private boolean mProfilingEnabled;
 
-    ThreadedRenderer(boolean translucent) {
-        AtlasInitializer.sInstance.init();
+    ThreadedRenderer(Context context, boolean translucent) {
+        AtlasInitializer.sInstance.init(context);
 
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
@@ -334,7 +342,7 @@
 
         private AtlasInitializer() {}
 
-        synchronized void init() {
+        synchronized void init(Context context) {
             if (mInitialized) return;
             IBinder binder = ServiceManager.getService("assetatlas");
             if (binder == null) return;
@@ -346,6 +354,8 @@
                     if (buffer != null) {
                         long[] map = atlas.getMap();
                         if (map != null) {
+                            // TODO Remove after fixing b/15425820
+                            validateMap(context, map);
                             nSetAtlas(buffer, map);
                             mInitialized = true;
                         }
@@ -361,6 +371,30 @@
                 Log.w(LOG_TAG, "Could not acquire atlas", e);
             }
         }
+
+        private static void validateMap(Context context, long[] map) {
+            Log.d("Atlas", "Validating map...");
+            HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+            // We only care about drawables that hold bitmaps
+            final Resources resources = context.getResources();
+            final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+            final int count = drawables.size();
+            for (int i = 0; i < count; i++) {
+                final Bitmap bitmap = drawables.valueAt(i).getBitmap();
+                if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
+                    preloadedPointers.add(bitmap.mNativeBitmap);
+                }
+            }
+
+            for (int i = 0; i < map.length; i += 4) {
+                if (!preloadedPointers.contains(map[i])) {
+                    Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+                    map[i] = 0;
+                }
+            }
+        }
     }
 
     static native void setupShadersDiskCache(String cacheFile);