Bug 1322650 - Add GeckoSurfaceTexture, GeckoSurface and associated Android Service r=jchen

This allows us to allocate an Android SurfaceTexture in the compositor process as well
as an accompanying Surface. We can then transfer the Surface back to the content process
via binder, where it can be used for things like WebGL and video decoding.

Each SurfaceTexture/Surface pair has a unique handle. We use this handle in
layer transactions to locate the SurfaceTexture for a given Surface and composite it
appropriately.

MozReview-Commit-ID: 68VSbXdfsMH
This commit is contained in:
James Willcox 2017-03-03 15:02:53 -06:00
Родитель 17c14a6258
Коммит 5de9b3dc5f
12 изменённых файлов: 422 добавлений и 303 удалений

Просмотреть файл

@ -1,204 +1,20 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:set ts=2 sts=2 sw=2 et cin:
/* 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/. */
#ifdef MOZ_WIDGET_ANDROID
#include <map>
#include <android/native_window_jni.h>
#include <android/log.h>
#include "AndroidSurfaceTexture.h"
#include "gfxImageSurface.h"
#include "gfxPrefs.h"
#include "AndroidBridge.h"
#include "nsThreadUtils.h"
#include "mozilla/gfx/Matrix.h"
#include "GeneratedJNINatives.h"
#include "GLContext.h"
using namespace mozilla;
namespace mozilla {
namespace gl {
class AndroidSurfaceTexture::Listener
: public java::SurfaceTextureListener::Natives<Listener>
{
using Base = java::SurfaceTextureListener::Natives<Listener>;
const nsCOMPtr<nsIRunnable> mCallback;
public:
using Base::AttachNative;
using Base::DisposeNative;
Listener(nsIRunnable* aCallback) : mCallback(aCallback) {}
void OnFrameAvailable()
{
if (NS_IsMainThread()) {
mCallback->Run();
return;
}
NS_DispatchToMainThread(mCallback);
}
};
already_AddRefed<AndroidSurfaceTexture>
AndroidSurfaceTexture::Create()
{
return Create(nullptr, 0);
}
already_AddRefed<AndroidSurfaceTexture>
AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture)
{
RefPtr<AndroidSurfaceTexture> st = new AndroidSurfaceTexture();
if (!st->Init(aContext, aTexture)) {
printf_stderr("Failed to initialize AndroidSurfaceTexture");
st = nullptr;
}
return st.forget();
}
nsresult
AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout)
{
MonitorAutoLock lock(mMonitor);
if (mAttachedContext == aContext) {
NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture");
return NS_OK;
}
if (!CanDetach()) {
return NS_ERROR_NOT_AVAILABLE;
}
while (mAttachedContext) {
// Wait until it's detached (or we time out)
if (NS_FAILED(lock.Wait(aTimeout))) {
return NS_ERROR_NOT_AVAILABLE;
}
}
MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
aContext->fGenTextures(1, &mTexture);
if (NS_FAILED(mSurfaceTexture->AttachToGLContext(mTexture))) {
return NS_ERROR_NOT_AVAILABLE;
}
mAttachedContext = aContext;
mAttachedContext->MakeCurrent();
return NS_OK;
}
nsresult
AndroidSurfaceTexture::Detach()
{
MonitorAutoLock lock(mMonitor);
if (!CanDetach() ||
!mAttachedContext ||
!mAttachedContext->IsOwningThreadCurrent())
{
return NS_ERROR_FAILURE;
}
mAttachedContext->MakeCurrent();
mSurfaceTexture->DetachFromGLContext();
mTexture = 0;
mAttachedContext = nullptr;
lock.NotifyAll();
return NS_OK;
}
bool
AndroidSurfaceTexture::CanDetach() const
{
// The API for attach/detach only exists on 16+, and PowerVR has some sort of
// fencing issue. Additionally, attach/detach seems to be busted on at least
// some Mali adapters (400MP2 for sure, bug 1131793)
return AndroidBridge::Bridge()->GetAPIVersion() >= 16 &&
(!mAttachedContext || mAttachedContext->Vendor() != GLVendor::Imagination) &&
(!mAttachedContext || mAttachedContext->Vendor() != GLVendor::ARM /* Mali */) &&
gfxPrefs::SurfaceTextureDetachEnabled();
}
bool
AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
{
if (!aTexture && !CanDetach()) {
// We have no texture and cannot initialize detached, bail out
return false;
}
if (NS_WARN_IF(NS_FAILED(
java::sdk::SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
return false;
}
if (!aTexture) {
mSurfaceTexture->DetachFromGLContext();
}
mAttachedContext = aContext;
if (NS_WARN_IF(NS_FAILED(
java::sdk::Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
return false;
}
mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
mSurface.Get());
MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
return true;
}
AndroidSurfaceTexture::AndroidSurfaceTexture()
: mTexture(0)
, mSurfaceTexture()
, mSurface()
, mAttachedContext(nullptr)
, mMonitor("AndroidSurfaceTexture")
{
}
AndroidSurfaceTexture::~AndroidSurfaceTexture()
{
if (mSurfaceTexture) {
SetFrameAvailableCallback(nullptr);
mSurfaceTexture = nullptr;
}
if (mNativeWindow) {
ANativeWindow_release(mNativeWindow);
mNativeWindow = nullptr;
}
}
void
AndroidSurfaceTexture::UpdateTexImage()
{
mSurfaceTexture->UpdateTexImage();
}
void
AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) const
AndroidSurfaceTexture::GetTransformMatrix(java::sdk::SurfaceTexture::LocalRef aSurfaceTexture,
gfx::Matrix4x4& aMatrix)
{
JNIEnv* const env = jni::GetEnvForThread();
auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
mSurfaceTexture->GetTransformMatrix(jarray);
aSurfaceTexture->GetTransformMatrix(jarray);
jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
@ -225,36 +41,6 @@ AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) const
env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
}
void
AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
{
java::SurfaceTextureListener::LocalRef newListener;
if (aRunnable) {
newListener = java::SurfaceTextureListener::New();
Listener::AttachNative(newListener, MakeUnique<Listener>(aRunnable));
}
if (aRunnable || mListener) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mSurfaceTexture->SetOnFrameAvailableListener(newListener)));
}
if (mListener) {
Listener::DisposeNative(java::SurfaceTextureListener::LocalRef(
newListener.Env(), mListener));
}
mListener = newListener;
}
void
AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
{
mSurfaceTexture->SetDefaultBufferSize(size.width, size.height);
}
} // gl
} // mozilla
#endif // MOZ_WIDGET_ANDROID

