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
);
88 if (!message
.GetString(0, &value
)) {
89 LOG(WARNING
) << "Converting post message to a string failed for port "
94 if (message
.GetSize() != 1) {
99 // Add the ports to AwMessagePortService.
100 for (const auto& iter
: sent_message_port_ids
) {
101 AddPort(iter
, ports_
[message_port_id
]);
104 ScopedJavaLocalRef
<jstring
> jmsg
= ConvertUTF16ToJavaString(env
, value
);
105 ScopedJavaLocalRef
<jintArray
> jports
=
106 ToJavaIntArray(env
, sent_message_port_ids
);
107 Java_AwMessagePortService_onReceivedMessage(env
,
114 void AwMessagePortServiceImpl::OnMessagePortMessageFilterClosing(
115 AwMessagePortMessageFilter
* filter
) {
116 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
117 for (MessagePorts::iterator iter
= ports_
.begin();
118 iter
!= ports_
.end(); iter
++) {
119 if (iter
->second
== filter
) {
125 void AwMessagePortServiceImpl::PostAppToWebMessage(JNIEnv
* env
, jobject obj
,
126 int sender_id
, jstring message
, jintArray sent_ports
) {
127 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
128 base::string16
* j_message
= new base::string16
;
129 ConvertJavaStringToUTF16(env
, message
, j_message
);
130 std::vector
<int>* j_sent_ports
= new std::vector
<int>;
131 if (sent_ports
!= nullptr)
132 base::android::JavaIntArrayToIntVector(env
, sent_ports
, j_sent_ports
);
134 BrowserThread::PostTask(
137 base::Bind(&AwMessagePortServiceImpl::PostAppToWebMessageOnIOThread
,
138 base::Unretained(this),
140 base::Owned(j_message
),
141 base::Owned(j_sent_ports
)));
144 // The message port service cannot immediately close the port, because
145 // it is possible that messages are still queued in the renderer process
146 // waiting for a conversion. Instead, it sends a special message with
147 // a flag which indicates that this message port should be closed.
148 void AwMessagePortServiceImpl::ClosePort(JNIEnv
* env
, jobject obj
,
149 int message_port_id
) {
150 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
151 BrowserThread::PostTask(
154 base::Bind(&AwMessagePortServiceImpl::PostClosePortMessage
,
155 base::Unretained(this),
159 void AwMessagePortServiceImpl::ReleaseMessages(JNIEnv
* env
, jobject obj
,
160 int message_port_id
) {
161 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
162 BrowserThread::PostTask(
165 base::Bind(&MessagePortProvider::ReleaseMessages
, message_port_id
));
168 void AwMessagePortServiceImpl::RemoveSentPorts(
169 const std::vector
<int>& sent_ports
) {
170 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
171 // Remove the filters that are associated with the transferred ports
172 for (const auto& iter
: sent_ports
)
176 void AwMessagePortServiceImpl::PostAppToWebMessageOnIOThread(
178 base::string16
* message
,
179 std::vector
<int>* sent_ports
) {
180 RemoveSentPorts(*sent_ports
);
181 ports_
[sender_id
]->SendAppToWebMessage(sender_id
, *message
, *sent_ports
);
184 void AwMessagePortServiceImpl::PostClosePortMessage(int message_port_id
) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
186 ports_
[message_port_id
]->SendClosePortMessage(message_port_id
);
189 void AwMessagePortServiceImpl::CleanupPort(int message_port_id
) {
190 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
191 ports_
.erase(message_port_id
);
194 void AwMessagePortServiceImpl::CreateMessageChannelOnIOThread(
195 scoped_refptr
<AwMessagePortMessageFilter
> filter
,
198 MessagePortProvider::CreateMessageChannel(filter
.get(), portId1
, portId2
);
199 MessagePortProvider::HoldMessages(*portId1
);
200 MessagePortProvider::HoldMessages(*portId2
);
201 AddPort(*portId1
, filter
.get());
202 AddPort(*portId2
, filter
.get());
205 void AwMessagePortServiceImpl::OnMessageChannelCreated(
206 ScopedJavaGlobalRef
<jobjectArray
>* ports
,
209 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
210 JNIEnv
* env
= AttachCurrentThread();
211 ScopedJavaLocalRef
<jobject
> obj
= java_ref_
.get(env
);
214 Java_AwMessagePortService_onMessageChannelCreated(env
, obj
.obj(), *port1
,
215 *port2
, ports
->obj());
218 // Adds a new port to the message port service.
219 void AwMessagePortServiceImpl::AddPort(int message_port_id
,
220 AwMessagePortMessageFilter
* filter
) {
221 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
222 if (ports_
.count(message_port_id
)) {
226 ports_
[message_port_id
] = filter
;
229 bool RegisterAwMessagePortService(JNIEnv
* env
) {
230 return RegisterNativesImpl(env
);
234 jlong
InitAwMessagePortService(JNIEnv
* env
, const JavaParamRef
<jobject
>& obj
) {
235 AwMessagePortServiceImpl
* service
= AwMessagePortServiceImpl::GetInstance();
236 service
->Init(env
, obj
);
237 return reinterpret_cast<intptr_t>(service
);
240 } // namespace android_webview