blob: 27b2bb2092121c7eccd504ab6e0754d32cfde8ed [file] [log] [blame]
/*
** Copyright 2006-2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#define LOG_TAG "webcoreglue"
#include <config.h>
#include <wtf/Platform.h>
#include "Cache.h"
#include "CookieClient.h"
#include "JavaSharedClient.h"
#include "KURL.h"
#include "Timer.h"
#include "TimerClient.h"
#ifdef ANDROID_INSTRUMENT
#include "Frame.h"
#include "SystemTime.h"
#endif
#undef LOG
#include <jni.h>
#include <JNIHelp.h>
#include <SkImageRef_GlobalPool.h>
#include <SkUtils.h>
#include <utils/Log.h>
#include <utils/misc.h>
// maximum bytes used to cache decoded images
// (not including big images using ashmem)
#define IMAGE_POOL_BUDGET (512 * 1024)
#ifdef ANDROID_INSTRUMENT
static uint32_t sTotalTimeUsed = 0;
namespace WebCore {
void Frame::resetSharedTimerTimeCounter()
{
sTotalTimeUsed = 0;
}
void Frame::reportSharedTimerTimeCounter()
{
LOG(LOG_DEBUG, "WebCore", "*-* Total native 2 (shared timer) time: %d ms\n",
sTotalTimeUsed);
}
}
#endif
namespace android {
// ----------------------------------------------------------------------------
static jfieldID gJavaBridge_ObjectID;
static bool checkException(JNIEnv* env)
{
if (env->ExceptionCheck() != 0)
{
LOGE("*** Uncaught exception returned from Java call!\n");
env->ExceptionDescribe();
return true;
}
return false;
}
// ----------------------------------------------------------------------------
extern JavaVM* jnienv_to_javavm(JNIEnv* env);
extern JNIEnv* javavm_to_jnienv(JavaVM* vm);
// ----------------------------------------------------------------------------
class JavaBridge : public WebCore::TimerClient, public WebCore::CookieClient
{
public:
JavaBridge(JNIEnv* env, jobject obj);
virtual ~JavaBridge();
/*
* WebCore -> Java API
*/
virtual void setSharedTimer(long long timemillis);
virtual void stopSharedTimer();
virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value);
virtual WebCore::String cookies(WebCore::KURL const& url);
virtual bool cookiesEnabled();
////////////////////////////////////////////
virtual void setSharedTimerCallback(void (*f)());
////////////////////////////////////////////
void signalServiceFuncPtrQueue();
// jni functions
static void Constructor(JNIEnv* env, jobject obj);
static void Finalize(JNIEnv* env, jobject obj);
static void SharedTimerFired(JNIEnv* env, jobject);
static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
static void ServiceFuncPtrQueue(JNIEnv*);
private:
JavaVM* mJvm;
jobject mJavaObject;
jmethodID mSetSharedTimer;
jmethodID mStopSharedTimer;
jmethodID mSetCookies;
jmethodID mCookies;
jmethodID mCookiesEnabled;
jmethodID mSignalFuncPtrQueue;
};
static void (*sSharedTimerFiredCallback)();
static JavaBridge* gJavaBridge;
JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
{
mJvm = jnienv_to_javavm(env);
mJavaObject = env->NewGlobalRef(obj);
jclass clazz = env->GetObjectClass(obj);
mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
LOG_ASSERT(mSetCookies, "Could not find method setCookies");
LOG_ASSERT(mCookies, "Could not find method cookies");
LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
WebCore::JavaSharedClient::SetTimerClient(this);
WebCore::JavaSharedClient::SetCookieClient(this);
gJavaBridge = this;
}
JavaBridge::~JavaBridge()
{
if (mJavaObject) {
JNIEnv* env = javavm_to_jnienv(mJvm);
env->DeleteGlobalRef(mJavaObject);
mJavaObject = 0;
}
WebCore::JavaSharedClient::SetTimerClient(NULL);
WebCore::JavaSharedClient::SetCookieClient(NULL);
}
void
JavaBridge::setSharedTimer(long long timemillis)
{
JNIEnv* env = javavm_to_jnienv(mJvm);
env->CallVoidMethod(mJavaObject, mSetSharedTimer, timemillis);
}
void
JavaBridge::stopSharedTimer()
{
JNIEnv* env = javavm_to_jnienv(mJvm);
env->CallVoidMethod(mJavaObject, mStopSharedTimer);
}
void
JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value)
{
JNIEnv* env = javavm_to_jnienv(mJvm);
const WebCore::DeprecatedString& urlStr = url.deprecatedString();
jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
const WebCore::DeprecatedString& docUrlStr = docUrl.deprecatedString();
jstring jDocUrlStr = env->NewString((unsigned short *)docUrlStr.unicode(), docUrlStr.length());
jstring jValueStr = env->NewString((unsigned short *)value.characters(), value.length());
env->CallVoidMethod(mJavaObject, mSetCookies, jUrlStr, jDocUrlStr, jValueStr);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(jDocUrlStr);
env->DeleteLocalRef(jValueStr);
}
WebCore::String
JavaBridge::cookies(WebCore::KURL const& url)
{
JNIEnv* env = javavm_to_jnienv(mJvm);
const WebCore::DeprecatedString& urlStr = url.deprecatedString();
jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
jstring string = (jstring)(env->CallObjectMethod(mJavaObject, mCookies, jUrlStr));
if (string == NULL || checkException(env))
return WebCore::String();
const jchar* str = env->GetStringChars(string, NULL);
WebCore::String ret = WebCore::String((const UChar*)str, env->GetStringLength(string));
env->ReleaseStringChars(string, str);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(string);
return ret;
}
bool
JavaBridge::cookiesEnabled()
{
JNIEnv* env = javavm_to_jnienv(mJvm);
jboolean ret = env->CallBooleanMethod(mJavaObject, mCookiesEnabled);
return (ret != 0);
}
void
JavaBridge::setSharedTimerCallback(void (*f)())
{
LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
"Shared timer callback may already be set or null!");
sSharedTimerFiredCallback = f;
}
void JavaBridge::signalServiceFuncPtrQueue()
{
javavm_to_jnienv(mJvm)->CallVoidMethod(mJavaObject, mSignalFuncPtrQueue);
}
// ----------------------------------------------------------------------------
// visible to Shared
void AndroidSignalServiceFuncPtrQueue()
{
gJavaBridge->signalServiceFuncPtrQueue();
}
// ----------------------------------------------------------------------------
void JavaBridge::Constructor(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = new JavaBridge(env, obj);
env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
}
void JavaBridge::Finalize(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = (JavaBridge*)
(env->GetIntField(obj, gJavaBridge_ObjectID));
LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
delete javaBridge;
env->SetIntField(obj, gJavaBridge_ObjectID, 0);
}
// we don't use the java bridge object, as we're just looking at a global
void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
{
if (sSharedTimerFiredCallback)
{
#ifdef ANDROID_INSTRUMENT
uint32_t startTime = WebCore::get_thread_msec();
#endif
SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
sSharedTimerFiredCallback();
#ifdef ANDROID_INSTRUMENT
sTotalTimeUsed += WebCore::get_thread_msec() - startTime;
#endif
}
}
void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
{
WebCore::cache()->setCapacities(0, bytes/2, bytes);
SkImageRef_GlobalPool::SetRAMBudget(IMAGE_POOL_BUDGET);
LOGV("--- set ImageRef budget %d\n", SkImageRef_GlobalPool::GetRAMBudget());
}
void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer)
{
WebCore::setDeferringTimers(defer);
}
void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
{
WebCore::JavaSharedClient::ServiceFunctionPtrQueue();
}
// ----------------------------------------------------------------------------
/*
* JNI registration.
*/
static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
/* name, signature, funcPtr */
{ "nativeConstructor", "()V",
(void*) JavaBridge::Constructor },
{ "nativeFinalize", "()V",
(void*) JavaBridge::Finalize },
{ "sharedTimerFired", "()V",
(void*) JavaBridge::SharedTimerFired },
{ "setCacheSize", "(I)V",
(void*) JavaBridge::SetCacheSize },
{ "setDeferringTimers", "(Z)V",
(void*) JavaBridge::SetDeferringTimers },
{ "nativeServiceFuncPtrQueue", "()V",
(void*) JavaBridge::ServiceFuncPtrQueue },
};
int register_javabridge(JNIEnv* env)
{
jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
}
} /* namespace android */