Просмотреть файл

@ -8,100 +8,23 @@
#define AndroidSurfaceTexture_h__
#ifdef MOZ_WIDGET_ANDROID
#include <jni.h>
#include <android/native_window.h>
#include "nsIRunnable.h"
#include "gfxPlatform.h"
#include "GLDefs.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/MatrixFwd.h"
#include "mozilla/Monitor.h"
#include "GeneratedJNIWrappers.h"
#include "mozilla/gfx/Matrix.h"
#include "SurfaceTexture.h"
typedef uint32_t AndroidSurfaceTextureHandle;
namespace mozilla {
namespace gl {
class GLContext;
/**
* This class is a wrapper around Android's SurfaceTexture class.
* Usage is pretty much exactly like the Java class, so see
* the Android documentation for details.
*/
class AndroidSurfaceTexture {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidSurfaceTexture)
public:
static void GetTransformMatrix(java::sdk::SurfaceTexture::LocalRef aSurfaceTexture,
mozilla::gfx::Matrix4x4& aMatrix);
// The SurfaceTexture is created in an attached state. This method requires
// Android Ice Cream Sandwich.
static already_AddRefed<AndroidSurfaceTexture> Create(GLContext* aGLContext, GLuint aTexture);
// Here the SurfaceTexture will be created in a detached state. You must call
// Attach() with the GLContext you wish to composite with. It must be done
// on the thread where that GLContext is current. This method requires
// Android Jelly Bean.
static already_AddRefed<AndroidSurfaceTexture> Create();
// If we are on Jelly Bean, the SurfaceTexture can be detached and reattached
// to allow consumption from different GLContexts. It is recommended to only
// attach while you are consuming in order to allow this.
//
// Only one GLContext may be attached at any given time. If another is already
// attached, we try to wait for it to become detached.
nsresult Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT);
nsresult Detach();
// Ability to detach is based on API version (16+), and we also block PowerVR
// since it has some type of fencing problem. Bug 1100126.
bool CanDetach() const;
GLContext* AttachedContext() const { return mAttachedContext; }
ANativeWindow* NativeWindow() const {
return mNativeWindow;
}
// This attaches the updated data to the TEXTURE_EXTERNAL target
void UpdateTexImage();
void GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix) const;
void SetDefaultSize(mozilla::gfx::IntSize size);
// The callback is guaranteed to be called on the main thread even
// if the upstream callback is received on a different thread
void SetFrameAvailableCallback(nsIRunnable* aRunnable);
GLuint Texture() const { return mTexture; }
const java::sdk::Surface::Ref& JavaSurface() const { return mSurface; }
private:
class Listener;
AndroidSurfaceTexture();
~AndroidSurfaceTexture();
bool Init(GLContext* aContext, GLuint aTexture);
GLuint mTexture;
java::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
java::sdk::Surface::GlobalRef mSurface;
java::SurfaceTextureListener::GlobalRef mListener;
GLContext* mAttachedContext;
ANativeWindow* mNativeWindow;
Monitor mMonitor;
};
}
}
} // gl
} // mozilla
#endif
#endif
#endif // MOZ_WIDGET_ANDROID
#endif // AndroidSurfaceTexture_h__

