Bug 863154 - Part 2: Catch Bitmap OOMs when decoding resources. r=mfinkle
authorChris Peterson <cpeterson@mozilla.com>
Tue, 07 May 2013 18:30:47 -0700
changeset 142252 ae87f942ac08bca3010133ee7901ce32e52551bf
parent 142251 814044b7f85345868cdcc9739bb9d86512d9564c
child 142253 9a8c7cd83f2293987e36b1103e07d29c0263844d
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs863154
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 863154 - Part 2: Catch Bitmap OOMs when decoding resources. r=mfinkle
mobile/android/base/GeckoAppShell.java
mobile/android/base/db/BrowserProvider.java
mobile/android/base/gfx/BitmapUtils.java
mobile/android/base/gfx/LayerView.java
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -23,17 +23,16 @@ import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ImageFormat;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.SurfaceTexture;
 import android.graphics.drawable.BitmapDrawable;
@@ -794,22 +793,22 @@ public class GeckoAppShell
             int color = BitmapUtils.getDominantColor(aSource);
             paint.setColor(color);
             canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
             paint.setColor(Color.argb(100, 255, 255, 255));
             canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
         }
 
         // draw the overlay
-        Bitmap overlay = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_bg);
+        Bitmap overlay = BitmapUtils.decodeResource(GeckoApp.mAppContext, R.drawable.home_bg);
         canvas.drawBitmap(overlay, null, new Rect(0, 0, size, size), null);
 
         // draw the favicon
         if (aSource == null)
-            aSource = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_star);
+            aSource = BitmapUtils.decodeResource(GeckoApp.mAppContext, R.drawable.home_star);
 
         // by default, we scale the icon to this size
         int sWidth = insetSize / 2;
         int sHeight = sWidth;
 
         if (aSource.getWidth() > insetSize || aSource.getHeight() > insetSize) {
             // however, if the icon is larger than our minimum, we allow it to be drawn slightly larger
             // (but not necessarily at its full resolution)
--- a/mobile/android/base/db/BrowserProvider.java
+++ b/mobile/android/base/db/BrowserProvider.java
@@ -1,76 +1,72 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.db;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.lang.Class;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
 import org.mozilla.gecko.Distribution;
 import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.ProfileMigrator;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.CommonColumns;
 import org.mozilla.gecko.db.BrowserContract.Control;
+import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.Favicons;
-import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.Schema;
 import org.mozilla.gecko.db.BrowserContract.SyncColumns;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.DBUtils;
 import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.ProfileMigrator;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.util.GeckoJarReader;
 import org.mozilla.gecko.util.ThreadUtils;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import android.app.SearchManager;
 import android.content.ContentProvider;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
 import android.content.ContentUris;
 import android.content.ContentValues;
-import android.content.ContentProviderResult;
-import android.content.ContentProviderOperation;
 import android.content.Context;
 import android.content.OperationApplicationException;
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.MatrixCursor;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
-import android.graphics.BitmapFactory;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class BrowserProvider extends ContentProvider {
     private static final String LOGTAG = "GeckoBrowserProvider";
     private Context mContext;
 
     static final String DATABASE_NAME = "browser.db";
 
     static final int DATABASE_VERSION = 16;
@@ -1247,17 +1243,17 @@ public class BrowserProvider extends Con
             Class<?> drawablesClass = R.drawable.class;
             try {
                 // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
                 Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_"));
                 if (faviconField == null) {
                     return null;
                 }
                 int faviconId = faviconField.getInt(null);
-                return BitmapFactory.decodeResource(mContext.getResources(), faviconId);
+                return BitmapUtils.decodeResource(mContext, faviconId);
             } catch (java.lang.IllegalAccessException ex) {
                 Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
             } catch (java.lang.NoSuchFieldException ex) {
                 // If the field does not exist, that means we intend to load via a file path
             }
             return null;
         }
 
--- a/mobile/android/base/gfx/BitmapUtils.java
+++ b/mobile/android/base/gfx/BitmapUtils.java
@@ -1,15 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.net.Uri;
 import android.util.Base64;
 import android.util.Log;
 
 import java.io.IOException;
@@ -103,16 +105,30 @@ public final class BitmapUtils {
             stream.close();
         } catch(IOException e) {
             Log.w(LOGTAG, "decodeUrl: IOException closing stream " + url, e);
         }
 
         return bitmap;
     }
 
+    public static Bitmap decodeResource(Context context, int id) {
+        return decodeResource(context, id, null);
+    }
+
+    public static Bitmap decodeResource(Context context, int id, BitmapFactory.Options options) {
+        Resources resources = context.getResources();
+        try {
+            return BitmapFactory.decodeResource(resources, id, options);
+        } catch (OutOfMemoryError e) {
+            Log.e(LOGTAG, "decodeResource() OOM! Resource id=" + id, e);
+            return null;
+        }
+    }
+
     public static int getDominantColor(Bitmap source) {
         return getDominantColor(source, true);
     }
 
     public static int getDominantColor(Bitmap source, boolean applyThreshold) {
       if (source == null)
         return Color.argb(255,255,255,255);
 
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -383,17 +383,17 @@ public class LayerView extends FrameLayo
 
     public GLController getGLController() {
         return mGLController;
     }
 
     private Bitmap getDrawable(int resId) {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inScaled = false;
-        return BitmapFactory.decodeResource(getContext().getResources(), resId, options);
+        return BitmapUtils.decodeResource(getContext(), resId, options);
     }
 
     Bitmap getShadowPattern() {
         return getDrawable(R.drawable.shadow);
     }
 
     Bitmap getScrollbarImage() {
         return getDrawable(R.drawable.scrollbar);