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