JavaBridge.cpp revision 21afc171e6a91d82acfe777acd1531d0105e458d
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 <SkUtils.h>
48#include <utils/misc.h>
49
50namespace android {
51
52// ----------------------------------------------------------------------------
53
54static jfieldID gJavaBridge_ObjectID;
55
56// ----------------------------------------------------------------------------
57
58class JavaBridge : public TimerClient, public CookieClient
59{
60public:
61    JavaBridge(JNIEnv* env, jobject obj);
62    virtual ~JavaBridge();
63
64    /*
65     * WebCore -> Java API
66     */
67    virtual void setSharedTimer(long long timemillis);
68    virtual void stopSharedTimer();
69
70    virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value);
71    virtual WebCore::String cookies(WebCore::KURL const& url);
72    virtual bool cookiesEnabled();
73
74    ////////////////////////////////////////////
75
76    virtual void setSharedTimerCallback(void (*f)());
77
78    ////////////////////////////////////////////
79
80    void signalServiceFuncPtrQueue();
81
82    // jni functions
83    static void Constructor(JNIEnv* env, jobject obj);
84    static void Finalize(JNIEnv* env, jobject obj);
85    static void SharedTimerFired(JNIEnv* env, jobject);
86    static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
87    static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online);
88    static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
89    static void ServiceFuncPtrQueue(JNIEnv*);
90
91private:
92    jobject     mJavaObject;
93    jmethodID   mSetSharedTimer;
94    jmethodID   mStopSharedTimer;
95    jmethodID   mSetCookies;
96    jmethodID   mCookies;
97    jmethodID   mCookiesEnabled;
98    jmethodID   mSignalFuncPtrQueue;
99};
100
101static void (*sSharedTimerFiredCallback)();
102static JavaBridge* gJavaBridge;
103
104JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
105{
106    mJavaObject = adoptGlobalRef(env, obj);
107    jclass clazz = env->GetObjectClass(obj);
108
109    mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
110    mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
111    mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
112    mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
113    mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
114    mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
115
116    LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
117    LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
118    LOG_ASSERT(mSetCookies, "Could not find method setCookies");
119    LOG_ASSERT(mCookies, "Could not find method cookies");
120    LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
121
122    JavaSharedClient::SetTimerClient(this);
123    JavaSharedClient::SetCookieClient(this);
124    gJavaBridge = this;
125}
126
127JavaBridge::~JavaBridge()
128{
129    if (mJavaObject) {
130        JNIEnv* env = JSC::Bindings::getJNIEnv();
131        env->DeleteGlobalRef(mJavaObject);
132        mJavaObject = 0;
133    }
134
135    JavaSharedClient::SetTimerClient(NULL);
136    JavaSharedClient::SetCookieClient(NULL);
137}
138
139void
140JavaBridge::setSharedTimer(long long timemillis)
141{
142    JNIEnv* env = JSC::Bindings::getJNIEnv();
143    AutoJObject obj = getRealObject(env, mJavaObject);
144    env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
145}
146
147void
148JavaBridge::stopSharedTimer()
149{
150    JNIEnv* env = JSC::Bindings::getJNIEnv();
151    AutoJObject obj = getRealObject(env, mJavaObject);
152    env->CallVoidMethod(obj.get(), mStopSharedTimer);
153}
154
155void
156JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value)
157{
158    JNIEnv* env = JSC::Bindings::getJNIEnv();
159    const WebCore::String& urlStr = url.string();
160    jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
161    const WebCore::String& docUrlStr = docUrl.string();
162    jstring jDocUrlStr = env->NewString(docUrlStr.characters(), docUrlStr.length());
163    jstring jValueStr = env->NewString(value.characters(), value.length());
164
165    AutoJObject obj = getRealObject(env, mJavaObject);
166    env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jDocUrlStr, jValueStr);
167    env->DeleteLocalRef(jUrlStr);
168    env->DeleteLocalRef(jDocUrlStr);
169    env->DeleteLocalRef(jValueStr);
170}
171
172WebCore::String
173JavaBridge::cookies(WebCore::KURL const& url)
174{
175    JNIEnv* env = JSC::Bindings::getJNIEnv();
176    const WebCore::String& urlStr = url.string();
177    jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
178
179    AutoJObject obj = getRealObject(env, mJavaObject);
180    jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr));
181
182    WebCore::String ret = to_string(env, string);
183    env->DeleteLocalRef(jUrlStr);
184    env->DeleteLocalRef(string);
185    return ret;
186}
187
188bool
189JavaBridge::cookiesEnabled()
190{
191    JNIEnv* env = JSC::Bindings::getJNIEnv();
192    AutoJObject obj = getRealObject(env, mJavaObject);
193    jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled);
194    return (ret != 0);
195}
196
197void
198JavaBridge::setSharedTimerCallback(void (*f)())
199{
200    LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
201               "Shared timer callback may already be set or null!");
202
203    sSharedTimerFiredCallback = f;
204}
205
206void JavaBridge::signalServiceFuncPtrQueue()
207{
208    // In order to signal the main thread we must go through JNI. This
209    // is the only usage on most threads, so we need to ensure a JNI
210    // environment is setup.
211    JNIEnv* env = JSC::Bindings::getJNIEnv();
212    AutoJObject obj = getRealObject(env, mJavaObject);
213    env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue);
214}
215
216// ----------------------------------------------------------------------------
217
218// visible to Shared
219void AndroidSignalServiceFuncPtrQueue()
220{
221    gJavaBridge->signalServiceFuncPtrQueue();
222}
223
224// ----------------------------------------------------------------------------
225
226void JavaBridge::Constructor(JNIEnv* env, jobject obj)
227{
228    JavaBridge* javaBridge = new JavaBridge(env, obj);
229    env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
230}
231
232void JavaBridge::Finalize(JNIEnv* env, jobject obj)
233{
234    JavaBridge* javaBridge = (JavaBridge*)
235        (env->GetIntField(obj, gJavaBridge_ObjectID));
236    LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
237    LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
238    delete javaBridge;
239    env->SetIntField(obj, gJavaBridge_ObjectID, 0);
240}
241
242// we don't use the java bridge object, as we're just looking at a global
243void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
244{
245    if (sSharedTimerFiredCallback)
246    {
247#ifdef ANDROID_INSTRUMENT
248        TimeCounter::start(TimeCounter::SharedTimerTimeCounter);
249#endif
250        SkAutoMemoryUsageProbe  mup("JavaBridge::sharedTimerFired");
251        sSharedTimerFiredCallback();
252#ifdef ANDROID_INSTRUMENT
253        TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__);
254#endif
255    }
256}
257
258void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
259{
260    WebCore::cache()->setCapacities(0, bytes/2, bytes);
261}
262
263void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online)
264{
265	WebCore::networkStateNotifier().networkStateChange(online);
266}
267
268void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer)
269{
270    WebCore::setDeferringTimers(defer);
271}
272
273void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
274{
275    JavaSharedClient::ServiceFunctionPtrQueue();
276}
277
278// ----------------------------------------------------------------------------
279
280/*
281 * JNI registration.
282 */
283static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
284    /* name, signature, funcPtr */
285    { "nativeConstructor", "()V",
286        (void*) JavaBridge::Constructor },
287    { "nativeFinalize", "()V",
288        (void*) JavaBridge::Finalize },
289    { "sharedTimerFired", "()V",
290        (void*) JavaBridge::SharedTimerFired },
291    { "setCacheSize", "(I)V",
292        (void*) JavaBridge::SetCacheSize },
293    { "setNetworkOnLine", "(Z)V",
294        (void*) JavaBridge::SetNetworkOnLine },
295    { "setDeferringTimers", "(Z)V",
296        (void*) JavaBridge::SetDeferringTimers },
297    { "nativeServiceFuncPtrQueue", "()V",
298        (void*) JavaBridge::ServiceFuncPtrQueue },
299};
300
301int register_javabridge(JNIEnv* env)
302{
303    jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
304    LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
305    gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
306    LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
307
308    return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
309                                    gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
310}
311
312} /* namespace android */
313