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 "KeyGeneratorClient.h"
35 #include "KURL.h"
36 #include "NetworkStateNotifier.h"
37 #include "Page.h"
38 #include "PluginClient.h"
39 #include "PluginDatabase.h"
40 #include "Timer.h"
41 #include "TimerClient.h"
42 #include "jni_utility.h"
43 #include "WebCoreJni.h"
44
45 #ifdef ANDROID_INSTRUMENT
46 #include "TimeCounter.h"
47 #endif
48
49 #include <jni.h>
50 #include <JNIHelp.h>
51 #include <SkUtils.h>
52 #include <utils/misc.h>
53
54 namespace android {
55
56 // ----------------------------------------------------------------------------
57
58 static jfieldID gJavaBridge_ObjectID;
59
60 // ----------------------------------------------------------------------------
61
62 class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient
63 {
64 public:
65 JavaBridge(JNIEnv* env, jobject obj);
66 virtual ~JavaBridge();
67
68 /*
69 * WebCore -> Java API
70 */
71 virtual void setSharedTimer(long long timemillis);
72 virtual void stopSharedTimer();
73
74 virtual void setCookies(WebCore::KURL const& url, WebCore::String const& value);
75 virtual WebCore::String cookies(WebCore::KURL const& url);
76 virtual bool cookiesEnabled();
77
78 virtual WTF::Vector<WebCore::String> getPluginDirectories();
79 virtual WebCore::String getPluginSharedDataDirectory();
80
81 virtual WTF::Vector<String> getSupportedKeyStrengthList();
82 virtual WebCore::String getSignedPublicKeyAndChallengeString(unsigned index,
83 const WebCore::String& challenge, const WebCore::KURL& url);
84
85 ////////////////////////////////////////////
86
87 virtual void setSharedTimerCallback(void (*f)());
88
89 ////////////////////////////////////////////
90
91 virtual void signalServiceFuncPtrQueue();
92
93 // jni functions
94 static void Constructor(JNIEnv* env, jobject obj);
95 static void Finalize(JNIEnv* env, jobject obj);
96 static void SharedTimerFired(JNIEnv* env, jobject);
97 static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
98 static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online);
99 static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
100 static void ServiceFuncPtrQueue(JNIEnv*);
101 static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload);
102
103 private:
104 jobject mJavaObject;
105 jmethodID mSetSharedTimer;
106 jmethodID mStopSharedTimer;
107 jmethodID mSetCookies;
108 jmethodID mCookies;
109 jmethodID mCookiesEnabled;
110 jmethodID mGetPluginDirectories;
111 jmethodID mGetPluginSharedDataDirectory;
112 jmethodID mSignalFuncPtrQueue;
113 jmethodID mGetKeyStrengthList;
114 jmethodID mGetSignedPublicKey;
115 };
116
117 static void (*sSharedTimerFiredCallback)();
118
JavaBridge(JNIEnv * env,jobject obj)119 JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
120 {
121 mJavaObject = adoptGlobalRef(env, obj);
122 jclass clazz = env->GetObjectClass(obj);
123
124 mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
125 mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
126 mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;)V");
127 mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
128 mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
129 mGetPluginDirectories = env->GetMethodID(clazz, "getPluginDirectories", "()[Ljava/lang/String;");
130 mGetPluginSharedDataDirectory = env->GetMethodID(clazz, "getPluginSharedDataDirectory", "()Ljava/lang/String;");
131 mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
132 mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;");
133 mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
134
135 LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
136 LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
137 LOG_ASSERT(mSetCookies, "Could not find method setCookies");
138 LOG_ASSERT(mCookies, "Could not find method cookies");
139 LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
140 LOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories");
141 LOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory");
142 LOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList");
143 LOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey");
144
145 JavaSharedClient::SetTimerClient(this);
146 JavaSharedClient::SetCookieClient(this);
147 JavaSharedClient::SetPluginClient(this);
148 JavaSharedClient::SetKeyGeneratorClient(this);
149 }
150
~JavaBridge()151 JavaBridge::~JavaBridge()
152 {
153 if (mJavaObject) {
154 JNIEnv* env = JSC::Bindings::getJNIEnv();
155 env->DeleteGlobalRef(mJavaObject);
156 mJavaObject = 0;
157 }
158
159 JavaSharedClient::SetTimerClient(NULL);
160 JavaSharedClient::SetCookieClient(NULL);
161 JavaSharedClient::SetPluginClient(NULL);
162 JavaSharedClient::SetKeyGeneratorClient(NULL);
163 }
164
165 void
setSharedTimer(long long timemillis)166 JavaBridge::setSharedTimer(long long timemillis)
167 {
168 JNIEnv* env = JSC::Bindings::getJNIEnv();
169 AutoJObject obj = getRealObject(env, mJavaObject);
170 env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
171 }
172
173 void
stopSharedTimer()174 JavaBridge::stopSharedTimer()
175 {
176 JNIEnv* env = JSC::Bindings::getJNIEnv();
177 AutoJObject obj = getRealObject(env, mJavaObject);
178 env->CallVoidMethod(obj.get(), mStopSharedTimer);
179 }
180
181 void
setCookies(WebCore::KURL const & url,WebCore::String const & value)182 JavaBridge::setCookies(WebCore::KURL const& url, WebCore::String const& value)
183 {
184 JNIEnv* env = JSC::Bindings::getJNIEnv();
185 const WebCore::String& urlStr = url.string();
186 jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
187 jstring jValueStr = env->NewString(value.characters(), value.length());
188
189 AutoJObject obj = getRealObject(env, mJavaObject);
190 env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jValueStr);
191 env->DeleteLocalRef(jUrlStr);
192 env->DeleteLocalRef(jValueStr);
193 }
194
195 WebCore::String
cookies(WebCore::KURL const & url)196 JavaBridge::cookies(WebCore::KURL const& url)
197 {
198 JNIEnv* env = JSC::Bindings::getJNIEnv();
199 const WebCore::String& urlStr = url.string();
200 jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
201
202 AutoJObject obj = getRealObject(env, mJavaObject);
203 jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr));
204
205 WebCore::String ret = to_string(env, string);
206 env->DeleteLocalRef(jUrlStr);
207 env->DeleteLocalRef(string);
208 return ret;
209 }
210
211 bool
cookiesEnabled()212 JavaBridge::cookiesEnabled()
213 {
214 JNIEnv* env = JSC::Bindings::getJNIEnv();
215 AutoJObject obj = getRealObject(env, mJavaObject);
216 jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled);
217 return (ret != 0);
218 }
219
220 WTF::Vector<WebCore::String>
getPluginDirectories()221 JavaBridge::getPluginDirectories()
222 {
223 WTF::Vector<WebCore::String> directories;
224 JNIEnv* env = JSC::Bindings::getJNIEnv();
225 AutoJObject obj = getRealObject(env, mJavaObject);
226 jobjectArray array = (jobjectArray)
227 env->CallObjectMethod(obj.get(), mGetPluginDirectories);
228 int count = env->GetArrayLength(array);
229 for (int i = 0; i < count; i++) {
230 jstring dir = (jstring) env->GetObjectArrayElement(array, i);
231 directories.append(to_string(env, dir));
232 env->DeleteLocalRef(dir);
233 }
234 env->DeleteLocalRef(array);
235 checkException(env);
236 return directories;
237 }
238
239 WebCore::String
getPluginSharedDataDirectory()240 JavaBridge::getPluginSharedDataDirectory()
241 {
242 JNIEnv* env = JSC::Bindings::getJNIEnv();
243 AutoJObject obj = getRealObject(env, mJavaObject);
244 jstring ret = (jstring)env->CallObjectMethod(obj.get(), mGetPluginSharedDataDirectory);
245 WebCore::String path = to_string(env, ret);
246 checkException(env);
247 return path;
248 }
249
250 void
setSharedTimerCallback(void (* f)())251 JavaBridge::setSharedTimerCallback(void (*f)())
252 {
253 LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
254 "Shared timer callback may already be set or null!");
255
256 sSharedTimerFiredCallback = f;
257 }
258
signalServiceFuncPtrQueue()259 void JavaBridge::signalServiceFuncPtrQueue()
260 {
261 // In order to signal the main thread we must go through JNI. This
262 // is the only usage on most threads, so we need to ensure a JNI
263 // environment is setup.
264 JNIEnv* env = JSC::Bindings::getJNIEnv();
265 AutoJObject obj = getRealObject(env, mJavaObject);
266 env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue);
267 }
268
getSupportedKeyStrengthList()269 WTF::Vector<WebCore::String>JavaBridge::getSupportedKeyStrengthList() {
270 WTF::Vector<WebCore::String> list;
271 JNIEnv* env = JSC::Bindings::getJNIEnv();
272 AutoJObject obj = getRealObject(env, mJavaObject);
273 jobjectArray array = (jobjectArray) env->CallObjectMethod(obj.get(),
274 mGetKeyStrengthList);
275 int count = env->GetArrayLength(array);
276 for (int i = 0; i < count; ++i) {
277 jstring keyStrength = (jstring) env->GetObjectArrayElement(array, i);
278 list.append(to_string(env, keyStrength));
279 env->DeleteLocalRef(keyStrength);
280 }
281 env->DeleteLocalRef(array);
282 checkException(env);
283 return list;
284 }
285
getSignedPublicKeyAndChallengeString(unsigned index,const WebCore::String & challenge,const WebCore::KURL & url)286 WebCore::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index,
287 const WebCore::String& challenge, const WebCore::KURL& url) {
288 JNIEnv* env = JSC::Bindings::getJNIEnv();
289 jstring jChallenge = env->NewString(challenge.characters(),
290 challenge.length());
291 const WebCore::String& urlStr = url.string();
292 jstring jUrl = env->NewString(urlStr.characters(), urlStr.length());
293 AutoJObject obj = getRealObject(env, mJavaObject);
294 jstring key = (jstring) env->CallObjectMethod(obj.get(),
295 mGetSignedPublicKey, index, jChallenge, jUrl);
296 WebCore::String ret = to_string(env, key);
297 env->DeleteLocalRef(jChallenge);
298 env->DeleteLocalRef(jUrl);
299 env->DeleteLocalRef(key);
300 return ret;
301 }
302
303 // ----------------------------------------------------------------------------
304
Constructor(JNIEnv * env,jobject obj)305 void JavaBridge::Constructor(JNIEnv* env, jobject obj)
306 {
307 JavaBridge* javaBridge = new JavaBridge(env, obj);
308 env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
309 }
310
Finalize(JNIEnv * env,jobject obj)311 void JavaBridge::Finalize(JNIEnv* env, jobject obj)
312 {
313 JavaBridge* javaBridge = (JavaBridge*)
314 (env->GetIntField(obj, gJavaBridge_ObjectID));
315 LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
316 LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
317 delete javaBridge;
318 env->SetIntField(obj, gJavaBridge_ObjectID, 0);
319 }
320
321 // we don't use the java bridge object, as we're just looking at a global
SharedTimerFired(JNIEnv * env,jobject)322 void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
323 {
324 if (sSharedTimerFiredCallback)
325 {
326 #ifdef ANDROID_INSTRUMENT
327 TimeCounter::start(TimeCounter::SharedTimerTimeCounter);
328 #endif
329 SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
330 sSharedTimerFiredCallback();
331 #ifdef ANDROID_INSTRUMENT
332 TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__);
333 #endif
334 }
335 }
336
SetCacheSize(JNIEnv * env,jobject obj,jint bytes)337 void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
338 {
339 WebCore::cache()->setCapacities(0, bytes/2, bytes);
340 }
341
SetNetworkOnLine(JNIEnv * env,jobject obj,jboolean online)342 void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online)
343 {
344 WebCore::networkStateNotifier().networkStateChange(online);
345 }
346
ServiceFuncPtrQueue(JNIEnv *)347 void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
348 {
349 JavaSharedClient::ServiceFunctionPtrQueue();
350 }
351
UpdatePluginDirectories(JNIEnv * env,jobject obj,jobjectArray array,jboolean reload)352 void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj,
353 jobjectArray array, jboolean reload) {
354 WTF::Vector<WebCore::String> directories;
355 int count = env->GetArrayLength(array);
356 for (int i = 0; i < count; i++) {
357 jstring dir = (jstring) env->GetObjectArrayElement(array, i);
358 directories.append(to_string(env, dir));
359 env->DeleteLocalRef(dir);
360 }
361 checkException(env);
362 WebCore::PluginDatabase *pluginDatabase =
363 WebCore::PluginDatabase::installedPlugins();
364 pluginDatabase->setPluginDirectories(directories);
365 // refreshPlugins() should refresh both PluginDatabase and Page's PluginData
366 WebCore::Page::refreshPlugins(reload);
367 }
368
369 // ----------------------------------------------------------------------------
370
371 /*
372 * JNI registration.
373 */
374 static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
375 /* name, signature, funcPtr */
376 { "nativeConstructor", "()V",
377 (void*) JavaBridge::Constructor },
378 { "nativeFinalize", "()V",
379 (void*) JavaBridge::Finalize },
380 { "sharedTimerFired", "()V",
381 (void*) JavaBridge::SharedTimerFired },
382 { "setCacheSize", "(I)V",
383 (void*) JavaBridge::SetCacheSize },
384 { "setNetworkOnLine", "(Z)V",
385 (void*) JavaBridge::SetNetworkOnLine },
386 { "nativeServiceFuncPtrQueue", "()V",
387 (void*) JavaBridge::ServiceFuncPtrQueue },
388 { "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V",
389 (void*) JavaBridge::UpdatePluginDirectories }
390 };
391
register_javabridge(JNIEnv * env)392 int register_javabridge(JNIEnv* env)
393 {
394 jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
395 LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
396 gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
397 LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
398
399 return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
400 gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
401 }
402
403 } /* namespace android */
404