Index: content/browser/android/app_web_message_port.cc |
diff --git a/content/browser/android/app_web_message_port.cc b/content/browser/android/app_web_message_port.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..56d538079d469fe6c87fabf289ef95dd8f06e29a |
--- /dev/null |
+++ b/content/browser/android/app_web_message_port.cc |
@@ -0,0 +1,163 @@ |
+// Copyright 2017 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 "content/browser/android/app_web_message_port.h" |
+ |
+#include "base/android/jni_android.h" |
+#include "base/android/jni_string.h" |
+#include "base/bind.h" |
+#include "content/browser/android/string_message_codec.h" |
+#include "jni/AppWebMessagePort_jni.h" |
+ |
+namespace content { |
+ |
+// static |
+void AppWebMessagePort::CreateAndBindToJavaObject( |
+ JNIEnv* env, |
+ mojo::ScopedMessagePipeHandle handle, |
+ const base::android::JavaRef<jobject>& jobject) { |
+ AppWebMessagePort* instance = |
+ new AppWebMessagePort(env, std::move(handle), jobject); |
+ Java_AppWebMessagePort_setNativeAppWebMessagePort( |
+ env, jobject, reinterpret_cast<jlong>(instance)); |
+} |
+ |
+// static |
+std::vector<MessagePort> AppWebMessagePort::UnwrapJavaArray( |
+ JNIEnv* env, |
+ const base::android::JavaRef<jobjectArray>& jports) { |
+ std::vector<MessagePort> ports; |
+ if (!jports.is_null()) { |
+ jsize num_ports = env->GetArrayLength(jports.obj()); |
+ for (jsize i = 0; i < num_ports; ++i) { |
+ base::android::ScopedJavaLocalRef<jobject> jport( |
+ env, env->GetObjectArrayElement(jports.obj(), i)); |
+ jlong native_port = |
+ Java_AppWebMessagePort_releaseNativePortForTransfer(env, jport); |
+ // Uninitialized ports should be trapper earlier at the Java layer. |
+ DCHECK(native_port != -1); |
+ AppWebMessagePort* instance = |
+ reinterpret_cast<AppWebMessagePort*>(native_port); |
+ ports.push_back(instance->port_); |
+ } |
+ } |
+ return ports; |
+} |
+ |
+void AppWebMessagePort::CloseMessagePort( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& jcaller) { |
+ // Explicitly reset the port here to ensure that OnMessagesAvailable has |
+ // finished before we destroy this. |
+ port_ = MessagePort(); |
+ |
+ delete this; |
+} |
+ |
+void AppWebMessagePort::PostMessage( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& jcaller, |
+ const base::android::JavaParamRef<jstring>& jmessage, |
+ const base::android::JavaParamRef<jobjectArray>& jports) { |
+ port_.PostMessage( |
+ EncodeStringMessage(base::android::ConvertJavaStringToUTF16(jmessage)), |
+ UnwrapJavaArray(env, jports)); |
+} |
+ |
+void AppWebMessagePort::DispatchReceivedMessages( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& jcaller) { |
+ jmethodID app_web_message_port_constructor = |
+ base::android::MethodID::Get<base::android::MethodID::TYPE_INSTANCE>( |
+ env, AppWebMessagePort_clazz(env), "<init>", "()V"); |
+ |
+ // Consume all of the available messages. |
+ // TODO(darin): Consider breaking this up across multiple PostTask calls. |
+ for (;;) { |
+ base::string16 encoded_message; |
+ std::vector<MessagePort> ports; |
+ if (!port_.GetMessage(&encoded_message, &ports)) |
+ return; |
+ |
+ base::string16 message; |
+ if (!DecodeStringMessage(encoded_message, &message)) |
+ return; |
+ |
+ base::android::ScopedJavaLocalRef<jstring> jmessage = |
+ base::android::ConvertUTF16ToJavaString(env, message); |
+ |
+ base::android::ScopedJavaLocalRef<jobjectArray> jports; |
+ if (ports.size() > 0) { |
+ jports = base::android::ScopedJavaLocalRef<jobjectArray>( |
+ env, |
+ env->NewObjectArray(ports.size(), |
+ AppWebMessagePort_clazz(env), |
+ nullptr)); |
+ |
+ // Instantiate the Java and C++ wrappers for the transferred ports. |
+ for (size_t i = 0; i < ports.size(); ++i) { |
+ base::android::ScopedJavaLocalRef<jobject> jport( |
+ env, |
+ env->NewObject(AppWebMessagePort_clazz(env), |
+ app_web_message_port_constructor)); |
+ CreateAndBindToJavaObject(env, ports[i].ReleaseHandle(), jport); |
+ |
+ env->SetObjectArrayElement(jports.obj(), i, jport.obj()); |
+ } |
+ } |
+ |
+ Java_AppWebMessagePort_onReceivedMessage( |
+ env, java_ref_.get(env), jmessage, jports); |
sgurun-gerrit only
2017/02/08 21:47:50
see comment below about using weak ref.
|
+ } |
+} |
+ |
+void AppWebMessagePort::StartReceivingMessages( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& jcaller) { |
+ port_.SetCallback( |
+ base::Bind(&AppWebMessagePort::OnMessagesAvailable, |
+ base::Unretained(this))); |
+} |
+ |
+AppWebMessagePort::AppWebMessagePort( |
+ JNIEnv* env, |
+ mojo::ScopedMessagePipeHandle handle, |
+ const base::android::JavaRef<jobject>& jobject) |
+ : port_(std::move(handle)), |
+ java_ref_(env, jobject) { |
+} |
+ |
+AppWebMessagePort::~AppWebMessagePort() { |
+} |
+ |
+void AppWebMessagePort::OnMessagesAvailable() { |
+ // Called on the IO thread. |
sgurun-gerrit only
2017/02/08 21:47:50
after moving to Mojo, is this still called on IO t
darin (slow to review)
2017/02/09 00:13:17
Yeah, good catch. This code should not assume that
|
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ Java_AppWebMessagePort_onMessagesAvailable(env, java_ref_.get(env)); |
sgurun-gerrit only
2017/02/08 21:47:50
java_ref_ is weak. I think you need to make sure i
darin (slow to review)
2017/02/09 00:13:17
Done.
|
+} |
+ |
+bool RegisterAppWebMessagePort(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+void InitializeAppWebMessagePortPair( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jclass>& jcaller, |
+ const base::android::JavaParamRef<jobjectArray>& ports) { |
+ DCHECK_EQ(2, env->GetArrayLength(ports.obj())); |
+ |
+ mojo::MessagePipe pipe; |
+ |
+ base::android::ScopedJavaLocalRef<jobject> jport0( |
+ env, env->GetObjectArrayElement(ports.obj(), 0)); |
+ AppWebMessagePort::CreateAndBindToJavaObject( |
+ env, std::move(pipe.handle0), jport0); |
+ |
+ base::android::ScopedJavaLocalRef<jobject> jport1( |
+ env, env->GetObjectArrayElement(ports.obj(), 1)); |
+ AppWebMessagePort::CreateAndBindToJavaObject( |
+ env, std::move(pipe.handle1), jport1); |
+} |
+ |
+} // namespace content |