Bug 779366 - Part 3: Move direct buffer allocation to DirectBufferAllocator. r=kats
authorChris Peterson <cpeterson@mozilla.com>
Tue, 31 Jul 2012 15:54:29 -0700
changeset 106624 4888b839508926a6da1a9f795cf18e8aaed78abe
parent 106623 bcb8b2b5a31022ee11ce766427b0a1efc4a1b5d4
child 106625 aa61e5ec56123c8411689e146ff4c3983bdc9b67
push idunknown
push userunknown
push dateunknown
reviewerskats
bugs779366
milestone17.0a1
Bug 779366 - Part 3: Move direct buffer allocation to DirectBufferAllocator. r=kats
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/Tab.java
mobile/android/base/gfx/BufferedCairoImage.java
mobile/android/base/gfx/CheckerboardImage.java
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/RectUtils.java
mobile/android/base/gfx/ScreenshotLayer.java
mobile/android/base/gfx/ScrollbarLayer.java
mobile/android/base/gfx/TextLayer.java
mobile/android/base/mozglue/DirectBufferAllocator.java
mozglue/android/nsGeckoUtils.cpp
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -9,16 +9,17 @@ import org.mozilla.gecko.gfx.BitmapUtils
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.GfxInfoThread;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.IntSize;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.RectUtils;
 import org.mozilla.gecko.gfx.ScreenshotLayer;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 import org.mozilla.gecko.util.ConfigurationUtils;
 import org.mozilla.gecko.util.FloatUtils;
 
 import org.json.JSONObject;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.NotificationManager;
@@ -239,18 +240,16 @@ public class GeckoAppShell
     public static native void notifyGetSmsFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifySmsDeleted(boolean aDeleted, int aRequestId, long aProcessId);
     public static native void notifySmsDeleteFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
 
-    public static native ByteBuffer allocateDirectBuffer(long size);
-    public static native void freeDirectBuffer(ByteBuffer buf);
     public static native void scheduleComposite();
     public static native void schedulePauseComposition();
     public static native void scheduleResumeComposition(int width, int height);
 
     public static native SurfaceBits getSurfaceBits(Surface surface);
 
     public static native void onFullScreenPluginHidden(View view);
 
@@ -2366,17 +2365,17 @@ class ScreenshotHandler implements Runna
         GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
         mMaxTextureSize = maxTextureSize[0];
         if (mMaxTextureSize == 0) {
             throw new UnsupportedOperationException();
         }
         mMaxPixels = Math.min(ScreenshotLayer.getMaxNumPixels(), mMaxTextureSize * mMaxTextureSize);
         mMinTextureSize = (int)Math.ceil(mMaxPixels / mMaxTextureSize);
         mPendingScreenshots = new LinkedList<PendingScreenshot>();
-        mBuffer = GeckoAppShell.allocateDirectBuffer(mMaxPixels * BYTES_FOR_16BPP);
+        mBuffer = DirectBufferAllocator.allocate(mMaxPixels * BYTES_FOR_16BPP);
         mDirtyRect = new RectF();
         clearDirtyRect();
     }
 
     // Invoked via reflection from robocop test
     public static void disableScreenshot() {
         sDisableScreenshot = true;
     }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -11,16 +11,20 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/ipc/app/defs.mk
 
 DIRS = locales
 
 DIST_FILES = package-name.txt
 
 include $(topsrcdir)/mobile/android/base/android-sync-files.mk
 
+MOZGLUE_JAVA_FILES := \
+  mozglue/DirectBufferAllocator.java \
+  $(NULL)
+
 UTIL_JAVA_FILES := \
   util/ConfigurationUtils.java \
   util/FloatUtils.java \
   $(NULL)
 
 FENNEC_JAVA_FILES = \
   AboutHomeContent.java \
   AboutHomeSection.java \
@@ -147,16 +151,17 @@ FENNEC_JAVA_FILES = \
   gfx/ViewportMetrics.java \
   gfx/VirtualLayer.java \
   ui/Axis.java \
   ui/PanZoomController.java \
   ui/SimpleScaleGestureDetector.java \
   ui/SubdocumentScrollHelper.java \
   GeckoNetworkManager.java \
   GeckoScreenOrientationListener.java \
