Home | History | Annotate | Download | only in jni
      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 
    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 
    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
    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
    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
    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
    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
    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>
    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
    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
    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 
    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 
    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 
    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 
    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 
    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
    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 
    345 void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
    346 {
    347     WebCore::cache()->setCapacities(0, bytes/2, bytes);
    348 }
    349 
    350 void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online)
    351 {
    352 	WebCore::networkStateNotifier().networkStateChange(online);
    353 }
    354 
    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 
    378 void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
    379 {
    380     JavaSharedClient::ServiceFunctionPtrQueue();
    381 }
    382 
    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 
    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 
    429 void JavaBridge::AddPackageName(JNIEnv* env, jobject obj, jstring packageName)
    430 {
    431     packageNotifier().addPackageName(to_string(env, packageName));
    432 }
    433 
    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 
    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