Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/bind_objc_block.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/values.h" | |
| 15 #import "ios/web/public/web_state/js/crw_js_injection_evaluator.h" | |
| 16 #include "ios/web/public/web_thread.h" | |
| 17 #include "mojo/public/cpp/system/core.h" | |
| 18 #include "services/shell/public/interfaces/interface_provider.mojom.h" | |
| 19 | |
| 20 namespace web { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 // Wraps an integer into |base::Value| as |TYPE_INTEGER|. | |
| 25 template <typename IntegerT> | |
| 26 std::unique_ptr<base::Value> ValueFromInteger(IntegerT handle) { | |
| 27 return std::unique_ptr<base::Value>( | |
| 28 new base::FundamentalValue(static_cast<int>(handle))); | |
| 29 } | |
| 30 | |
| 31 } // namespace | |
| 32 | |
| 33 MojoFacade::MojoFacade(shell::mojom::InterfaceProvider* interface_provider, | |
| 34 id<CRWJSInjectionEvaluator> script_evaluator) | |
| 35 : interface_provider_(interface_provider), | |
| 36 script_evaluator_(script_evaluator) { | |
| 37 DCHECK_CURRENTLY_ON(WebThread::UI); | |
| 38 DCHECK(interface_provider_); | |
| 39 DCHECK(script_evaluator_); | |
| 40 } | |
| 41 | |
| 42 MojoFacade::~MojoFacade() { | |
| 43 DCHECK_CURRENTLY_ON(WebThread::UI); | |
| 44 } | |
| 45 | |
| 46 std::string MojoFacade::HandleMojoMessage( | |
| 47 const std::string& mojo_message_as_json) { | |
| 48 DCHECK_CURRENTLY_ON(WebThread::UI); | |
| 49 std::string name; | |
| 50 std::unique_ptr<base::DictionaryValue> args; | |
| 51 GetMessageNameAndArguments(mojo_message_as_json, &name, &args); | |
| 52 | |
| 53 std::unique_ptr<base::Value> result; | |
| 54 if (name == "service_provider.connectToService") { | |
| 55 result = HandleServiceProviderConnectToService(args.get()); | |
| 56 } else if (name == "core.close") { | |
| 57 result = HandleCoreClose(args.get()); | |
| 58 } else if (name == "core.createMessagePipe") { | |
| 59 result = HandleCoreCreateMessagePipe(args.get()); | |
| 60 } else if (name == "core.writeMessage") { | |
| 61 result = HandleCoreWriteMessage(args.get()); | |
| 62 } else if (name == "core.readMessage") { | |
| 63 result = HandleCoreReadMessage(args.get()); | |
| 64 } else if (name == "support.watch") { | |
| 65 result = HandleSupportWatch(args.get()); | |
| 66 } else if (name == "support.cancelWatch") { | |
| 67 result = HandleSupportCancelWatch(args.get()); | |
| 68 } | |
| 69 | |
| 70 if (!result) { | |
| 71 return ""; | |
| 72 } | |
| 73 | |
| 74 std::string json_result; | |
| 75 base::JSONWriter::Write(*result, &json_result); | |
| 76 return json_result; | |
| 77 } | |
| 78 | |
| 79 void MojoFacade::GetMessageNameAndArguments( | |
| 80 const std::string& mojo_message_as_json, | |
| 81 std::string* out_name, | |
| 82 std::unique_ptr<base::DictionaryValue>* out_args) { | |
| 83 int error_code = 0; | |
| 84 std::string error_message; | |
| 85 std::unique_ptr<base::Value> mojo_message_as_value( | |
| 86 base::JSONReader::ReadAndReturnError(mojo_message_as_json, false, | |
| 87 &error_code, &error_message)); | |
| 88 CHECK(!error_code); | |
| 89 base::DictionaryValue* mojo_message = nullptr; | |
| 90 CHECK(mojo_message_as_value->GetAsDictionary(&mojo_message)); | |
| 91 | |
| 92 std::string name; | |
| 93 CHECK(mojo_message->GetString("name", &name)); | |
| 94 | |
| 95 base::DictionaryValue* args = nullptr; | |
| 96 CHECK(mojo_message->GetDictionary("args", &args)); | |
| 97 | |
| 98 *out_name = name; | |
| 99 *out_args = args->CreateDeepCopy(); | |
| 100 } | |
| 101 | |
| 102 std::unique_ptr<base::Value> MojoFacade::HandleServiceProviderConnectToService( | |
| 103 const base::DictionaryValue* args) { | |
| 104 const base::Value* service_name_as_value = nullptr; | |
| 105 CHECK(args->Get("serviceName", &service_name_as_value)); | |
| 106 | |
| 107 // By design service_provider.connectToService either succeeds or crashes, so | |
| 108 // check if service name is a valid string is intentionally omitted. | |
| 109 std::string service_name_as_string; | |
| 110 service_name_as_value->GetAsString(&service_name_as_string); | |
| 111 | |
| 112 mojo::MessagePipe pipe; | |
| 113 interface_provider_->GetInterface(mojo::String::From(service_name_as_string), | |
| 114 std::move(pipe.handle0)); | |
| 115 | |
| 116 return ValueFromInteger(pipe.handle1.release().value()); | |
| 117 } | |
| 118 | |
| 119 std::unique_ptr<base::Value> MojoFacade::HandleCoreClose( | |
| 120 const base::DictionaryValue* args) { | |
| 121 int handle = 0; | |
| 122 CHECK(args->GetInteger("handle", &handle)); | |
| 123 | |
| 124 mojo::Handle(handle).Close(); | |
| 125 | |
| 126 return ValueFromInteger(MOJO_RESULT_OK); | |
| 127 } | |
| 128 | |
| 129 std::unique_ptr<base::Value> MojoFacade::HandleCoreCreateMessagePipe( | |
| 130 base::DictionaryValue* args) { | |
| 131 const base::Value* options_as_value = nullptr; | |
| 132 CHECK(args->Get("optionsDict", &options_as_value)); | |
| 133 | |
| 134 if (options_as_value->IsType(base::Value::TYPE_DICTIONARY)) { | |
| 135 // Extract options when this codepath is hit. | |
|
Ken Rockot(use gerrit already)
2016/05/13 15:21:45
nit: Can you just CHECK that the dictionary is emp
Eugene But (OOO till 7-30)
2016/05/14 00:05:09
Done.
| |
| 136 NOTIMPLEMENTED(); | |
| 137 } | |
| 138 | |
| 139 CHECK(options_as_value->IsType(base::Value::TYPE_NULL)); | |
| 140 | |
| 141 mojo::MessagePipe message_pipe; | |
| 142 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue); | |
| 143 result->SetInteger("handle0", message_pipe.handle0.release().value()); | |
| 144 result->SetInteger("handle1", message_pipe.handle1.release().value()); | |
| 145 return std::unique_ptr<base::Value>(result.release()); | |
| 146 } | |
| 147 | |
| 148 std::unique_ptr<base::Value> MojoFacade::HandleCoreWriteMessage( | |
| 149 base::DictionaryValue* args) { | |
| 150 int handle = 0; | |
| 151 CHECK(args->GetInteger("handle", &handle)); | |
| 152 | |
| 153 base::ListValue* handles_list = nullptr; | |
| 154 CHECK(args->GetList("handles", &handles_list)); | |
| 155 | |
| 156 base::DictionaryValue* buffer = nullptr; | |
| 157 CHECK(args->GetDictionary("buffer", &buffer)); | |
| 158 | |
| 159 const base::Value* flags_as_value = nullptr; | |
| 160 CHECK(args->Get("flags", &flags_as_value)); | |
| 161 | |
| 162 int flags = MOJO_WRITE_MESSAGE_FLAG_NONE; | |
| 163 if (!flags_as_value->GetAsInteger(&flags)) { | |
| 164 flags = MOJO_WRITE_MESSAGE_FLAG_NONE; | |
| 165 } | |
| 166 | |
| 167 std::vector<MojoHandle> handles(handles_list->GetSize()); | |
| 168 for (size_t i = 0; i < handles_list->GetSize(); i++) { | |
| 169 int one_handle = 0; | |
| 170 handles_list->GetInteger(i, &one_handle); | |
| 171 handles[i] = one_handle; | |
| 172 } | |
| 173 | |
| 174 std::vector<uint8_t> bytes(buffer->size()); | |
| 175 for (size_t i = 0; i < buffer->size(); i++) { | |
| 176 int one_byte = 0; | |
| 177 buffer->GetInteger(base::IntToString(i), &one_byte); | |
| 178 bytes[i] = one_byte; | |
| 179 } | |
| 180 | |
| 181 mojo::MessagePipeHandle message_pipe(static_cast<MojoHandle>(handle)); | |
| 182 MojoResult result = | |
| 183 mojo::WriteMessageRaw(message_pipe, bytes.data(), bytes.size(), | |
| 184 handles.data(), handles.size(), flags); | |
| 185 | |
| 186 return ValueFromInteger(result); | |
| 187 } | |
| 188 | |
| 189 std::unique_ptr<base::Value> MojoFacade::HandleCoreReadMessage( | |
| 190 const base::DictionaryValue* args) { | |
| 191 const base::Value* handle_as_value = nullptr; | |
| 192 CHECK(args->Get("handle", &handle_as_value)); | |
| 193 int handle_as_int = 0; | |
| 194 if (!handle_as_value->GetAsInteger(&handle_as_int)) { | |
| 195 handle_as_int = 0; | |
| 196 } | |
| 197 | |
| 198 const base::Value* flags_as_value = nullptr; | |
| 199 CHECK(args->Get("flags", &flags_as_value)); | |
| 200 | |
| 201 int flags = MOJO_READ_MESSAGE_FLAG_NONE; | |
| 202 if (!flags_as_value->GetAsInteger(&flags)) { | |
| 203 flags = MOJO_READ_MESSAGE_FLAG_NONE; | |
| 204 } | |
| 205 | |
| 206 uint32_t num_bytes = 0; | |
| 207 uint32_t num_handles = 0; | |
| 208 mojo::MessagePipeHandle handle(static_cast<MojoHandle>(handle_as_int)); | |
| 209 MojoResult mojo_result = mojo::ReadMessageRaw(handle, nullptr, &num_bytes, | |
| 210 nullptr, &num_handles, flags); | |
| 211 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue); | |
| 212 | |
| 213 if (mojo_result == MOJO_RESULT_RESOURCE_EXHAUSTED) { | |
| 214 std::vector<uint8_t> bytes(num_bytes); | |
| 215 std::vector<MojoHandle> handles(num_handles); | |
| 216 mojo_result = mojo::ReadMessageRaw(handle, bytes.data(), &num_bytes, | |
| 217 handles.data(), &num_handles, flags); | |
| 218 | |
| 219 base::ListValue* handles_list = new base::ListValue; | |
| 220 for (uint32_t i = 0; i < num_handles; i++) { | |
| 221 handles_list->AppendInteger(handles[i]); | |
| 222 } | |
| 223 result->Set("handles", std::unique_ptr<base::Value>(handles_list)); | |
| 224 | |
| 225 base::ListValue* buffer = new base::ListValue; | |
| 226 for (uint32_t i = 0; i < num_bytes; i++) { | |
| 227 buffer->AppendInteger(bytes[i]); | |
| 228 } | |
| 229 result->Set("buffer", std::unique_ptr<base::Value>(buffer)); | |
| 230 } | |
| 231 result->SetInteger("result", mojo_result); | |
| 232 | |
| 233 return std::unique_ptr<base::Value>(result.release()); | |
| 234 } | |
| 235 | |
| 236 std::unique_ptr<base::Value> MojoFacade::HandleSupportWatch( | |
| 237 const base::DictionaryValue* args) { | |
| 238 int handle = 0; | |
| 239 CHECK(args->GetInteger("handle", &handle)); | |
| 240 int signals = 0; | |
| 241 CHECK(args->GetInteger("signals", &signals)); | |
| 242 int callback_id; | |
| 243 CHECK(args->GetInteger("callbackId", &callback_id)); | |
| 244 | |
| 245 mojo::Watcher::ReadyCallback callback = base::BindBlock(^(MojoResult result) { | |
| 246 NSString* script = | |
| 247 [NSString stringWithFormat:@"__crWeb.mojo.signalWatch(%d, %d)", | |
| 248 callback_id, result]; | |
| 249 [script_evaluator_ executeJavaScript:script completionHandler:nil]; | |
| 250 }); | |
| 251 | |
| 252 mojo::Watcher& watcher = watchers_[++last_watch_id_]; | |
| 253 watcher.Start(static_cast<mojo::Handle>(handle), signals, callback); | |
| 254 return ValueFromInteger(last_watch_id_); | |
| 255 } | |
| 256 | |
| 257 std::unique_ptr<base::Value> MojoFacade::HandleSupportCancelWatch( | |
| 258 const base::DictionaryValue* args) { | |
| 259 int watch_id = 0; | |
| 260 CHECK(args->GetInteger("watchId", &watch_id)); | |
| 261 auto watch_it = watchers_.find(watch_id); | |
| 262 if (watch_it != watchers_.end()) { | |
| 263 watch_it->second.Cancel(); | |
|
Ken Rockot(use gerrit already)
2016/05/13 15:21:45
nit: No need to call this explicitly, the Watcher'
Eugene But (OOO till 7-30)
2016/05/14 00:05:09
Cool. Done.
| |
| 264 watchers_.erase(watch_it); | |
| 265 } | |
| 266 return nullptr; | |
| 267 } | |
| 268 | |
| 269 } // namespace web | |
| OLD | NEW |