blob: 9f89ccdae57feb92da61361abad49de259a29751 [file] [log] [blame]
/*
* Copyright 2006, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "webcoreglue"
#include "config.h"
#include "MemoryCache.h"
#include "Connection.h"
#include "CookieClient.h"
#include "FileSystemClient.h"
#include "JavaSharedClient.h"
#include "KeyGeneratorClient.h"
#include "KURL.h"
#include "NetworkStateNotifier.h"
#include "PackageNotifier.h"
#include "Page.h"
#include "PluginClient.h"
#include "PluginDatabase.h"
#include "Timer.h"
#include "TimerClient.h"
#include "WebCache.h"
#include "WebCoreJni.h"
#include <JNIHelp.h>
#include <JNIUtility.h>
#include <SkUtils.h>
#include <jni.h>
#include <utils/misc.h>
#include <wtf/Platform.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/AtomicString.h>
namespace android {
// ----------------------------------------------------------------------------
static jfieldID gJavaBridge_ObjectID;
// ----------------------------------------------------------------------------
class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient, public FileSystemClient
{
public:
JavaBridge(JNIEnv* env, jobject obj);
virtual ~JavaBridge();
/*
* WebCore -> Java API
*/
virtual void setSharedTimer(long long timemillis);
virtual void stopSharedTimer();
virtual void setCookies(WebCore::KURL const& url, WTF::String const& value);
virtual WTF::String cookies(WebCore::KURL const& url);
virtual bool cookiesEnabled();
virtual WTF::Vector<WTF::String> getPluginDirectories();
virtual WTF::String getPluginSharedDataDirectory();
virtual WTF::Vector<String> getSupportedKeyStrengthList();
virtual WTF::String getSignedPublicKeyAndChallengeString(unsigned index,
const WTF::String& challenge, const WebCore::KURL& url);
virtual WTF::String resolveFilePathForContentUri(const WTF::String& uri);
////////////////////////////////////////////
virtual void setSharedTimerCallback(void (*f)());
////////////////////////////////////////////
virtual void signalServiceFuncPtrQueue();
// jni functions
static void Constructor(JNIEnv* env, jobject obj);
static void Finalize(JNIEnv* env, jobject obj);
static void SharedTimerFired(JNIEnv* env, jobject);
static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online);
static void SetNetworkType(JNIEnv* env, jobject obj, jstring type, jstring subtype);
static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
static void ServiceFuncPtrQueue(JNIEnv*);
static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload);
static void AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames);
static void AddPackageName(JNIEnv* env, jobject obj, jstring packageName);
static void RemovePackageName(JNIEnv* env, jobject obj, jstring packageName);
static void UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy, jstring newExList);
private:
jweak mJavaObject;
jmethodID mSetSharedTimer;
jmethodID mStopSharedTimer;
jmethodID mSetCookies;
jmethodID mCookies;
jmethodID mCookiesEnabled;
jmethodID mGetPluginDirectories;
jmethodID mGetPluginSharedDataDirectory;
jmethodID mSignalFuncPtrQueue;
jmethodID mGetKeyStrengthList;
jmethodID mGetSignedPublicKey;
jmethodID mResolveFilePathForContentUri;
AutoJObject javaObject(JNIEnv* env) { return getRealObject(env, mJavaObject); }
};
static void (*sSharedTimerFiredCallback)();
JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
{
mJavaObject = env->NewWeakGlobalRef(obj);
jclass clazz = env->GetObjectClass(obj);
mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;)V");
mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
mGetPluginDirectories = env->GetMethodID(clazz, "getPluginDirectories", "()[Ljava/lang/String;");
mGetPluginSharedDataDirectory = env->GetMethodID(clazz, "getPluginSharedDataDirectory", "()Ljava/lang/String;");
mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;");
mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
mResolveFilePathForContentUri = env->GetMethodID(clazz, "resolveFilePathForContentUri", "(Ljava/lang/String;)Ljava/lang/String;");
env->DeleteLocalRef(clazz);
ALOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
ALOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
ALOG_ASSERT(mSetCookies, "Could not find method setCookies");
ALOG_ASSERT(mCookies, "Could not find method cookies");
ALOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
ALOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories");
ALOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory");
ALOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList");
ALOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey");
JavaSharedClient::SetTimerClient(this);
JavaSharedClient::SetCookieClient(this);
JavaSharedClient::SetPluginClient(this);
JavaSharedClient::SetKeyGeneratorClient(this);
JavaSharedClient::SetFileSystemClient(this);
}
JavaBridge::~JavaBridge()
{
if (mJavaObject) {
JNIEnv* env = JSC::Bindings::getJNIEnv();
env->DeleteWeakGlobalRef(mJavaObject);
mJavaObject = 0;
}
JavaSharedClient::SetTimerClient(NULL);
JavaSharedClient::SetCookieClient(NULL);
JavaSharedClient::SetPluginClient(NULL);
JavaSharedClient::SetKeyGeneratorClient(NULL);
JavaSharedClient::SetFileSystemClient(NULL);
}
void
JavaBridge::setSharedTimer(long long timemillis)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return;
env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
}
void
JavaBridge::stopSharedTimer()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return;
env->CallVoidMethod(obj.get(), mStopSharedTimer);
}
void
JavaBridge::setCookies(WebCore::KURL const& url, WTF::String const& value)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return;
const WTF::String& urlStr = url.string();
jstring jUrlStr = wtfStringToJstring(env, urlStr);
jstring jValueStr = wtfStringToJstring(env, value);
env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jValueStr);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(jValueStr);
}
WTF::String
JavaBridge::cookies(WebCore::KURL const& url)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return String();
const WTF::String& urlStr = url.string();
jstring jUrlStr = wtfStringToJstring(env, urlStr);
jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr));
WTF::String ret = jstringToWtfString(env, string);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(string);
return ret;
}
bool
JavaBridge::cookiesEnabled()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return false;
jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled);
return (ret != 0);
}
WTF::Vector<WTF::String>
JavaBridge::getPluginDirectories()
{
WTF::Vector<WTF::String> directories;
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return directories;
jobjectArray array = (jobjectArray)
env->CallObjectMethod(obj.get(), mGetPluginDirectories);
int count = env->GetArrayLength(array);
for (int i = 0; i < count; i++) {
jstring dir = (jstring) env->GetObjectArrayElement(array, i);
directories.append(jstringToWtfString(env, dir));
env->DeleteLocalRef(dir);
}
env->DeleteLocalRef(array);
checkException(env);
return directories;
}
WTF::String
JavaBridge::getPluginSharedDataDirectory()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return String();
jstring ret = (jstring)env->CallObjectMethod(obj.get(), mGetPluginSharedDataDirectory);
WTF::String path = jstringToWtfString(env, ret);
checkException(env);
return path;
}
void
JavaBridge::setSharedTimerCallback(void (*f)())
{
ALOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
"Shared timer callback may already be set or null!");
sSharedTimerFiredCallback = f;
}
void JavaBridge::signalServiceFuncPtrQueue()
{
// In order to signal the main thread we must go through JNI. This
// is the only usage on most threads, so we need to ensure a JNI
// environment is setup.
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return;
env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue);
}
WTF::Vector<WTF::String>JavaBridge::getSupportedKeyStrengthList() {
WTF::Vector<WTF::String> list;
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return list;
jobjectArray array = (jobjectArray) env->CallObjectMethod(obj.get(),
mGetKeyStrengthList);
int count = env->GetArrayLength(array);
for (int i = 0; i < count; ++i) {
jstring keyStrength = (jstring) env->GetObjectArrayElement(array, i);
list.append(jstringToWtfString(env, keyStrength));
env->DeleteLocalRef(keyStrength);
}
env->DeleteLocalRef(array);
checkException(env);
return list;
}
WTF::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index,
const WTF::String& challenge, const WebCore::KURL& url) {
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return String();
jstring jChallenge = wtfStringToJstring(env, challenge);
const WTF::String& urlStr = url.string();
jstring jUrl = wtfStringToJstring(env, urlStr);
jstring key = (jstring) env->CallObjectMethod(obj.get(),
mGetSignedPublicKey, index, jChallenge, jUrl);
WTF::String ret = jstringToWtfString(env, key);
env->DeleteLocalRef(jChallenge);
env->DeleteLocalRef(jUrl);
env->DeleteLocalRef(key);
return ret;
}
WTF::String JavaBridge::resolveFilePathForContentUri(const WTF::String& uri) {
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = javaObject(env);
if (!obj.get())
return String();
jstring jUri = wtfStringToJstring(env, uri);
jstring path = static_cast<jstring>(env->CallObjectMethod(obj.get(), mResolveFilePathForContentUri, jUri));
WTF::String ret = jstringToWtfString(env, path);
env->DeleteLocalRef(jUri);
env->DeleteLocalRef(path);
return ret;
}
// ----------------------------------------------------------------------------
void JavaBridge::Constructor(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = new JavaBridge(env, obj);
env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
}
void JavaBridge::Finalize(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = (JavaBridge*)
(env->GetIntField(obj, gJavaBridge_ObjectID));
ALOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
ALOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
delete javaBridge;
env->SetIntField(obj, gJavaBridge_ObjectID, 0);
}
// we don't use the java bridge object, as we're just looking at a global
void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
{
if (sSharedTimerFiredCallback)
sSharedTimerFiredCallback();
}
void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
{
WebCore::memoryCache()->setCapacities(0, bytes/2, bytes);
}
void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online)
{
WebCore::networkStateNotifier().networkStateChange(online);
}
void JavaBridge::SetNetworkType(JNIEnv* env, jobject obj, jstring javatype, jstring javasubtype)
{
DEFINE_STATIC_LOCAL(AtomicString, wifi, ("wifi"));
DEFINE_STATIC_LOCAL(AtomicString, mobile, ("mobile"));
DEFINE_STATIC_LOCAL(AtomicString, mobileSupl, ("mobile_supl"));
DEFINE_STATIC_LOCAL(AtomicString, gprs, ("gprs"));
DEFINE_STATIC_LOCAL(AtomicString, edge, ("edge"));
DEFINE_STATIC_LOCAL(AtomicString, umts, ("umts"));
String type = jstringToWtfString(env, javatype);
String subtype = jstringToWtfString(env, javasubtype);
Connection::ConnectionType connectionType = Connection::UNKNOWN;
if (type == wifi)
connectionType = Connection::WIFI;
else if (type == mobile || type == mobileSupl) {
if (subtype == edge || subtype == gprs)
connectionType = Connection::CELL_2G;
else if (subtype == umts)
connectionType = Connection::CELL_3G;
}
WebCore::networkStateNotifier().networkTypeChange(connectionType);
}
void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
{
JavaSharedClient::ServiceFunctionPtrQueue();
}
void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj,
jobjectArray array, jboolean reload) {
WTF::Vector<WTF::String> directories;
int count = env->GetArrayLength(array);
for (int i = 0; i < count; i++) {
jstring dir = (jstring) env->GetObjectArrayElement(array, i);
directories.append(jstringToWtfString(env, dir));
env->DeleteLocalRef(dir);
}
checkException(env);
WebCore::PluginDatabase *pluginDatabase =
WebCore::PluginDatabase::installedPlugins();
pluginDatabase->setPluginDirectories(directories);
// refreshPlugins() should refresh both PluginDatabase and Page's PluginData
WebCore::Page::refreshPlugins(reload);
}
void JavaBridge::AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames)
{
if (!packageNames)
return;
// dalvikvm will raise exception if any of these fail
jclass setClass = env->FindClass("java/util/Set");
jmethodID iterator = env->GetMethodID(setClass, "iterator",
"()Ljava/util/Iterator;");
jobject iter = env->CallObjectMethod(packageNames, iterator);
jclass iteratorClass = env->FindClass("java/util/Iterator");
jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
HashSet<WTF::String> namesSet;
while (env->CallBooleanMethod(iter, hasNext)) {
jstring name = static_cast<jstring>(env->CallObjectMethod(iter, next));
namesSet.add(jstringToWtfString(env, name));
env->DeleteLocalRef(name);
}
packageNotifier().addPackageNames(namesSet);
env->DeleteLocalRef(iteratorClass);
env->DeleteLocalRef(iter);
env->DeleteLocalRef(setClass);
}
void JavaBridge::AddPackageName(JNIEnv* env, jobject obj, jstring packageName)
{
packageNotifier().addPackageName(jstringToWtfString(env, packageName));
}
void JavaBridge::RemovePackageName(JNIEnv* env, jobject obj, jstring packageName)
{
packageNotifier().removePackageName(jstringToWtfString(env, packageName));
}
void JavaBridge::UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy, jstring newExList)
{
std::string proxy = jstringToStdString(env, newProxy);
std::string exList = jstringToStdString(env, newExList);
WebCache::get(false)->proxy()->UpdateProxySettings(proxy, exList);
WebCache::get(true)->proxy()->UpdateProxySettings(proxy, exList);
}
// ----------------------------------------------------------------------------
/*
* JNI registration.
*/
static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
/* name, signature, funcPtr */
{ "nativeConstructor", "()V",
(void*) JavaBridge::Constructor },
{ "nativeFinalize", "()V",
(void*) JavaBridge::Finalize },
{ "sharedTimerFired", "()V",
(void*) JavaBridge::SharedTimerFired },
{ "setCacheSize", "(I)V",
(void*) JavaBridge::SetCacheSize },
{ "setNetworkOnLine", "(Z)V",
(void*) JavaBridge::SetNetworkOnLine },
{ "setNetworkType", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) JavaBridge::SetNetworkType },
{ "nativeServiceFuncPtrQueue", "()V",
(void*) JavaBridge::ServiceFuncPtrQueue },
{ "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V",
(void*) JavaBridge::UpdatePluginDirectories },
{ "addPackageNames", "(Ljava/util/Set;)V",
(void*) JavaBridge::AddPackageNames },
{ "addPackageName", "(Ljava/lang/String;)V",
(void*) JavaBridge::AddPackageName },
{ "removePackageName", "(Ljava/lang/String;)V",
(void*) JavaBridge::RemovePackageName },
{ "nativeUpdateProxy", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) JavaBridge::UpdateProxy }
};
int registerJavaBridge(JNIEnv* env)
{
jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
env->DeleteLocalRef(javaBridge);
return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
}
} /* namespace android */