Просмотреть файл

@ -473,5 +473,12 @@
android:isolatedProcess="false">
</service>
<service
android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
android:enabled="true"
android:exported="false"
android:isolatedProcess="false">
</service>
</application>
</manifest>

Просмотреть файл

@ -547,6 +547,7 @@ libs:: classes.dex
GECKOVIEW_AIDLS = \
org/mozilla/gecko/IGeckoEditableChild.aidl \
org/mozilla/gecko/IGeckoEditableParent.aidl \
org/mozilla/gecko/gfx/ISurfaceAllocator.aidl \
org/mozilla/gecko/media/ICodec.aidl \
org/mozilla/gecko/media/ICodecCallbacks.aidl \
org/mozilla/gecko/media/IMediaDrmBridge.aidl \

Просмотреть файл

@ -379,6 +379,8 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x
'gfx/FloatSize.java',
'gfx/FullScreenState.java',
'gfx/GeckoLayerClient.java',
'gfx/GeckoSurface.java',
'gfx/GeckoSurfaceTexture.java',
'gfx/ImmutableViewportMetrics.java',
'gfx/IntSize.java',
'gfx/LayerView.java',
@ -391,6 +393,8 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x
'gfx/RectUtils.java',
'gfx/RenderTask.java',
'gfx/StackScroller.java',
'gfx/SurfaceAllocator.java',
'gfx/SurfaceAllocatorService.java',
'gfx/SurfaceTextureListener.java',
'gfx/ViewTransform.java',
'gfx/VsyncSource.java',
@ -1262,6 +1266,7 @@ DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
FINAL_TARGET_PP_FILES += ['package-name.txt.in']
gvjar.sources += ['generated/org/mozilla/gecko/' + x for x in [
'gfx/ISurfaceAllocator.java',
'IGeckoEditableChild.java',
'IGeckoEditableParent.java',
'media/ICodec.java',

Просмотреть файл

@ -53,6 +53,13 @@
android:process=":tab"
android:isolatedProcess="false">
</service>
<service
android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
android:enabled="true"
android:exported="false"
android:isolatedProcess="false">
</service>
</application>
</manifest>

Просмотреть файл

@ -0,0 +1,7 @@
/* 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;
parcelable GeckoSurface;

Просмотреть файл

@ -0,0 +1,12 @@
/* 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.gfx.GeckoSurface;
interface ISurfaceAllocator {
GeckoSurface acquireSurface(in int width, in int height, in boolean singleBufferMode);
void releaseSurface(in int handle);
}

Просмотреть файл

@ -0,0 +1,83 @@
/* -*- 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.graphics.SurfaceTexture;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
import android.util.Log;
import java.util.HashMap;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.AppConstants.Versions;
public final class GeckoSurface extends Surface {
private static final String LOGTAG = "GeckoSurface";
private static HashMap<Integer, GeckoSurfaceTexture> sSurfaceTextures = new HashMap<Integer, GeckoSurfaceTexture>();
private int mHandle;
private boolean mIsSingleBuffer;
private volatile boolean mIsAvailable;
@WrapForJNI(exceptionMode = "nsresult")
public GeckoSurface(GeckoSurfaceTexture gst) {
super(gst);
mHandle = gst.getHandle();
mIsSingleBuffer = gst.isSingleBuffer();
mIsAvailable = true;
}
public GeckoSurface(Parcel p, SurfaceTexture dummy) {
// A no-arg constructor exists, but is hidden in the SDK. We need to create a dummy
// SurfaceTexture here in order to create the instance. This is used to transfer the
// GeckoSurface across binder.
super(dummy);
readFromParcel(p);
mHandle = p.readInt();
mIsSingleBuffer = p.readByte() == 1 ? true : false;
mIsAvailable = (p.readByte() == 1 ? true : false);
dummy.release();
}
public static final Parcelable.Creator<GeckoSurface> CREATOR = new Parcelable.Creator<GeckoSurface>() {
public GeckoSurface createFromParcel(Parcel p) {
return new GeckoSurface(p, new SurfaceTexture(0));
}
public GeckoSurface[] newArray(int size) {
return new GeckoSurface[size];
}
};
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(mHandle);
out.writeByte((byte) (mIsSingleBuffer ? 1 : 0));
out.writeByte((byte) (mIsAvailable ? 1 : 0));
}
@WrapForJNI
public int getHandle() {
return mHandle;
}
@WrapForJNI
public boolean getAvailable() {
return mIsAvailable;
}
@WrapForJNI
public void setAvailable(boolean available) {
mIsAvailable = available;
}
}

Просмотреть файл

@ -0,0 +1,140 @@
/* -*- 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.graphics.SurfaceTexture;
import android.util.Log;
import java.util.HashMap;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.AppConstants.Versions;
public final class GeckoSurfaceTexture extends SurfaceTexture {
private static final String LOGTAG = "GeckoSurfaceTexture";
private static volatile int sNextHandle = 1;
private static HashMap<Integer, GeckoSurfaceTexture> sSurfaceTextures = new HashMap<Integer, GeckoSurfaceTexture>();
private int mHandle;
private boolean mIsSingleBuffer;
private int mTexName;
private GeckoSurfaceTexture.Callbacks mListener;
@WrapForJNI(dispatchTo = "current")
private static native int nativeAcquireTexture();
private GeckoSurfaceTexture(int handle, int texName) {
super(texName);
mHandle = handle;
mIsSingleBuffer = false;
mTexName = texName;
}
private GeckoSurfaceTexture(int handle, int texName, boolean singleBufferMode) {
super(texName, singleBufferMode);
mHandle = handle;
mIsSingleBuffer = singleBufferMode;
mTexName = texName;
}
@WrapForJNI
public int getHandle() {
return mHandle;
}
@WrapForJNI
public int getTexName() {
return mTexName;
}
@WrapForJNI
public boolean isSingleBuffer() {
return mIsSingleBuffer;
}
@Override
@WrapForJNI
public synchronized void updateTexImage() {
super.updateTexImage();
if (mListener != null) {
mListener.onUpdateTexImage();
}
}
@Override
@WrapForJNI
public synchronized void releaseTexImage() {
if (!mIsSingleBuffer) {
return;
}
super.releaseTexImage();
if (mListener != null) {
mListener.onReleaseTexImage();
}
}
public synchronized void setListener(GeckoSurfaceTexture.Callbacks listener) {
mListener = listener;
}
@WrapForJNI
public static boolean isSingleBufferSupported() {
return Versions.feature19Plus;
}
public static GeckoSurfaceTexture acquire(boolean singleBufferMode) {
if (singleBufferMode && !isSingleBufferSupported()) {
throw new IllegalArgumentException("single buffer mode not supported on API version < 19");
}
int handle = sNextHandle++;
int texName = nativeAcquireTexture();
final GeckoSurfaceTexture gst;
if (isSingleBufferSupported()) {
gst = new GeckoSurfaceTexture(handle, texName, singleBufferMode);
} else {
gst = new GeckoSurfaceTexture(handle, texName);
}
synchronized (sSurfaceTextures) {
if (sSurfaceTextures.containsKey(handle)) {
gst.release();
throw new IllegalArgumentException("Already have a GeckoSurfaceTexture with that handle");
}
sSurfaceTextures.put(handle, gst);
}
return gst;
}
public static void dispose(int handle) {
final GeckoSurfaceTexture gst;
synchronized (sSurfaceTextures) {
gst = sSurfaceTextures.remove(handle);
}
if (gst != null) {
gst.setListener(null);
gst.release();
}
}
@WrapForJNI
public static GeckoSurfaceTexture lookup(int handle) {
synchronized (sSurfaceTextures) {
return sSurfaceTextures.get(handle);
}
}
public interface Callbacks {
void onUpdateTexImage();
void onReleaseTexImage();
}
}

Просмотреть файл

@ -0,0 +1,103 @@
/* -*- 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.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.SurfaceTexture;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.GeckoAppShell;
public final class SurfaceAllocator {
private static final String LOGTAG = "SurfaceAllocator";
private static SurfaceAllocatorConnection sConnection;
private static synchronized void ensureConnection() throws Exception {
if (sConnection != null) {
return;
}
sConnection = new SurfaceAllocatorConnection();
Intent intent = new Intent();
intent.setClassName(GeckoAppShell.getApplicationContext(),
"org.mozilla.gecko.gfx.SurfaceAllocatorService");
// FIXME: may not want to auto create
if (!GeckoAppShell.getApplicationContext().bindService(intent, sConnection, Context.BIND_AUTO_CREATE)) {
throw new Exception("Failed to connect to surface allocator service!");
}
}
@WrapForJNI
public static GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) throws Exception {
ensureConnection();
try {
return sConnection.getAllocator().acquireSurface(width, height, singleBufferMode);
} catch (RemoteException e) {
throw new Exception("Failed to acquire GeckoSurface", e);
}
}
@WrapForJNI
public static void disposeSurface(GeckoSurface surface) {
try {
ensureConnection();
} catch (Exception e) {
Log.w(LOGTAG, "Failed to dispose surface, no connection");
return;
}
// Release the SurfaceTexture on the other side
try {
sConnection.getAllocator().releaseSurface(surface.getHandle());
} catch (RemoteException e) {
Log.w(LOGTAG, "Failed to release surface texture", e);
}
// And now our Surface
try {
surface.release();
} catch (Exception e) {
Log.w(LOGTAG, "Failed to release surface", e);
}
}
private static final class SurfaceAllocatorConnection implements ServiceConnection {
private ISurfaceAllocator mAllocator;
public synchronized ISurfaceAllocator getAllocator() {
while (mAllocator == null) {
try {
this.wait();
} catch (InterruptedException e) { }
}
return mAllocator;
}
@Override
public synchronized void onServiceConnected(ComponentName name, IBinder service) {
mAllocator = ISurfaceAllocator.Stub.asInterface(service);
this.notifyAll();
}
@Override
public synchronized void onServiceDisconnected(ComponentName name) {
mAllocator = null;
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class SurfaceAllocatorService extends Service {
static private String LOGTAG = "SurfaceAllocatorService";
public int onStartCommand(final Intent intent, final int flags, final int startId) {
return Service.START_STICKY;
}
private Binder mBinder = new ISurfaceAllocator.Stub() {
public GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) {
GeckoSurfaceTexture gst = GeckoSurfaceTexture.acquire(singleBufferMode);
if (width > 0 && height > 0) {
gst.setDefaultBufferSize(width, height);
}
return new GeckoSurface(gst);
}
public void releaseSurface(int handle) {
GeckoSurfaceTexture.dispose(handle);
}
};
public IBinder onBind(final Intent intent) {
return mBinder;
}
public boolean onUnbind(Intent intent) {
return false;
}
}