blob: 77757e99ec92d4f5d6b5438292aaf887cb96a89e [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/common/android/surface_callback.h"
#include <android/native_window_jni.h>
#include "base/android/jni_android.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "ui/gl/android_native_window.h"
#include "jni/SurfaceCallback_jni.h"
using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::GetMethodID;
using base::WaitableEvent;
using content::SurfaceTexturePeer;
namespace content {
namespace {
struct GlobalState {
base::Lock registration_lock;
// We hold a reference to a message loop proxy which handles message loop
// destruction gracefully, which is important since we post tasks from an
// arbitrary binder thread while the main thread might be shutting down.
// Also, in single-process mode we have two ChildThread objects for render
// and gpu thread, so we need to store the msg loops separately.
scoped_refptr<base::MessageLoopProxy> native_window_loop;
scoped_refptr<base::MessageLoopProxy> video_surface_loop;
NativeWindowCallback native_window_callback;
VideoSurfaceCallback video_surface_callback;
};
base::LazyInstance<GlobalState>::Leaky g_state = LAZY_INSTANCE_INITIALIZER;
void RunNativeWindowCallback(int32 routing_id,
int32 renderer_id,
ANativeWindow* native_window,
WaitableEvent* completion) {
g_state.Pointer()->native_window_callback.Run(
routing_id, renderer_id, native_window, completion);
}
void RunVideoSurfaceCallback(int32 routing_id,
int32 renderer_id,
jobject surface) {
g_state.Pointer()->video_surface_callback.Run(
routing_id, renderer_id, surface);
}
} // namespace <anonymous>
static void SetSurface(JNIEnv* env, jclass clazz,
jint type,
jobject surface,
jint primaryID,
jint secondaryID) {
SetSurfaceAsync(env, surface,
static_cast<SurfaceTexturePeer::SurfaceTextureTarget>(type),
primaryID, secondaryID, NULL);
}
void ReleaseSurface(jobject surface) {
if (surface == NULL)
return;
JNIEnv* env = AttachCurrentThread();
CHECK(env);
jclass cls = env->FindClass("android/view/Surface");
DCHECK(cls);
jmethodID method = env->GetMethodID(cls, "release", "()V");
DCHECK(method);
env->CallVoidMethod(surface, method);
DCHECK(env);
env->DeleteLocalRef(cls);
}
void SetSurfaceAsync(JNIEnv* env,
jobject jsurface,
SurfaceTexturePeer::SurfaceTextureTarget type,
int primary_id,
int secondary_id,
WaitableEvent* completion) {
base::AutoLock lock(g_state.Pointer()->registration_lock);
ANativeWindow* native_window = NULL;
if (jsurface &&
type != SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE) {
native_window = ANativeWindow_fromSurface(env, jsurface);
ReleaseSurface(jsurface);
}
GlobalState* const global_state = g_state.Pointer();
switch (type) {
case SurfaceTexturePeer::SET_GPU_SURFACE_TEXTURE: {
// This should only be sent as a reaction to the renderer
// activating compositing. If the GPU process crashes, we expect this
// to be resent after the new thread is initialized.
DCHECK(global_state->native_window_loop);
global_state->native_window_loop->PostTask(
FROM_HERE,
base::Bind(&RunNativeWindowCallback,
primary_id,
static_cast<uint32_t>(secondary_id),
native_window,
completion));
// ANativeWindow_release will be called in SetNativeWindow()
break;
}
case SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE: {
jobject surface = env->NewGlobalRef(jsurface);
DCHECK(global_state->video_surface_loop);
global_state->video_surface_loop->PostTask(
FROM_HERE,
base::Bind(&RunVideoSurfaceCallback,
primary_id,
secondary_id,
surface));
break;
}
}
}
void RegisterVideoSurfaceCallback(base::MessageLoopProxy* loop,
VideoSurfaceCallback& callback) {
GlobalState* const global_state = g_state.Pointer();
base::AutoLock lock(global_state->registration_lock);
global_state->video_surface_loop = loop;
global_state->video_surface_callback = callback;
}
void RegisterNativeWindowCallback(base::MessageLoopProxy* loop,
NativeWindowCallback& callback) {
GlobalState* const global_state = g_state.Pointer();
base::AutoLock lock(global_state->registration_lock);
global_state->native_window_loop = loop;
global_state->native_window_callback = callback;
}
bool RegisterSurfaceCallback(JNIEnv* env) {
return RegisterNativesImpl(env);
}
} // namespace content