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

Side by Side Diff: ios/web/webui/mojo_facade.mm

Issue 1956113002: [ios Mojo] iOS facade class for Mojo API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated gyp files Created 4 years, 7 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
« no previous file with comments | « ios/web/webui/mojo_facade.h ('k') | ios/web/webui/mojo_facade_unittest.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #import "ios/web/webui/mojo_facade.h"
6
7 #import <Foundation/Foundation.h>
8
9 #include "base/ios/block_types.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/mac/scoped_block.h"
13 #include "base/memory/singleton.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/values.h"
17 #import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
18 #include "ios/web/public/web_thread.h"
19 #include "mojo/public/c/system/core.h"
20 #include "services/shell/public/interfaces/interface_provider.mojom.h"
21
22 namespace web {
23
24 namespace {
25
26 // Wraps Mojo integer into |base::Value| as |TYPE_INTEGER|.
27 template <typename MojoIntegerT>
28 std::unique_ptr<base::Value> ValueFromMojoInteger(MojoIntegerT handle) {
29 return std::unique_ptr<base::Value>(
30 new base::FundamentalValue(static_cast<int>(handle)));
31 }
32
33 // Singleton which holds contexts for all currently active watches. Must be used
34 // only on UI thread.
35 class WatchCallbackHolder {
36 public:
37 static WatchCallbackHolder* GetInstance() {
38 DCHECK_CURRENTLY_ON(WebThread::UI);
39 return base::Singleton<WatchCallbackHolder>::get();
40 }
41
42 // Adds |callback_block| which must be executed when the Watch callback fires.
43 // Returns context which can be passed to |Run| to execute the block. Callers
44 // are responsible for removing contexts which are no longer active by calling
45 // |Remove|.
46 uintptr_t Add(void (^callback_block)(void)) {
47 DCHECK_CURRENTLY_ON(WebThread::UI);
48 callbacks_[++last_watch_context_].reset([callback_block copy]);
49 return last_watch_context_;
50 }
51
52 // Executes the callback previously added by calling |Add|. |watch_context| is
53 // the context returned from |Add|. Calling this method for a context which
54 // has been previously removed is no-op.
55 void Run(uintptr_t watch_context) {
56 DCHECK_CURRENTLY_ON(WebThread::UI);
57 ProceduralBlock callback = callbacks_[watch_context];
58 if (callback)
59 callback();
60 }
61
62 // Removes previously added callback. |watch_context| is the context returned
63 // from |Add|.
64 void Remove(uintptr_t watch_context) {
65 DCHECK_CURRENTLY_ON(WebThread::UI);
66 DCHECK(callbacks_.find(watch_context) != callbacks_.end());
67 callbacks_.erase(watch_context);
68 }
69
70 private:
71 WatchCallbackHolder() : last_watch_context_(0) {}
72 ~WatchCallbackHolder() {
73 // Clients are responsible for removing all callbacks before shutdown.
74 DCHECK(callbacks_.empty());
75 }
76
77 // Required by base::Singleton.
78 friend struct base::DefaultSingletonTraits<WatchCallbackHolder>;
79
80 // Context for the last added callback. Context for the next callback will be
81 // |last_watch_context_ + 1|.
82 uintptr_t last_watch_context_;
83 // Callbacks added via |Add| method.
84 std::map<uintptr_t, base::mac::ScopedBlock<ProceduralBlock>> callbacks_;
85
86 DISALLOW_COPY_AND_ASSIGN(WatchCallbackHolder);
87 };
88
89 // Callback for |MojoWatch| call. Called when:
90 // - watched signal has been satisfied;
91 // - it became known that none of the watched signals will ever be satisfied;
92 // - handle was closed;
93 void MojoWatchCallback(uintptr_t watch_context,
94 MojoResult result,
95 struct MojoHandleSignalsState signals_state,
96 MojoWatchNotificationFlags flags) {
97 WatchCallbackHolder::GetInstance()->Run(watch_context);
98 }
99
100 } // namespace
101
102 MojoFacade::MojoFacade(shell::mojom::InterfaceProvider* interface_provider,
103 id<CRWJSInjectionEvaluator> script_evaluator)
104 : interface_provider_(interface_provider),
105 script_evaluator_(script_evaluator) {
106 DCHECK_CURRENTLY_ON(WebThread::UI);
107 DCHECK(interface_provider_);
108 DCHECK(script_evaluator_);
109 }
110
111 MojoFacade::~MojoFacade() {
112 DCHECK_CURRENTLY_ON(WebThread::UI);
113 for (uintptr_t context : watch_contexts_)
114 WatchCallbackHolder::GetInstance()->Remove(context);
115 }
116
117 std::string MojoFacade::HandleMojoMessage(
118 const std::string& mojo_message_as_json) {
119 DCHECK_CURRENTLY_ON(WebThread::UI);
120 std::string name;
121 std::unique_ptr<base::DictionaryValue> args;
122 GetMessageNameAndArguments(mojo_message_as_json, &name, &args);
123
124 std::unique_ptr<base::Value> result;
125 if (name == "service_provider.connectToService") {
Ken Rockot(use gerrit already) 2016/05/12 21:13:05 I mean I guess efficiency is already tossed out be
Eugene But (OOO till 7-30) 2016/05/13 02:54:26 I doubt that you will see any performance differen
126 result = HandleServiceProviderConnectToService(args.get());
127 } else if (name == "core.close") {
128 result = HandleCoreClose(args.get());
129 } else if (name == "core.createMessagePipe") {
130 result = HandleCoreCreateMessagePipe(args.get());
131 } else if (name == "core.writeMessage") {
132 result = HandleCoreWriteMessage(args.get());
133 } else if (name == "core.readMessage") {
134 result = HandleCoreReadMessage(args.get());
135 } else if (name == "support.watch") {
136 result = HandleSupportWatch(args.get());
137 }
138
139 if (!result) {
140 return "";
141 }
142
143 std::string json_result;
144 base::JSONWriter::Write(*result, &json_result);
145 return json_result;
146 }
147
148 void MojoFacade::GetMessageNameAndArguments(
149 const std::string& mojo_message_as_json,
150 std::string* out_name,
151 std::unique_ptr<base::DictionaryValue>* out_args) {
152 int error_code = 0;
153 std::string error_message;
154 std::unique_ptr<base::Value> mojo_message_as_value(
155 base::JSONReader::ReadAndReturnError(mojo_message_as_json, false,
156 &error_code, &error_message));
157 CHECK(!error_code);
158 base::DictionaryValue* mojo_message = nullptr;
159 CHECK(mojo_message_as_value->GetAsDictionary(&mojo_message));
160
161 std::string name;
162 CHECK(mojo_message->GetString("name", &name));
163
164 base::DictionaryValue* args = nullptr;
165 CHECK(mojo_message->GetDictionary("args", &args));
166
167 *out_name = name;
168 *out_args = args->CreateDeepCopy();
169 }
170
171 std::unique_ptr<base::Value> MojoFacade::HandleServiceProviderConnectToService(
172 const base::DictionaryValue* args) {
173 const base::Value* service_name_as_value = nullptr;
174 CHECK(args->Get("serviceName", &service_name_as_value));
175
176 // By design service_provider.connectToService either succeeds or crashes, so
177 // check if service name is a valid string is intentionally omitted.
178 std::string service_name_as_string;
179 service_name_as_value->GetAsString(&service_name_as_string);
180
181 mojo::MessagePipe pipe;
182 interface_provider_->GetInterface(mojo::String::From(service_name_as_string),
183 std::move(pipe.handle0));
184
185 return ValueFromMojoInteger(pipe.handle1.release().value());
186 }
187
188 std::unique_ptr<base::Value> MojoFacade::HandleCoreClose(
189 const base::DictionaryValue* args) {
190 int handle = 0;
191 CHECK(args->GetInteger("handle", &handle));
192
193 return ValueFromMojoInteger(MojoClose(handle));
194 }
195
196 std::unique_ptr<base::Value> MojoFacade::HandleCoreCreateMessagePipe(
197 base::DictionaryValue* args) {
198 const base::Value* options_as_value = nullptr;
199 CHECK(args->Get("optionsDict", &options_as_value));
200
201 std::unique_ptr<MojoCreateMessagePipeOptions> options;
202 if (options_as_value->IsType(base::Value::TYPE_DICTIONARY)) {
203 // Extract options and reset |options| pointer when this codepath is hit.
204 NOTIMPLEMENTED();
205 } else {
206 CHECK(options_as_value->IsType(base::Value::TYPE_NULL));
207 }
208
209 MojoHandle handle0;
210 MojoHandle handle1;
211 MojoCreateMessagePipe(options.get(), &handle0, &handle1);
212
213 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
214 result->SetInteger("handle0", handle0);
215 result->SetInteger("handle1", handle1);
216 return std::unique_ptr<base::Value>(result.release());
217 }
218
219 std::unique_ptr<base::Value> MojoFacade::HandleCoreWriteMessage(
220 base::DictionaryValue* args) {
221 int handle = 0;
222 CHECK(args->GetInteger("handle", &handle));
223
224 base::ListValue* handles_list = nullptr;
225 CHECK(args->GetList("handles", &handles_list));
226
227 base::DictionaryValue* buffer = nullptr;
228 CHECK(args->GetDictionary("buffer", &buffer));
229
230 const base::Value* flags_as_value = nullptr;
231 CHECK(args->Get("flags", &flags_as_value));
232
233 int flags = MOJO_WRITE_MESSAGE_FLAG_NONE;
234 if (!flags_as_value->GetAsInteger(&flags)) {
235 flags = MOJO_WRITE_MESSAGE_FLAG_NONE;
236 }
237
238 std::vector<MojoHandle> handles(handles_list->GetSize());
239 for (size_t i = 0; i < handles_list->GetSize(); i++) {
240 int one_handle = 0;
241 handles_list->GetInteger(i, &one_handle);
242 handles[i] = one_handle;
243 }
244
245 std::vector<uint8_t> bytes(buffer->size());
246 for (size_t i = 0; i < buffer->size(); i++) {
247 int one_byte = 0;
248 buffer->GetInteger(base::IntToString(i), &one_byte);
249 bytes[i] = one_byte;
250 }
251
252 MojoResult result =
253 MojoWriteMessage(static_cast<MojoHandle>(handle), bytes.data(),
254 bytes.size(), handles.data(), handles.size(), flags);
255
256 return ValueFromMojoInteger(result);
257 }
258
259 std::unique_ptr<base::Value> MojoFacade::HandleCoreReadMessage(
260 const base::DictionaryValue* args) {
261 const base::Value* handle_as_value = nullptr;
262 CHECK(args->Get("handle", &handle_as_value));
263 int handle_as_int = 0;
264 if (!handle_as_value->GetAsInteger(&handle_as_int)) {
265 handle_as_int = 0;
266 }
267
268 const base::Value* flags_as_value = nullptr;
269 CHECK(args->Get("flags", &flags_as_value));
270
271 int flags = MOJO_READ_MESSAGE_FLAG_NONE;
272 if (!flags_as_value->GetAsInteger(&flags)) {
273 flags = MOJO_READ_MESSAGE_FLAG_NONE;
274 }
275
276 uint32_t num_bytes = 0;
277 uint32_t num_handles = 0;
278 MojoResult mojo_result =
279 MojoReadMessage(static_cast<MojoHandle>(handle_as_int), nullptr,
280 &num_bytes, nullptr, &num_handles, flags);
281 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
282
283 if (mojo_result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
284 std::vector<uint8_t> bytes(num_bytes);
285 std::vector<MojoHandle> handles(num_handles);
286 mojo_result =
287 MojoReadMessage(static_cast<MojoHandle>(handle_as_int), bytes.data(),
288 &num_bytes, handles.data(), &num_handles, flags);
289
290 base::ListValue* handles_list = new base::ListValue;
291 for (uint32_t i = 0; i < num_handles; i++) {
292 handles_list->AppendInteger(handles[i]);
293 }
294 result->Set("handles", std::unique_ptr<base::Value>(handles_list));
295
296 base::ListValue* buffer = new base::ListValue;
297 for (uint32_t i = 0; i < num_bytes; i++) {
298 buffer->AppendInteger(bytes[i]);
299 }
300 result->Set("buffer", std::unique_ptr<base::Value>(buffer));
301 }
302 result->SetInteger("result", mojo_result);
303
304 return std::unique_ptr<base::Value>(result.release());
305 }
306
307 std::unique_ptr<base::Value> MojoFacade::HandleSupportWatch(
308 const base::DictionaryValue* args) {
309 int handle = 0;
310 CHECK(args->GetInteger("handle", &handle));
311 int signals = 0;
312 CHECK(args->GetInteger("signals", &signals));
313 std::string callback;
314 CHECK(args->GetString("callback", &callback_id));
315
316 uintptr_t context = WatchCallbackHolder::GetInstance()->Add(^{
317 [script_evaluator_ executeJavaScript:base::SysUTF8ToNSString(callback)
318 completionHandler:nil];
319 });
320
321 watch_contexts_.push_back(context);
322
323 return ValueFromMojoInteger(
324 MojoWatch(handle, signals, &MojoWatchCallback, context));
325 }
326
327 } // namespace web
OLDNEW
« no previous file with comments | « ios/web/webui/mojo_facade.h ('k') | ios/web/webui/mojo_facade_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698