+  $(MOZGLUE_JAVA_FILES) \
   $(UTIL_JAVA_FILES) \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 FENNEC_JAVA_FILES += GeckoSmsManager.java
 endif
 
 FENNEC_PP_JAVA_FILES = \
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -2,16 +2,17 @@
  * 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;
 
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.Layer;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.ContentResolver;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -137,34 +138,33 @@ public final class Tab {
     public Drawable getThumbnail() {
         return mThumbnail;
     }
 
     synchronized public ByteBuffer getThumbnailBuffer() {
         int capacity = getThumbnailWidth() * getThumbnailHeight() * 2 /* 16 bpp */;
         if (mThumbnailBuffer != null && mThumbnailBuffer.capacity() == capacity)
             return mThumbnailBuffer;
-        if (mThumbnailBuffer != null)
-            GeckoAppShell.freeDirectBuffer(mThumbnailBuffer); // not calling freeBuffer() because it would deadlock
-        return mThumbnailBuffer = GeckoAppShell.allocateDirectBuffer(capacity);
+        freeBuffer();
+        mThumbnailBuffer = DirectBufferAllocator.allocate(capacity);
+        return mThumbnailBuffer;
     }
 
     public Bitmap getThumbnailBitmap() {
         if (mThumbnailBitmap != null)
             return mThumbnailBitmap;
         return mThumbnailBitmap = Bitmap.createBitmap(getThumbnailWidth(), getThumbnailHeight(), Bitmap.Config.RGB_565);
     }
 
     public void finalize() {
         freeBuffer();
     }
 
     synchronized void freeBuffer() {
-        if (mThumbnailBuffer != null)
-            GeckoAppShell.freeDirectBuffer(mThumbnailBuffer);
+        DirectBufferAllocator.free(mThumbnailBuffer);
         mThumbnailBuffer = null;
     }
 
     int getThumbnailWidth() {
         return (int) (GeckoApp.mAppContext.getResources().getDimension(R.dimen.tab_thumbnail_width));
     }
 
     int getThumbnailHeight() {
--- a/mobile/android/base/gfx/BufferedCairoImage.java
+++ b/mobile/android/base/gfx/BufferedCairoImage.java
@@ -1,16 +1,16 @@
 /* -*- 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 org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.graphics.Bitmap;
 
 import java.nio.ByteBuffer;
 
 /** A Cairo image that simply saves a buffer of pixel data. */
 public class BufferedCairoImage extends CairoImage {
     private ByteBuffer mBuffer;
@@ -24,18 +24,18 @@ public class BufferedCairoImage extends 
     }
 
     /** Creates a buffered Cairo image from an Android bitmap. */
     public BufferedCairoImage(Bitmap bitmap) {
         setBitmap(bitmap);
     }
 
     private void freeBuffer() {
-        if (mNeedToFreeBuffer && mBuffer != null)
-            GeckoAppShell.freeDirectBuffer(mBuffer);
+        if (mNeedToFreeBuffer)
+            DirectBufferAllocator.free(mBuffer);
         mNeedToFreeBuffer = false;
         mBuffer = null;
     }
 
     protected void finalize() throws Throwable {
         try {
             freeBuffer();
         } finally {
@@ -59,13 +59,12 @@ public class BufferedCairoImage extends 
     }
 
     public void setBitmap(Bitmap bitmap) {
         mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
         mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
         mNeedToFreeBuffer = true;
 
         int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat);
-        mBuffer = GeckoAppShell.allocateDirectBuffer(mSize.getArea() * bpp);
+        mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp);
         bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
     }
 }
-
--- a/mobile/android/base/gfx/CheckerboardImage.java
+++ b/mobile/android/base/gfx/CheckerboardImage.java
@@ -1,16 +1,16 @@
 /* -*- 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 org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.graphics.Color;
 
 import java.nio.ByteBuffer;
 import java.nio.ShortBuffer;
 import java.util.Arrays;
 
 /** A Cairo image that displays a tinted checkerboard. */
@@ -26,17 +26,17 @@ public class CheckerboardImage extends C
 
     private ByteBuffer mBuffer;
     private int mMainColor;
     private boolean mShowChecks;
 
     /** Creates a new checkerboard image. */
     public CheckerboardImage() {
         int bpp = CairoUtils.bitsPerPixelForCairoFormat(FORMAT);
-        mBuffer = GeckoAppShell.allocateDirectBuffer(SIZE * SIZE * bpp / 8);
+        mBuffer = DirectBufferAllocator.allocate(SIZE * SIZE * bpp / 8);
         update(true, Color.WHITE);
     }
 
     /** Returns the current color of the checkerboard. */
     public int getColor() {
         return mMainColor;
     }
 
