Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(478)

Side by Side Diff: content/browser/android/app_web_message_port.cc

Issue 2422793002: HTML MessagePort as mojo::MessagePipeHandle (Closed)
Patch Set: Cleanup Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "content/browser/android/app_web_message_port.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "jni/AppWebMessagePort_jni.h"
13
14 namespace content {
15 namespace {
16
17 // To avoid setting up a V8 context here, we just hard code the format for
18 // string type messages. /me ducks!
19
20 const uint32_t kVarIntShift = 7;
21 const uint32_t kVarIntMask = (1 << kVarIntShift) - 1;
22
23 const uint8_t kVersionTag = 0xFF;
24 const uint8_t kStringTag = 'S';
25
26 const uint32_t kVersion = 9;
27
28 void WriteUint8(uint8_t value, std::vector<uint8_t>* buffer) {
29 buffer->push_back(value);
30 }
31
32 void WriteUint32(uint32_t value, std::vector<uint8_t>* buffer) {
33 for (;;) {
34 uint8_t b = (value & kVarIntMask);
35 value >>= kVarIntShift;
36 if (!value) {
37 WriteUint8(b, buffer);
38 break;
39 }
40 WriteUint8(b | (1 << kVarIntShift), buffer);
41 }
42 }
43
44 void WriteBytes(const char* bytes, size_t num_bytes,
45 std::vector<uint8_t>* buffer) {
46 buffer->insert(buffer->end(), bytes, bytes + num_bytes);
47 }
48
49 base::string16 EncodeStringMessage(const base::string16& data) {
50 std::string data_utf8(base::UTF16ToUTF8(data));
51
52 std::vector<uint8_t> buffer;
53 WriteUint8(kVersionTag, &buffer);
54 WriteUint32(kVersion, &buffer);
55
56 WriteUint8(kStringTag, &buffer);
57 WriteUint32(static_cast<uint32_t>(data_utf8.size()), &buffer);
58 WriteBytes(data_utf8.data(), data_utf8.size(), &buffer);
59
60 base::string16 result;
61 size_t result_num_bytes = (buffer.size() + 1) & ~1;
62 result.resize(result_num_bytes / 2);
63 uint8_t* destination = reinterpret_cast<uint8_t*>(&result[0]);
64 memcpy(destination, &buffer[0], buffer.size());
65 if (result_num_bytes > buffer.size())
66 destination[result_num_bytes - 1] = '\0';
67
68 return result;
69 }
70
71 bool ReadUint8(const uint8_t** ptr, const uint8_t* end, uint8_t* value) {
72 if (*ptr >= end)
73 return false;
74 *value = *(*ptr)++;
75 return true;
76 }
77
78 bool ReadUint32(const uint8_t** ptr, const uint8_t* end, uint32_t* value) {
79 *value = 0;
80 uint8_t current_byte;
81 int shift = 0;
82 do {
83 if (*ptr >= end)
84 return false;
85 current_byte = *(*ptr)++;
86 *value |= (static_cast<uint32_t>(current_byte & kVarIntMask) << shift);
87 shift += kVarIntShift;
88 } while (current_byte & (1 << kVarIntShift));
89 return true;
90 }
91
92 bool DecodeStringMessage(const base::string16& encoded_data,
93 base::string16* result) {
94 size_t num_bytes = encoded_data.size() * 2;
95
96 const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&encoded_data[0]);
97 const uint8_t* end = ptr + num_bytes;
98
99 uint8_t tag;
100 if (!ReadUint8(&ptr, end, &tag) || tag != kVersionTag)
101 return false;
102
103 uint32_t version;
104 if (!ReadUint32(&ptr, end, &version))
105 return false;
106
107 if (!ReadUint8(&ptr, end, &tag) || tag != kStringTag)
108 return false;
109
110 uint32_t num_utf8_bytes;
111 if (!ReadUint32(&ptr, end, &num_utf8_bytes))
112 return false;
113
114 const char* utf8_start = reinterpret_cast<const char*>(ptr);
115 return base::UTF8ToUTF16(utf8_start, num_utf8_bytes, result);
116 }
117
118 } // namespace
119
120 // static
121 void AppWebMessagePort::CreateAndBindToJavaObject(
122 JNIEnv* env,
123 mojo::ScopedMessagePipeHandle handle,
124 const base::android::JavaRef<jobject>& jobject) {
125 AppWebMessagePort* instance =
126 new AppWebMessagePort(env, std::move(handle), jobject);
127 Java_AppWebMessagePort_setNativeAppWebMessagePort(
128 env, jobject, reinterpret_cast<jlong>(instance));
129 }
130
131 // static
132 std::vector<MessagePort> AppWebMessagePort::UnwrapJavaArray(
133 JNIEnv* env,
134 const base::android::JavaRef<jobjectArray>& jports) {
135 std::vector<MessagePort> ports;
136 if (!env->IsSameObject(jports.obj(), nullptr)) {
137 jsize num_ports = env->GetArrayLength(jports.obj());
138 for (jsize i = 0; i < num_ports; ++i) {
139 base::android::ScopedJavaLocalRef<jobject> jport(
140 env, env->GetObjectArrayElement(jports.obj(), i));
141 jlong native_port =
142 Java_AppWebMessagePort_releaseNativePortForTransfer(env, jport);
143 // Uninitialized ports should be trapper earlier at the Java layer.
144 DCHECK(native_port != -1);
145 AppWebMessagePort* instance =
146 reinterpret_cast<AppWebMessagePort*>(native_port);
147 ports.push_back(instance->port_);
148 }
149 }
150 return ports;
151 }
152
153 void AppWebMessagePort::CloseMessagePort(
154 JNIEnv* env,
155 const base::android::JavaParamRef<jobject>& jcaller) {
156 // Explicitly reset the port here to ensure that OnMessagesAvailable has
157 // finished before we destroy this.
158 port_ = MessagePort();
159
160 delete this;
161 }
162
163 void AppWebMessagePort::PostMessage(
164 JNIEnv* env,
165 const base::android::JavaParamRef<jobject>& jcaller,
166 const base::android::JavaParamRef<jstring>& jmessage,
167 const base::android::JavaParamRef<jobjectArray>& jports) {
168 port_.PostMessage(
169 EncodeStringMessage(base::android::ConvertJavaStringToUTF16(jmessage)),
170 UnwrapJavaArray(env, jports));
171 }
172
173 void AppWebMessagePort::DispatchReceivedMessages(
174 JNIEnv* env,
175 const base::android::JavaParamRef<jobject>& jcaller) {
176 jmethodID app_web_message_port_constructor =
177 base::android::MethodID::Get<base::android::MethodID::TYPE_INSTANCE>(
178 env, AppWebMessagePort_clazz(env), "<init>", "()V");
179
180 // Consume all of the available messages.
181 // TODO(darin): Consider breaking this up across multiple PostTask calls.
182 for (;;) {
183 base::string16 encoded_message;
184 std::vector<MessagePort> ports;
185 if (!port_.GetMessage(&encoded_message, &ports))
186 return;
187
188 base::string16 message;
189 if (!DecodeStringMessage(encoded_message, &message))
190 return;
191
192 base::android::ScopedJavaLocalRef<jstring> jmessage =
193 base::android::ConvertUTF16ToJavaString(env, message);
194
195 base::android::ScopedJavaLocalRef<jobjectArray> jports;
196 if (ports.size() > 0) {
197 jports = base::android::ScopedJavaLocalRef<jobjectArray>(
198 env,
199 env->NewObjectArray(ports.size(),
200 AppWebMessagePort_clazz(env),
201 nullptr));
202
203 // Instantiate the Java and C++ wrappers for the transferred ports.
204 for (size_t i = 0; i < ports.size(); ++i) {
205 base::android::ScopedJavaLocalRef<jobject> jport(
206 env,
207 env->NewObject(AppWebMessagePort_clazz(env),
208 app_web_message_port_constructor));
209 CreateAndBindToJavaObject(env, ports[i].ReleaseHandle(), jport);
210
211 env->SetObjectArrayElement(jports.obj(), i, jport.obj());
212 }
213 }
214
215 Java_AppWebMessagePort_onReceivedMessage(
216 env, java_ref_.get(env), jmessage, jports);
217 }
218 }
219
220 void AppWebMessagePort::StartReceivingMessages(
221 JNIEnv* env,
222 const base::android::JavaParamRef<jobject>& jcaller) {
223 port_.SetCallback(
224 base::Bind(&AppWebMessagePort::OnMessagesAvailable,
225 base::Unretained(this)));
226 }
227
228 AppWebMessagePort::AppWebMessagePort(
229 JNIEnv* env,
230 mojo::ScopedMessagePipeHandle handle,
231 const base::android::JavaRef<jobject>& jobject)
232 : port_(std::move(handle)),
233 java_ref_(env, jobject) {
234 }
235
236 AppWebMessagePort::~AppWebMessagePort() {
237 }
238
239 void AppWebMessagePort::OnMessagesAvailable() {
240 // Called on the IO thread.
241 JNIEnv* env = base::android::AttachCurrentThread();
242 Java_AppWebMessagePort_onMessagesAvailable(env, java_ref_.get(env));
243 }
244
245 bool RegisterAppWebMessagePort(JNIEnv* env) {
246 return RegisterNativesImpl(env);
247 }
248
249 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698