1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "android_webview/native/aw_message_port_service_impl.h"
7 #include "android_webview/browser/aw_browser_context.h"
8 #include "android_webview/browser/aw_message_port_message_filter.h"
9 #include "android_webview/native/aw_contents.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/bind.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/message_port_provider.h"
15 #include "jni/AwMessagePortService_jni.h"
17 namespace android_webview
{
19 using base::android::AttachCurrentThread
;
20 using base::android::ConvertJavaStringToUTF16
;
21 using base::android::ConvertUTF16ToJavaString
;
22 using base::android::ScopedJavaGlobalRef
;
23 using base::android::ScopedJavaLocalRef
;
24 using base::android::ToJavaIntArray
;
25 using content::BrowserThread
;
26 using content::MessagePortProvider
;
29 AwMessagePortServiceImpl
* AwMessagePortServiceImpl::GetInstance() {
30 return static_cast<AwMessagePortServiceImpl
*>(
31 AwBrowserContext::GetDefault()->GetMessagePortService());
34 AwMessagePortServiceImpl::AwMessagePortServiceImpl() {
37 AwMessagePortServiceImpl::~AwMessagePortServiceImpl() {
38 JNIEnv
* env
= AttachCurrentThread();
39 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
42 Java_AwMessagePortService_unregisterNativeAwMessagePortService(env
,
46 void AwMessagePortServiceImpl::Init(JNIEnv
* env
, jobject obj
) {
47 java_ref_
= JavaObjectWeakGlobalRef(env
, obj
);
50 void AwMessagePortServiceImpl::CreateMessageChannel(
53 scoped_refptr
<AwMessagePortMessageFilter
> filter
) {
54 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
56 ScopedJavaGlobalRef
<jobjectArray
>* j_ports
=
57 new ScopedJavaGlobalRef
<jobjectArray
>();
58 j_ports
->Reset(env
, ports
);
60 int* portId1
= new int;
61 int* portId2
= new int;
62 BrowserThread::PostTaskAndReply(
65 base::Bind(&AwMessagePortServiceImpl::CreateMessageChannelOnIOThread
,
66 base::Unretained(this),
70 base::Bind(&AwMessagePortServiceImpl::OnMessageChannelCreated
,
71 base::Unretained(this),
74 base::Owned(portId2
)));
77 void AwMessagePortServiceImpl::OnConvertedWebToAppMessage(
79 const base::ListValue
& message
,
80 const std::vector
<int>& sent_message_port_ids
) {
81 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
82 JNIEnv
* env
= AttachCurrentThread();
83 ScopedJavaLocalRef
<jobject
> jobj
= java_ref_
.get(env
);
87 if (message
.GetSize() != 1) {
93 if (!message
.GetString(0, &value
)) {
94 LOG(WARNING
) << "Converting post message to a string failed for port "
98 ScopedJavaLocalRef
<jstring
> jmsg
= ConvertUTF16ToJavaString(env
, value
);
99 ScopedJavaLocalRef
<jintArray
> jports
=
100 ToJavaIntArray(env
, sent_message_port_ids
);
101 Java_AwMessagePortService_onReceivedMessage(env
,
108 void AwMessagePortServiceImpl::OnMessagePortMessageFilterClosing(
109 AwMessagePortMessageFilter
* filter
) {
110 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
111 for (MessagePorts::iterator iter
= ports_
.begin();
112 iter
!= ports_
.end(); iter
++) {
113 if (iter
->second
== filter
) {
119 void AwMessagePortServiceImpl::PostAppToWebMessage(JNIEnv
* env
, jobject obj
,
120 int sender_id
, jstring message
, jintArray sent_ports
) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
122 base::string16
* j_message
= new base::string16
;
123 ConvertJavaStringToUTF16(env
, message
, j_message
);
124 std::vector
<int>* j_sent_ports
= new std::vector
<int>;
125 if (sent_ports
!= nullptr)
126 base::android::JavaIntArrayToIntVector(env
, sent_ports
, j_sent_ports
);
128 BrowserThread::PostTask(
131 base::Bind(&AwMessagePortServiceImpl::PostAppToWebMessageOnIOThread
,
132 base::Unretained(this),
134 base::Owned(j_message
),
135 base::Owned(j_sent_ports
)));
138 // The message port service cannot immediately close the port, because
139 // it is possible that messages are still queued in the renderer process
140 // waiting for a conversion. Instead, it sends a special message with
141 // a flag which indicates that this message port should be closed.
142 void AwMessagePortServiceImpl::ClosePort(JNIEnv
* env
, jobject obj
,
143 int message_port_id
) {
144 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
145 BrowserThread::PostTask(
148 base::Bind(&AwMessagePortServiceImpl::PostClosePortMessage
,
149 base::Unretained(this),
153 void AwMessagePortServiceImpl::RemoveSentPorts(
154 const std::vector
<int>& sent_ports
) {
155 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
156 // Remove the filters that are associated with the transferred ports
157 for (const auto& iter
: sent_ports
)
161 void AwMessagePortServiceImpl::PostAppToWebMessageOnIOThread(
163 base::string16
* message
,
164 std::vector
<int>* sent_ports
) {
165 RemoveSentPorts(*sent_ports
);
166 ports_
[sender_id
]->SendAppToWebMessage(sender_id
, *message
, *sent_ports
);
169 void AwMessagePortServiceImpl::PostClosePortMessage(int message_port_id
) {
170 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
171 ports_
[message_port_id
]->SendClosePortMessage(message_port_id
);
174 void AwMessagePortServiceImpl::CleanupPort(int message_port_id
) {
175 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
176 ports_
.erase(message_port_id
);
179 void AwMessagePortServiceImpl::CreateMessageChannelOnIOThread(
180 scoped_refptr
<AwMessagePortMessageFilter
> filter
,
183 MessagePortProvider::CreateMessageChannel(filter
.get(), portId1
, portId2
);
184 AddPort(*portId1
, filter
.get());
185 AddPort(*portId2
, filter
.get());
188 void AwMessagePortServiceImpl::OnMessageChannelCreated(
189 ScopedJavaGlobalRef
<jobjectArray
>* ports
,
192 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
193 JNIEnv
* env
= AttachCurrentThread();
194 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
197 Java_AwMessagePortService_onMessageChannelCreated(env
, obj
.obj(), *port1
,
198 *port2
, ports
->obj());
201 void AwMessagePortServiceImpl::AddPort(int message_port_id
,
202 AwMessagePortMessageFilter
* filter
) {
203 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
204 if (ports_
.count(message_port_id
)) {
208 ports_
[message_port_id
] = filter
;
211 bool RegisterAwMessagePortService(JNIEnv
* env
) {
212 return RegisterNativesImpl(env
);
216 jlong
InitAwMessagePortService(JNIEnv
* env
, jobject obj
) {
217 AwMessagePortServiceImpl
* service
= AwMessagePortServiceImpl::GetInstance();
218 service
->Init(env
, obj
);
219 return reinterpret_cast<intptr_t>(service
);
222 } // namespace android_webview