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