JavaBridge.cpp revision 528e2187562372a650037bc65fc4446ac2ff0772
1/* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_TAG "webcoreglue" 27 28#include <config.h> 29#include <wtf/Platform.h> 30 31#include "Cache.h" 32#include "CookieClient.h" 33#include "JavaSharedClient.h" 34#include "KURL.h" 35#include "NetworkStateNotifier.h" 36#include "Timer.h" 37#include "TimerClient.h" 38#include "jni_utility.h" 39#include "WebCoreJni.h" 40 41#ifdef ANDROID_INSTRUMENT 42#include "TimeCounter.h" 43#endif 44 45#include <jni.h> 46#include <JNIHelp.h> 47#include <SkImageRef_GlobalPool.h> 48#include <SkUtils.h> 49#include <utils/misc.h> 50 51// maximum bytes used to cache decoded images 52// (not including big images using ashmem) 53#define IMAGE_POOL_BUDGET (512 * 1024) 54 55namespace android { 56 57// ---------------------------------------------------------------------------- 58 59static jfieldID gJavaBridge_ObjectID; 60 61// ---------------------------------------------------------------------------- 62 63class JavaBridge : public TimerClient, public CookieClient 64{ 65public: 66 JavaBridge(JNIEnv* env, jobject obj); 67 virtual ~JavaBridge(); 68 69 /* 70 * WebCore -> Java API 71 */ 72 virtual void setSharedTimer(long long timemillis); 73 virtual void stopSharedTimer(); 74 75 virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value); 76 virtual WebCore::String cookies(WebCore::KURL const& url); 77 virtual bool cookiesEnabled(); 78 79 //////////////////////////////////////////// 80 81 virtual void setSharedTimerCallback(void (*f)()); 82 83 //////////////////////////////////////////// 84 85 void signalServiceFuncPtrQueue(); 86 87 // jni functions 88 static void Constructor(JNIEnv* env, jobject obj); 89 static void Finalize(JNIEnv* env, jobject obj); 90 static void SharedTimerFired(JNIEnv* env, jobject); 91 static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes); 92 static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online); 93 static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer); 94 static void ServiceFuncPtrQueue(JNIEnv*); 95 96private: 97 jobject mJavaObject; 98 jmethodID mSetSharedTimer; 99 jmethodID mStopSharedTimer; 100 jmethodID mSetCookies; 101 jmethodID mCookies; 102 jmethodID mCookiesEnabled; 103 jmethodID mSignalFuncPtrQueue; 104}; 105 106static void (*sSharedTimerFiredCallback)(); 107static JavaBridge* gJavaBridge; 108 109JavaBridge::JavaBridge(JNIEnv* env, jobject obj) 110{ 111 mJavaObject = adoptGlobalRef(env, obj); 112 jclass clazz = env->GetObjectClass(obj); 113 114 mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V"); 115 mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V"); 116 mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 117 mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;"); 118 mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z"); 119 mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V"); 120 121 LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer"); 122 LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer"); 123 LOG_ASSERT(mSetCookies, "Could not find method setCookies"); 124 LOG_ASSERT(mCookies, "Could not find method cookies"); 125 LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled"); 126 127 JavaSharedClient::SetTimerClient(this); 128 JavaSharedClient::SetCookieClient(this); 129 gJavaBridge = this; 130} 131 132JavaBridge::~JavaBridge() 133{ 134 if (mJavaObject) { 135 JNIEnv* env = JSC::Bindings::getJNIEnv(); 136 env->DeleteGlobalRef(mJavaObject); 137 mJavaObject = 0; 138 } 139 140 JavaSharedClient::SetTimerClient(NULL); 141 JavaSharedClient::SetCookieClient(NULL); 142} 143 144void 145JavaBridge::setSharedTimer(long long timemillis) 146{ 147 JNIEnv* env = JSC::Bindings::getJNIEnv(); 148 AutoJObject obj = getRealObject(env, mJavaObject); 149 env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis); 150} 151 152void 153JavaBridge::stopSharedTimer() 154{ 155 JNIEnv* env = JSC::Bindings::getJNIEnv(); 156 AutoJObject obj = getRealObject(env, mJavaObject); 157 env->CallVoidMethod(obj.get(), mStopSharedTimer); 158} 159 160void 161JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value) 162{ 163 JNIEnv* env = JSC::Bindings::getJNIEnv(); 164 const WebCore::String& urlStr = url.string(); 165 jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length()); 166 const WebCore::String& docUrlStr = docUrl.string(); 167 jstring jDocUrlStr = env->NewString(docUrlStr.characters(), docUrlStr.length()); 168 jstring jValueStr = env->NewString(value.characters(), value.length()); 169 170 AutoJObject obj = getRealObject(env, mJavaObject); 171 env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jDocUrlStr, jValueStr); 172 env->DeleteLocalRef(jUrlStr); 173 env->DeleteLocalRef(jDocUrlStr); 174 env->DeleteLocalRef(jValueStr); 175} 176 177WebCore::String 178JavaBridge::cookies(WebCore::KURL const& url) 179{ 180 JNIEnv* env = JSC::Bindings::getJNIEnv(); 181 const WebCore::String& urlStr = url.string(); 182 jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length()); 183 184 AutoJObject obj = getRealObject(env, mJavaObject); 185 jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr)); 186 187 WebCore::String ret = to_string(env, string); 188 env->DeleteLocalRef(jUrlStr); 189 env->DeleteLocalRef(string); 190 return ret; 191} 192 193bool 194JavaBridge::cookiesEnabled() 195{ 196 JNIEnv* env = JSC::Bindings::getJNIEnv(); 197 AutoJObject obj = getRealObject(env, mJavaObject); 198 jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled); 199 return (ret != 0); 200} 201 202void 203JavaBridge::setSharedTimerCallback(void (*f)()) 204{ 205 LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f, 206 "Shared timer callback may already be set or null!"); 207 208 sSharedTimerFiredCallback = f; 209} 210 211void JavaBridge::signalServiceFuncPtrQueue() 212{ 213 // In order to signal the main thread we must go through JNI. This 214 // is the only usage on most threads, so we need to ensure a JNI 215 // environment is setup. 216 JNIEnv* env = JSC::Bindings::getJNIEnv(); 217 AutoJObject obj = getRealObject(env, mJavaObject); 218 env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue); 219} 220 221// ---------------------------------------------------------------------------- 222 223// visible to Shared 224void AndroidSignalServiceFuncPtrQueue() 225{ 226 gJavaBridge->signalServiceFuncPtrQueue(); 227} 228 229// ---------------------------------------------------------------------------- 230 231void JavaBridge::Constructor(JNIEnv* env, jobject obj) 232{ 233 JavaBridge* javaBridge = new JavaBridge(env, obj); 234 env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge); 235} 236 237void JavaBridge::Finalize(JNIEnv* env, jobject obj) 238{ 239 JavaBridge* javaBridge = (JavaBridge*) 240 (env->GetIntField(obj, gJavaBridge_ObjectID)); 241 LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!"); 242 LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge); 243 delete javaBridge; 244 env->SetIntField(obj, gJavaBridge_ObjectID, 0); 245} 246 247// we don't use the java bridge object, as we're just looking at a global 248void JavaBridge::SharedTimerFired(JNIEnv* env, jobject) 249{ 250 if (sSharedTimerFiredCallback) 251 { 252#ifdef ANDROID_INSTRUMENT 253 TimeCounter::start(TimeCounter::SharedTimerTimeCounter); 254#endif 255 SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired"); 256 sSharedTimerFiredCallback(); 257#ifdef ANDROID_INSTRUMENT 258 TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__); 259#endif 260 } 261} 262 263void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes) 264{ 265 WebCore::cache()->setCapacities(0, bytes/2, bytes); 266 SkImageRef_GlobalPool::SetRAMBudget(IMAGE_POOL_BUDGET); 267 LOGV("--- set ImageRef budget %d\n", SkImageRef_GlobalPool::GetRAMBudget()); 268} 269 270void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online) 271{ 272 WebCore::networkStateNotifier().networkStateChange(online); 273} 274 275void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer) 276{ 277 WebCore::setDeferringTimers(defer); 278} 279 280void JavaBridge::ServiceFuncPtrQueue(JNIEnv*) 281{ 282 JavaSharedClient::ServiceFunctionPtrQueue(); 283} 284 285// ---------------------------------------------------------------------------- 286 287/* 288 * JNI registration. 289 */ 290static JNINativeMethod gWebCoreJavaBridgeMethods[] = { 291 /* name, signature, funcPtr */ 292 { "nativeConstructor", "()V", 293 (void*) JavaBridge::Constructor }, 294 { "nativeFinalize", "()V", 295 (void*) JavaBridge::Finalize }, 296 { "sharedTimerFired", "()V", 297 (void*) JavaBridge::SharedTimerFired }, 298 { "setCacheSize", "(I)V", 299 (void*) JavaBridge::SetCacheSize }, 300 { "setNetworkOnLine", "(Z)V", 301 (void*) JavaBridge::SetNetworkOnLine }, 302 { "setDeferringTimers", "(Z)V", 303 (void*) JavaBridge::SetDeferringTimers }, 304 { "nativeServiceFuncPtrQueue", "()V", 305 (void*) JavaBridge::ServiceFuncPtrQueue }, 306}; 307 308int register_javabridge(JNIEnv* env) 309{ 310 jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge"); 311 LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge"); 312 gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I"); 313 LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge"); 314 315 return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge", 316 gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods)); 317} 318 319} /* namespace android */ 320