@@ -109,20 +109,18 @@ public class CheckerboardImage extends C
         int c = ((r << 11) | (g << 5) | b);
         // Swap endianness.
         return (short)((c >> 8) | ((c & 0xff) << 8));
     }
 
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mBuffer != null) {
-                GeckoAppShell.freeDirectBuffer(mBuffer);
-                mBuffer = null;
-            }
+            DirectBufferAllocator.free(mBuffer);
+            mBuffer = null;
         } finally {
             super.finalize();
         }
     }
 
     @Override
     public ByteBuffer getBuffer() {
         return mBuffer;
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -2,16 +2,17 @@
  * 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 org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.gfx.Layer.RenderContext;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.RegionIterator;
@@ -158,29 +159,27 @@ public class LayerRenderer {
         mVertScrollLayer = ScrollbarLayer.create(this, true);
         mFadeRunnable = new FadeRunnable();
 
         mFrameTimings = new int[60];
         mCurrentFrame = mFrameTimingsSum = mDroppedFrames = 0;
 
         // Initialize the FloatBuffer that will be used to store all vertices and texture
         // coordinates in draw() commands.
-        mCoordByteBuffer = GeckoAppShell.allocateDirectBuffer(COORD_BUFFER_SIZE * 4);
+        mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4);
         mCoordByteBuffer.order(ByteOrder.nativeOrder());
         mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
     }
 
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mCoordByteBuffer != null) {
-                GeckoAppShell.freeDirectBuffer(mCoordByteBuffer);
-                mCoordByteBuffer = null;
-                mCoordBuffer = null;
-            }
+            DirectBufferAllocator.free(mCoordByteBuffer);
+            mCoordByteBuffer = null;
+            mCoordBuffer = null;
         } finally {
             super.finalize();
         }
     }
 
     void onSurfaceCreated(EGLConfig config) {
         checkMonitoringEnabled();
         createDefaultProgram();
--- a/mobile/android/base/gfx/RectUtils.java
+++ b/mobile/android/base/gfx/RectUtils.java
@@ -1,26 +1,28 @@
 /* -*- 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 org.mozilla.gecko.FloatUtils;
+import org.mozilla.gecko.util.FloatUtils;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 
 public final class RectUtils {
+    private RectUtils() {}
+
     public static Rect create(JSONObject json) {
         try {
             int x = json.getInt("x");
             int y = json.getInt("y");
             int width = json.getInt("width");
             int height = json.getInt("height");
             return new Rect(x, y, x + width, y + height);
         } catch (JSONException e) {
--- a/mobile/android/base/gfx/ScreenshotLayer.java
+++ b/mobile/android/base/gfx/ScreenshotLayer.java
@@ -1,16 +1,16 @@
 /* -*- 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 org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
 
 public class ScreenshotLayer extends SingleTileLayer {
@@ -63,17 +63,17 @@ public class ScreenshotLayer extends Sin
         ScreenshotLayer sl = create(bitmap);
         sl.reset();
         return sl;
     }
 
     public static ScreenshotLayer create(Bitmap bitmap) {
         IntSize size = new IntSize(bitmap.getWidth(), bitmap.getHeight());
         // allocate a buffer that can hold our max screenshot size
-        ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(SCREENSHOT_SIZE_LIMIT * BYTES_FOR_16BPP);
+        ByteBuffer buffer = DirectBufferAllocator.allocate(SCREENSHOT_SIZE_LIMIT * BYTES_FOR_16BPP);
         // construct the screenshot layer
         ScreenshotLayer sl =  new ScreenshotLayer(new ScreenshotImage(buffer, size.width, size.height, CairoImage.FORMAT_RGB16_565), size);
         // paint the passed in bitmap into the buffer
         try {
             sl.setBitmap(bitmap);
         } catch (IllegalArgumentException ex) {
             Log.e(LOGTAG, "error setting bitmap: ", ex);
         }
@@ -103,20 +103,18 @@ public class ScreenshotLayer extends Sin
             mBuffer = inBuffer;
             mSize = new IntSize(inWidth, inHeight);
             mFormat = inFormat;
         }
 
         @Override
         protected void finalize() throws Throwable {
             try {
-                if (mBuffer != null) {
-                    GeckoAppShell.freeDirectBuffer(mBuffer);
-                    mBuffer = null;
-                }
+                DirectBufferAllocator.free(mBuffer);
+                mBuffer = null;
             } finally {
                 super.finalize();
             }
         }
 
         void copyBuffer(ByteBuffer src, ByteBuffer dst, Rect rect, int stride) {
             int start = (rect.top * stride) + (rect.left * BYTES_FOR_16BPP);
             int end = ((rect.bottom - 1) * stride) + (rect.right * BYTES_FOR_16BPP);
--- a/mobile/android/base/gfx/ScrollbarLayer.java
+++ b/mobile/android/base/gfx/ScrollbarLayer.java
@@ -1,16 +1,16 @@
 /* -*- 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 org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 import org.mozilla.gecko.util.FloatUtils;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -125,17 +125,17 @@ public class ScrollbarLayer extends Tile
 
         mBitmap.copyPixelsToBuffer(buffer.asIntBuffer());
     }
 
     public static ScrollbarLayer create(LayerRenderer renderer, boolean vertical) {
         // just create an empty image for now, it will get drawn
         // on demand anyway
         int imageSize = IntSize.nextPowerOfTwo(BAR_SIZE);
-        ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(imageSize * imageSize * 4);
+        ByteBuffer buffer = DirectBufferAllocator.allocate(imageSize * imageSize * 4);
         CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize,
                                                   CairoImage.FORMAT_ARGB32);
         return new ScrollbarLayer(renderer, image, vertical, buffer);
     }
 
     private void createProgram() {
         int vertexShader = LayerRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                                                     LayerRenderer.DEFAULT_VERTEX_SHADER);
--- a/mobile/android/base/gfx/TextLayer.java
+++ b/mobile/android/base/gfx/TextLayer.java
@@ -1,16 +1,16 @@
 /* -*- 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 org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.DirectBufferAllocator;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Typeface;
 
 import java.nio.ByteBuffer;
@@ -29,17 +29,17 @@ public class TextLayer extends SingleTil
     private TextLayer(ByteBuffer buffer, BufferedCairoImage image, IntSize size, String text) {
         super(false, image);
         mBuffer = buffer;
         mSize = size;
         renderText(text);
     }
 
     public static TextLayer create(IntSize size, String text) {
-        ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(size.width * size.height * 4);
+        ByteBuffer buffer = DirectBufferAllocator.allocate(size.width * size.height * 4);
         BufferedCairoImage image = new BufferedCairoImage(buffer, size.width, size.height,
                                                           CairoImage.FORMAT_ARGB32);
         return new TextLayer(buffer, image, size, text);
     }
 
     public void setText(String text) {
         renderText(text);
         invalidate();
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/mozglue/DirectBufferAllocator.java
@@ -0,0 +1,50 @@
+/* -*- 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.mozglue;
+
+import java.nio.ByteBuffer;
+
+//
+// We must manually allocate direct buffers in JNI to work around a bug where Honeycomb's
+// ByteBuffer.allocateDirect() grossly overallocates the direct buffer size.
+// https://code.google.com/p/android/issues/detail?id=16941
+//
+
+public final class DirectBufferAllocator {
+    private DirectBufferAllocator() {}
+
+    public static ByteBuffer allocate(int size) {
+        if (size <= 0 || (size % 4) != 0) {
+            throw new IllegalArgumentException("Invalid size " + size);
+        }
+
+        ByteBuffer directBuffer = nativeAllocateDirectBuffer(size);
+        if (directBuffer == null) {
+            throw new OutOfMemoryError("allocateDirectBuffer() returned null");
+        } else if (!directBuffer.isDirect()) {
+            throw new AssertionError("allocateDirectBuffer() did not return a direct buffer");
+        }
+
+        return directBuffer;
+    }
+
+    public static ByteBuffer free(ByteBuffer buffer) {
+        if (buffer == null) {
+            return null;
+        }
+
+        if (!buffer.isDirect()) {
+            throw new IllegalArgumentException("buffer must be direct");
+        }
+
+        nativeFreeDirectBuffer(buffer);
+        return null;
+    }
+
+    // These JNI methods are implemented in mozglue/android/nsGeckoUtils.cpp.
+    private static native ByteBuffer nativeAllocateDirectBuffer(long size);
+    private static native void nativeFreeDirectBuffer(ByteBuffer buf);
+}
--- a/mozglue/android/nsGeckoUtils.cpp
+++ b/mozglue/android/nsGeckoUtils.cpp
@@ -15,39 +15,39 @@
 #include <fcntl.h>
 
 extern "C"
 __attribute__ ((visibility("default")))
 void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map)
 {
     const char* str;
-    // XXX: java doesn't give us true UTF8, we should figure out something 
+    // XXX: java doesn't give us true UTF8, we should figure out something
     // better to do here
     str = jenv->GetStringUTFChars(map, NULL);
     if (str == NULL)
         return;
     putenv(strdup(str));
     jenv->ReleaseStringUTFChars(map, str);
 }
 
 extern "C"
 __attribute__ ((visibility("default")))
 jobject JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *jenv, jclass, jlong size)
+Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeAllocateDirectBuffer(JNIEnv *jenv, jclass, jlong size)
 {
     jobject buffer = NULL;
     void* mem = malloc(size);
     if (mem) {
         buffer = jenv->NewDirectByteBuffer(mem, size);
         if (!buffer)
             free(mem);
     }
     return buffer;
 }
 
 extern "C"
 __attribute__ ((visibility("default")))
 void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_freeDirectBuffer(JNIEnv *jenv, jclass, jobject buf)
+Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeFreeDirectBuffer(JNIEnv *jenv, jclass, jobject buf)
 {
     free(jenv->GetDirectBufferAddress(buf));
 }