From d2a4306024cc3bd6c52c70646ad6ec37f0259622 Mon Sep 17 00:00:00 2001 From: sgurun Date: Fri, 23 Jan 2015 12:54:05 -0800 Subject: Enable posting a message from JS to Android webview. For future CL: queueing messages, sending messages from Java to JS through message channel, transferring ports in message channels, closing channels. BUG=393291 Review URL: https://codereview.chromium.org/831523004 Cr-Commit-Position: refs/heads/master@{#312922} --- .../native/android_webview_jni_registrar.cc | 2 + android_webview/native/aw_contents.cc | 79 ++++------ android_webview/native/aw_contents.h | 3 + .../native/aw_message_port_service_impl.cc | 161 +++++++++++++++++++++ .../native/aw_message_port_service_impl.h | 65 +++++++++ android_webview/native/webview_native.gyp | 3 + 6 files changed, 261 insertions(+), 52 deletions(-) create mode 100644 android_webview/native/aw_message_port_service_impl.cc create mode 100644 android_webview/native/aw_message_port_service_impl.h (limited to 'android_webview/native') diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index 253a070..e81853f 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc @@ -14,6 +14,7 @@ #include "android_webview/native/aw_dev_tools_server.h" #include "android_webview/native/aw_form_database.h" #include "android_webview/native/aw_http_auth_handler.h" +#include "android_webview/native/aw_message_port_service_impl.h" #include "android_webview/native/aw_pdf_exporter.h" #include "android_webview/native/aw_picture.h" #include "android_webview/native/aw_quota_manager_bridge_impl.h" @@ -58,6 +59,7 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = { { "AwWebResourceResponseImpl", RegisterAwWebResourceResponse }, { "InputStream", RegisterInputStream }, { "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper }, + { "AwMessagePortService", RegisterAwMessagePortService }, }; bool RegisterJni(JNIEnv* env) { diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index 2a9a35f..64cd9a9 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -21,6 +21,7 @@ #include "android_webview/native/aw_browser_dependency_factory.h" #include "android_webview/native/aw_contents_client_bridge.h" #include "android_webview/native/aw_contents_io_thread_client_impl.h" +#include "android_webview/native/aw_message_port_service_impl.h" #include "android_webview/native/aw_pdf_exporter.h" #include "android_webview/native/aw_picture.h" #include "android_webview/native/aw_web_contents_delegate.h" @@ -133,23 +134,6 @@ void OnIoThreadClientReady(content::RenderFrameHost* rfh) { render_process_id, render_frame_id); } -void OnMessageChannelCreated(ScopedJavaGlobalRef* callback, - int* port1, - int* port2) { - JNIEnv* env = AttachCurrentThread(); - Java_AwContents_onMessageChannelCreated(env, *port1, *port2, - callback->obj()); -} - -void PostMessageToFrameOnIOThread(WebContents* web_contents, - base::string16* source_origin, - base::string16* target_origin, - base::string16* data, - std::vector* ports) { - content::MessagePortProvider::PostMessageToFrame(web_contents, - *source_origin, *target_origin, *data, *ports); -} - } // namespace // static @@ -1084,49 +1068,40 @@ void AwContents::PostMessageToFrame(JNIEnv* env, jobject obj, jstring frame_name, jstring message, jstring source_origin, jstring target_origin, jintArray msgPorts) { - base::string16* j_source_origin = new base::string16; - ConvertJavaStringToUTF16(env, source_origin, j_source_origin); - base::string16* j_target_origin = new base::string16; - ConvertJavaStringToUTF16(env, target_origin, j_target_origin); - base::string16* j_message = new base::string16; - ConvertJavaStringToUTF16(env, message, j_message); - std::vector* j_ports = new std::vector; - + base::string16 j_source_origin(ConvertJavaStringToUTF16(env, source_origin)); + base::string16 j_target_origin(ConvertJavaStringToUTF16(env, target_origin)); + base::string16 j_message(ConvertJavaStringToUTF16(env, message)); + std::vector j_ports; if (msgPorts != nullptr) - base::android::JavaIntArrayToIntVector(env, msgPorts, j_ports); - - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&PostMessageToFrameOnIOThread, - web_contents_.get(), - base::Owned(j_source_origin), - base::Owned(j_target_origin), - base::Owned(j_message), - base::Owned(j_ports))); + base::android::JavaIntArrayToIntVector(env, msgPorts, &j_ports); + + content::MessagePortProvider::PostMessageToFrame(web_contents_.get(), + j_source_origin, + j_target_origin, + j_message, + j_ports); +} + +scoped_refptr +AwContents::GetMessagePortMessageFilter() { + // Create a message port message filter if necessary + if (message_port_message_filter_.get() == nullptr) { + message_port_message_filter_ = + new AwMessagePortMessageFilter( + web_contents_->GetMainFrame()->GetRoutingID()); + web_contents_->GetRenderProcessHost()->AddFilter( + message_port_message_filter_.get()); + } + return message_port_message_filter_; } void AwContents::CreateMessageChannel(JNIEnv* env, jobject obj, jobject callback) { - ScopedJavaGlobalRef* j_callback = new ScopedJavaGlobalRef(); - j_callback->Reset(env, callback); - int* port1 = new int; - int* port2 = new int; - BrowserThread::PostTaskAndReply( - BrowserThread::IO, - FROM_HERE, - base::Bind(&content::MessagePortProvider::CreateMessageChannel, - web_contents_.get(), - port1, - port2), - base::Bind(&OnMessageChannelCreated, - base::Owned(j_callback), - base::Owned(port1), - base::Owned(port2))); + AwMessagePortServiceImpl::GetInstance()->CreateMessageChannel(env, callback, + GetMessagePortMessageFilter()); } - void SetShouldDownloadFavicons(JNIEnv* env, jclass jclazz) { g_should_download_favicons = true; } diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h index 4a4afbb..13ad67c 100644 --- a/android_webview/native/aw_contents.h +++ b/android_webview/native/aw_contents.h @@ -11,6 +11,7 @@ #include #include "android_webview/browser/aw_browser_permission_request_delegate.h" +#include "android_webview/browser/aw_message_port_message_filter.h" #include "android_webview/browser/browser_view_renderer.h" #include "android_webview/browser/browser_view_renderer_client.h" #include "android_webview/browser/find_helper.h" @@ -220,6 +221,7 @@ class AwContents : public FindHelper::Listener, void SetJsOnlineProperty(JNIEnv* env, jobject obj, jboolean network_up); void TrimMemory(JNIEnv* env, jobject obj, jint level, jboolean visible); + scoped_refptr GetMessagePortMessageFilter(); void PostMessageToFrame(JNIEnv* env, jobject obj, jstring frame_id, jstring message, jstring source_origin, jstring target_origin, jintArray msgPorts); @@ -244,6 +246,7 @@ class AwContents : public FindHelper::Listener, BrowserViewRenderer browser_view_renderer_; scoped_ptr pdf_exporter_; scoped_ptr permission_request_handler_; + scoped_refptr message_port_message_filter_; // GURL is supplied by the content layer as requesting frame. // Callback is supplied by the content layer, and is invoked with the result diff --git a/android_webview/native/aw_message_port_service_impl.cc b/android_webview/native/aw_message_port_service_impl.cc new file mode 100644 index 0000000..5fa4e1b --- /dev/null +++ b/android_webview/native/aw_message_port_service_impl.cc @@ -0,0 +1,161 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/native/aw_message_port_service_impl.h" + +#include "android_webview/browser/aw_browser_context.h" +#include "android_webview/browser/aw_message_port_message_filter.h" +#include "android_webview/native/aw_contents.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/message_port_provider.h" +#include "jni/AwMessagePortService_jni.h" + +namespace android_webview { + +using base::android::AttachCurrentThread; +using base::android::ConvertUTF16ToJavaString; +using base::android::ScopedJavaGlobalRef; +using base::android::ScopedJavaLocalRef; +using base::android::ToJavaIntArray; +using content::BrowserThread; +using content::MessagePortProvider; + +//static +AwMessagePortServiceImpl* AwMessagePortServiceImpl::GetInstance() { + return static_cast( + AwBrowserContext::GetDefault()->GetMessagePortService()); +} + +AwMessagePortServiceImpl::AwMessagePortServiceImpl() { +} + +AwMessagePortServiceImpl::~AwMessagePortServiceImpl() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef obj = java_ref_.get(env); + if (obj.is_null()) + return; + Java_AwMessagePortService_unregisterNativeAwMessagePortService(env, + obj.obj()); +} + +void AwMessagePortServiceImpl::Init(JNIEnv* env, jobject obj) { + java_ref_ = JavaObjectWeakGlobalRef(env, obj); +} + +void AwMessagePortServiceImpl::CreateMessageChannel( + JNIEnv* env, + jobject callback, + scoped_refptr filter) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + ScopedJavaGlobalRef* j_callback = new ScopedJavaGlobalRef(); + j_callback->Reset(env, callback); + + int* portId1 = new int; + int* portId2 = new int; + BrowserThread::PostTaskAndReply( + BrowserThread::IO, + FROM_HERE, + base::Bind(&AwMessagePortServiceImpl::CreateMessageChannelOnIOThread, + base::Unretained(this), + filter, + portId1, + portId2), + base::Bind(&AwMessagePortServiceImpl::OnMessageChannelCreated, + base::Unretained(this), + base::Owned(j_callback), + base::Owned(portId1), + base::Owned(portId2))); +} + +void AwMessagePortServiceImpl::OnConvertedMessage( + int message_port_id, + const base::ListValue& message, + const std::vector& sent_message_port_ids) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef jobj = java_ref_.get(env); + if (jobj.is_null()) + return; + + if (message.GetSize() != 1) { + NOTREACHED(); + return; + } + + base::string16 value; + if (!message.GetString(0, &value)) { + LOG(WARNING) << "Converting post message to a string failed for port " + << message_port_id; + return; + } + ScopedJavaLocalRef jmsg = ConvertUTF16ToJavaString(env, value); + ScopedJavaLocalRef jports = + ToJavaIntArray(env, sent_message_port_ids); + Java_AwMessagePortService_onPostMessage(env, + jobj.obj(), + message_port_id, + jmsg.obj(), + jports.obj()); +} + +void AwMessagePortServiceImpl::OnMessagePortMessageFilterClosing( + AwMessagePortMessageFilter* filter) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + for (MessagePorts::iterator iter = ports_.begin(); + iter != ports_.end(); iter++) { + if (iter->second == filter) { + ports_.erase(iter); + } + } +} + +void AwMessagePortServiceImpl::CreateMessageChannelOnIOThread( + scoped_refptr filter, + int* portId1, + int* portId2) { + content::MessagePortProvider::CreateMessageChannel(filter.get(), portId1, + portId2); + AddPort(*portId1, filter.get()); + AddPort(*portId2, filter.get()); +} + +void AwMessagePortServiceImpl::OnMessageChannelCreated( + ScopedJavaGlobalRef* callback, + int* port1, + int* port2) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef obj = java_ref_.get(env); + if (obj.is_null()) + return; + Java_AwMessagePortService_onMessageChannelCreated(env, obj.obj(), *port1, + *port2, callback->obj()); +} + +void AwMessagePortServiceImpl::AddPort(int message_port_id, + AwMessagePortMessageFilter* filter) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (ports_.count(message_port_id)) { + NOTREACHED(); + return; + } + ports_[message_port_id] = filter; +} + +bool RegisterAwMessagePortService(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +// static +jlong InitAwMessagePortService(JNIEnv* env, jobject obj) { + AwMessagePortServiceImpl* service = AwMessagePortServiceImpl::GetInstance(); + service->Init(env, obj); + return reinterpret_cast(service); +} + +} // namespace android_webview diff --git a/android_webview/native/aw_message_port_service_impl.h b/android_webview/native/aw_message_port_service_impl.h new file mode 100644 index 0000000..d938b6e --- /dev/null +++ b/android_webview/native/aw_message_port_service_impl.h @@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_NATIVE_AW_MESSAGE_PORT_SERVICE_IMPL_H_ +#define ANDROID_WEBVIEW_NATIVE_AW_MESSAGE_PORT_SERVICE_IMPL_H_ + +#include +#include + +#include "android_webview/browser/aw_message_port_service.h" +#include "base/android/jni_weak_ref.h" +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/strings/string16.h" + +namespace android_webview { + +// This class is the native peer of AwMessagePortService.java. Please see the +// java class for an explanation of use, ownership and lifetime. + +// Threading: Created and initialized on UI thread. For other methods, see +// the method level DCHECKS or documentation. +class AwMessagePortServiceImpl : public AwMessagePortService { + public: + static AwMessagePortServiceImpl* GetInstance(); + + AwMessagePortServiceImpl(); + ~AwMessagePortServiceImpl(); + void Init(JNIEnv* env, jobject object); + + void CreateMessageChannel(JNIEnv* env, jobject callback, + scoped_refptr filter); + + // AwMessagePortService implementation + void OnConvertedMessage( + int message_port_id, + const base::ListValue& message, + const std::vector& sent_message_port_ids) override; + void OnMessagePortMessageFilterClosing( + AwMessagePortMessageFilter* filter) override; + +private: + void CreateMessageChannelOnIOThread( + scoped_refptr filter, + int* port1, + int* port2); + void OnMessageChannelCreated( + base::android::ScopedJavaGlobalRef* callback, + int* port1, + int* port2); + void AddPort(int message_port_id, AwMessagePortMessageFilter* filter); + + JavaObjectWeakGlobalRef java_ref_; + typedef std::map MessagePorts; + MessagePorts ports_; // Access on IO thread + + DISALLOW_COPY_AND_ASSIGN(AwMessagePortServiceImpl); +}; + +bool RegisterAwMessagePortService(JNIEnv* env); + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_NATIVE_AW_MESSAGE_PORT_SERVICE_IMPL_H_ diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 52b3e45..34889e1 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp @@ -58,6 +58,8 @@ 'aw_http_auth_handler.h', 'aw_media_url_interceptor.cc', 'aw_media_url_interceptor.h', + 'aw_message_port_service_impl.cc', + 'aw_messagE_port_service_impl.h', 'aw_pdf_exporter.cc', 'aw_pdf_exporter.h', 'aw_picture.cc', @@ -131,6 +133,7 @@ '../java/src/org/chromium/android_webview/AwDevToolsServer.java', '../java/src/org/chromium/android_webview/AwFormDatabase.java', '../java/src/org/chromium/android_webview/AwHttpAuthHandler.java', + '../java/src/org/chromium/android_webview/AwMessagePortService.java', '../java/src/org/chromium/android_webview/AwPdfExporter.java', '../java/src/org/chromium/android_webview/AwPicture.java', '../java/src/org/chromium/android_webview/AwQuotaManagerBridge.java', -- cgit v1.1