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