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

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

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

Powered by Google App Engine
This is Rietveld 408576698