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