Bug 863288 - Add sanity checks and error logging for bitmap decoding. r=mfinkle

This commit is contained in:
Chris Peterson 2013-04-22 18:03:01 -07:00
parent 2c93e9b902
commit 67c16f339d
9 changed files with 67 additions and 36 deletions

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;
@ -19,7 +20,6 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -657,8 +657,9 @@ public class AwesomeBar extends GeckoActivity
}
Bitmap bitmap = null;
if (b != null)
bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
if (b != null) {
bitmap = BitmapUtils.decodeByteArray(b);
}
String shortcutTitle = TextUtils.isEmpty(title) ? url.replaceAll("^([a-z]+://)?(www\\.)?", "") : title;
GeckoAppShell.createShortcut(shortcutTitle, url, bitmap, "");

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.background.announcements.AnnouncementsBroadcastService;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
@ -1156,10 +1157,10 @@ abstract public class GeckoApp
if (isDataURI) {
int dataStart = aSrc.indexOf(',');
byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
BitmapFactory.decodeByteArray(buf, 0, buf.length, options);
BitmapUtils.decodeByteArray(buf, options);
options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeByteArray(buf, 0, buf.length, options);
image = BitmapUtils.decodeByteArray(buf, options);
} else {
int byteRead;
byte[] buf = new byte[4192];
@ -1174,10 +1175,10 @@ abstract public class GeckoApp
os.write(buf, 0, byteRead);
}
byte[] imgBuffer = os.toByteArray();
BitmapFactory.decodeByteArray(imgBuffer, 0, imgBuffer.length, options);
BitmapUtils.decodeByteArray(imgBuffer, options);
options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeByteArray(imgBuffer, 0, imgBuffer.length, options);
image = BitmapUtils.decodeByteArray(imgBuffer, options);
}
if(image != null) {
mgr.setBitmap(image);
@ -1186,7 +1187,7 @@ abstract public class GeckoApp
return false;
}
} catch(OutOfMemoryError ome) {
Log.e(LOGTAG, "Out of Memmory when coverting to byte array", ome);
Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
return false;
} catch(IOException ioe) {
Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe);

View File

@ -6,11 +6,11 @@
package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.nio.ByteBuffer;
@ -187,18 +187,14 @@ public final class ThumbnailHelper {
}
private void setTabThumbnail(Tab tab, Bitmap bitmap, byte[] compressed) {
try {
if (bitmap == null) {
if (compressed == null) {
Log.w(LOGTAG, "setTabThumbnail: one of bitmap or compressed must be non-null!");
return;
}
bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
if (bitmap == null) {
if (compressed == null) {
Log.w(LOGTAG, "setTabThumbnail: one of bitmap or compressed must be non-null!");
return;
}
tab.updateThumbnail(bitmap);
} catch (OutOfMemoryError ome) {
Log.w(LOGTAG, "setTabThumbnail: decoding byte array of length " + compressed.length + " ran out of memory");
bitmap = BitmapUtils.decodeByteArray(compressed);
}
tab.updateThumbnail(bitmap);
}
private boolean shouldUpdateThumbnail(Tab tab) {

View File

@ -24,7 +24,6 @@ import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
@ -898,8 +897,8 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
if (b == null)
continue;
Bitmap favicon = BitmapFactory.decodeByteArray(b, 0, b.length);
if (favicon == null || favicon.getWidth() <= 0 || favicon.getHeight() <= 0)
Bitmap favicon = BitmapUtils.decodeByteArray(b);
if (favicon == null)
continue;
favicon = Favicons.getInstance().scaleImage(favicon);

View File

@ -7,13 +7,13 @@ package org.mozilla.gecko;
import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.gfx.BitmapUtils;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@ -91,8 +91,8 @@ abstract public class AwesomeBarTab {
byte[] b = cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
Bitmap favicon = null;
if (b != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
if (bitmap != null && bitmap.getWidth() > 0 && bitmap.getHeight() > 0) {
Bitmap bitmap = BitmapUtils.decodeByteArray(b);
if (bitmap != null) {
favicon = Favicons.getInstance().scaleImage(bitmap);
}
}

View File

@ -9,6 +9,7 @@ import org.mozilla.gecko.AwesomeBar.ContextMenuSubject;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.ThreadUtils;
@ -19,7 +20,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
@ -27,7 +27,6 @@ import android.util.Pair;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
@ -193,8 +192,8 @@ public class HistoryTab extends AwesomeBarTab {
Bitmap favicon = null;
if (b != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
if (bitmap != null && bitmap.getWidth() > 0 && bitmap.getHeight() > 0) {
Bitmap bitmap = BitmapUtils.decodeByteArray(b);
if (bitmap != null) {
favicon = Favicons.getInstance().scaleImage(bitmap);
}
}

View File

@ -14,6 +14,7 @@ import org.mozilla.gecko.db.BrowserContract.History;
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.gfx.BitmapUtils;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@ -22,7 +23,6 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.provider.Browser;
@ -707,14 +707,13 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
}
int faviconIndex = c.getColumnIndexOrThrow(Combined.FAVICON);
byte[] b = c.getBlob(faviconIndex);
c.close();
if (b == null)
return null;
return BitmapFactory.decodeByteArray(b, 0, b.length);
return BitmapUtils.decodeByteArray(b);
}
@Override

View File

@ -14,6 +14,42 @@ import android.util.Log;
public final class BitmapUtils {
private static final String LOGTAG = "GeckoBitmapUtils";
private BitmapUtils() {}
public static Bitmap decodeByteArray(byte[] bytes) {
return decodeByteArray(bytes, null);
}
public static Bitmap decodeByteArray(byte[] bytes, BitmapFactory.Options options) {
if (bytes.length <= 0) {
throw new IllegalArgumentException("bytes.length " + bytes.length
+ " must be a positive number");
}
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
} catch (OutOfMemoryError e) {
Log.e(LOGTAG, "decodeByteArray(bytes.length=" + bytes.length
+ ", options= " + options + ") OOM!", e);
return null;
}
if (bitmap == null) {
Log.w(LOGTAG, "decodeByteArray() returning null because BitmapFactory returned null");
return null;
}
if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
Log.w(LOGTAG, "decodeByteArray() returning null because BitmapFactory returned "
+ "a bitmap with dimensions " + bitmap.getWidth()
+ "x" + bitmap.getHeight());
return null;
}
return bitmap;
}
public static int getDominantColor(Bitmap source) {
return getDominantColor(source, true);
}
@ -74,7 +110,7 @@ public final class BitmapUtils {
String base64 = dataURI.substring(dataURI.indexOf(',') + 1);
try {
byte[] raw = Base64.decode(base64, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(raw, 0, raw.length);
return BitmapUtils.decodeByteArray(raw);
} catch (Exception e) {
Log.e(LOGTAG, "exception decoding bitmap from data URI: " + dataURI, e);
}

View File

@ -15,6 +15,7 @@ import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.TopSitesCursorWrapper;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
@ -25,7 +26,6 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
@ -313,7 +313,7 @@ public class TopSitesView extends GridView {
if (b == null)
continue;
Bitmap thumbnail = BitmapFactory.decodeByteArray(b, 0, b.length);
Bitmap thumbnail = BitmapUtils.decodeByteArray(b);
if (thumbnail == null)
continue;
@ -658,7 +658,7 @@ public class TopSitesView extends GridView {
final byte[] b = c.getBlob(c.getColumnIndexOrThrow(Thumbnails.DATA));
Bitmap bitmap = null;
if (b != null) {
bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
bitmap = BitmapUtils.decodeByteArray(b);
}
c.close();