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