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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ios/web/webui/mojo_facade.mm
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
new file mode 100644
index 0000000000000000000000000000000000000000..fed5bcc025d60061d8e761eb929a0eb79fb0a423
--- /dev/null
+++ b/ios/web/webui/mojo_facade.mm
@@ -0,0 +1,327 @@
+// Copyright 2016 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.
+
+#import "ios/web/webui/mojo_facade.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/ios/block_types.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/mac/scoped_block.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/values.h"
+#import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
+#include "ios/web/public/web_thread.h"
+#include "mojo/public/c/system/core.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace web {
+
+namespace {
+
+// Wraps Mojo integer into |base::Value| as |TYPE_INTEGER|.
+template <typename MojoIntegerT>
+std::unique_ptr<base::Value> ValueFromMojoInteger(MojoIntegerT handle) {
+ return std::unique_ptr<base::Value>(
+ new base::FundamentalValue(static_cast<int>(handle)));
+}
+
+// Singleton which holds contexts for all currently active watches. Must be used
+// only on UI thread.
+class WatchCallbackHolder {
+ public:
+ static WatchCallbackHolder* GetInstance() {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ return base::Singleton<WatchCallbackHolder>::get();
+ }
+
+ // Adds |callback_block| which must be executed when the Watch callback fires.
+ // Returns context which can be passed to |Run| to execute the block. Callers
+ // are responsible for removing contexts which are no longer active by calling
+ // |Remove|.
+ uintptr_t Add(void (^callback_block)(void)) {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ callbacks_[++last_watch_context_].reset([callback_block copy]);
+ return last_watch_context_;
+ }
+
+ // Executes the callback previously added by calling |Add|. |watch_context| is
+ // the context returned from |Add|. Calling this method for a context which
+ // has been previously removed is no-op.
+ void Run(uintptr_t watch_context) {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ ProceduralBlock callback = callbacks_[watch_context];
+ if (callback)
+ callback();
+ }
+
+ // Removes previously added callback. |watch_context| is the context returned
+ // from |Add|.
+ void Remove(uintptr_t watch_context) {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ DCHECK(callbacks_.find(watch_context) != callbacks_.end());
+ callbacks_.erase(watch_context);
+ }
+
+ private:
+ WatchCallbackHolder() : last_watch_context_(0) {}
+ ~WatchCallbackHolder() {
+ // Clients are responsible for removing all callbacks before shutdown.
+ DCHECK(callbacks_.empty());
+ }
+
+ // Required by base::Singleton.
+ friend struct base::DefaultSingletonTraits<WatchCallbackHolder>;
+
+ // Context for the last added callback. Context for the next callback will be
+ // |last_watch_context_ + 1|.
+ uintptr_t last_watch_context_;
+ // Callbacks added via |Add| method.
+ std::map<uintptr_t, base::mac::ScopedBlock<ProceduralBlock>> callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(WatchCallbackHolder);
+};
+
+// Callback for |MojoWatch| call. Called when:
+// - watched signal has been satisfied;
+// - it became known that none of the watched signals will ever be satisfied;
+// - handle was closed;
+void MojoWatchCallback(uintptr_t watch_context,
+ MojoResult result,
+ struct MojoHandleSignalsState signals_state,
+ MojoWatchNotificationFlags flags) {
+ WatchCallbackHolder::GetInstance()->Run(watch_context);
+}
+
+} // namespace
+
+MojoFacade::MojoFacade(shell::mojom::InterfaceProvider* interface_provider,
+ id<CRWJSInjectionEvaluator> script_evaluator)
+ : interface_provider_(interface_provider),
+ script_evaluator_(script_evaluator) {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ DCHECK(interface_provider_);
+ DCHECK(script_evaluator_);
+}
+
+MojoFacade::~MojoFacade() {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ for (uintptr_t context : watch_contexts_)
+ WatchCallbackHolder::GetInstance()->Remove(context);
+}
+
+std::string MojoFacade::HandleMojoMessage(
+ const std::string& mojo_message_as_json) {
+ DCHECK_CURRENTLY_ON(WebThread::UI);
+ std::string name;
+ std::unique_ptr<base::DictionaryValue> args;
+ GetMessageNameAndArguments(mojo_message_as_json, &name, &args);
+
+ std::unique_ptr<base::Value> result;
+ 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
+ result = HandleServiceProviderConnectToService(args.get());
+ } else if (name == "core.close") {
+ result = HandleCoreClose(args.get());
+ } else if (name == "core.createMessagePipe") {
+ result = HandleCoreCreateMessagePipe(args.get());
+ } else if (name == "core.writeMessage") {
+ result = HandleCoreWriteMessage(args.get());
+ } else if (name == "core.readMessage") {
+ result = HandleCoreReadMessage(args.get());
+ } else if (name == "support.watch") {
+ result = HandleSupportWatch(args.get());
+ }
+
+ if (!result) {
+ return "";
+ }
+
+ std::string json_result;
+ base::JSONWriter::Write(*result, &json_result);
+ return json_result;
+}
+
+void MojoFacade::GetMessageNameAndArguments(
+ const std::string& mojo_message_as_json,
+ std::string* out_name,
+ std::unique_ptr<base::DictionaryValue>* out_args) {
+ int error_code = 0;
+ std::string error_message;
+ std::unique_ptr<base::Value> mojo_message_as_value(
+ base::JSONReader::ReadAndReturnError(mojo_message_as_json, false,
+ &error_code, &error_message));
+ CHECK(!error_code);
+ base::DictionaryValue* mojo_message = nullptr;
+ CHECK(mojo_message_as_value->GetAsDictionary(&mojo_message));
+
+ std::string name;
+ CHECK(mojo_message->GetString("name", &name));
+
+ base::DictionaryValue* args = nullptr;
+ CHECK(mojo_message->GetDictionary("args", &args));
+
+ *out_name = name;
+ *out_args = args->CreateDeepCopy();
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleServiceProviderConnectToService(
+ const base::DictionaryValue* args) {
+ const base::Value* service_name_as_value = nullptr;
+ CHECK(args->Get("serviceName", &service_name_as_value));
+
+ // By design service_provider.connectToService either succeeds or crashes, so
+ // check if service name is a valid string is intentionally omitted.
+ std::string service_name_as_string;
+ service_name_as_value->GetAsString(&service_name_as_string);
+
+ mojo::MessagePipe pipe;
+ interface_provider_->GetInterface(mojo::String::From(service_name_as_string),
+ std::move(pipe.handle0));
+
+ return ValueFromMojoInteger(pipe.handle1.release().value());
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleCoreClose(
+ const base::DictionaryValue* args) {
+ int handle = 0;
+ CHECK(args->GetInteger("handle", &handle));
+
+ return ValueFromMojoInteger(MojoClose(handle));
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleCoreCreateMessagePipe(
+ base::DictionaryValue* args) {
+ const base::Value* options_as_value = nullptr;
+ CHECK(args->Get("optionsDict", &options_as_value));
+
+ std::unique_ptr<MojoCreateMessagePipeOptions> options;
+ if (options_as_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ // Extract options and reset |options| pointer when this codepath is hit.
+ NOTIMPLEMENTED();
+ } else {
+ CHECK(options_as_value->IsType(base::Value::TYPE_NULL));
+ }
+
+ MojoHandle handle0;
+ MojoHandle handle1;
+ MojoCreateMessagePipe(options.get(), &handle0, &handle1);
+
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+ result->SetInteger("handle0", handle0);
+ result->SetInteger("handle1", handle1);
+ return std::unique_ptr<base::Value>(result.release());
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleCoreWriteMessage(
+ base::DictionaryValue* args) {
+ int handle = 0;
+ CHECK(args->GetInteger("handle", &handle));
+
+ base::ListValue* handles_list = nullptr;
+ CHECK(args->GetList("handles", &handles_list));
+
+ base::DictionaryValue* buffer = nullptr;
+ CHECK(args->GetDictionary("buffer", &buffer));
+
+ const base::Value* flags_as_value = nullptr;
+ CHECK(args->Get("flags", &flags_as_value));
+
+ int flags = MOJO_WRITE_MESSAGE_FLAG_NONE;
+ if (!flags_as_value->GetAsInteger(&flags)) {
+ flags = MOJO_WRITE_MESSAGE_FLAG_NONE;
+ }
+
+ std::vector<MojoHandle> handles(handles_list->GetSize());
+ for (size_t i = 0; i < handles_list->GetSize(); i++) {
+ int one_handle = 0;
+ handles_list->GetInteger(i, &one_handle);
+ handles[i] = one_handle;
+ }
+
+ std::vector<uint8_t> bytes(buffer->size());
+ for (size_t i = 0; i < buffer->size(); i++) {
+ int one_byte = 0;
+ buffer->GetInteger(base::IntToString(i), &one_byte);
+ bytes[i] = one_byte;
+ }
+
+ MojoResult result =
+ MojoWriteMessage(static_cast<MojoHandle>(handle), bytes.data(),
+ bytes.size(), handles.data(), handles.size(), flags);
+
+ return ValueFromMojoInteger(result);
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleCoreReadMessage(
+ const base::DictionaryValue* args) {
+ const base::Value* handle_as_value = nullptr;
+ CHECK(args->Get("handle", &handle_as_value));
+ int handle_as_int = 0;
+ if (!handle_as_value->GetAsInteger(&handle_as_int)) {
+ handle_as_int = 0;
+ }
+
+ const base::Value* flags_as_value = nullptr;
+ CHECK(args->Get("flags", &flags_as_value));
+
+ int flags = MOJO_READ_MESSAGE_FLAG_NONE;
+ if (!flags_as_value->GetAsInteger(&flags)) {
+ flags = MOJO_READ_MESSAGE_FLAG_NONE;
+ }
+
+ uint32_t num_bytes = 0;
+ uint32_t num_handles = 0;
+ MojoResult mojo_result =
+ MojoReadMessage(static_cast<MojoHandle>(handle_as_int), nullptr,
+ &num_bytes, nullptr, &num_handles, flags);
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+
+ if (mojo_result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
+ std::vector<uint8_t> bytes(num_bytes);
+ std::vector<MojoHandle> handles(num_handles);
+ mojo_result =
+ MojoReadMessage(static_cast<MojoHandle>(handle_as_int), bytes.data(),
+ &num_bytes, handles.data(), &num_handles, flags);
+
+ base::ListValue* handles_list = new base::ListValue;
+ for (uint32_t i = 0; i < num_handles; i++) {
+ handles_list->AppendInteger(handles[i]);
+ }
+ result->Set("handles", std::unique_ptr<base::Value>(handles_list));
+
+ base::ListValue* buffer = new base::ListValue;
+ for (uint32_t i = 0; i < num_bytes; i++) {
+ buffer->AppendInteger(bytes[i]);
+ }
+ result->Set("buffer", std::unique_ptr<base::Value>(buffer));
+ }
+ result->SetInteger("result", mojo_result);
+
+ return std::unique_ptr<base::Value>(result.release());
+}
+
+std::unique_ptr<base::Value> MojoFacade::HandleSupportWatch(
+ const base::DictionaryValue* args) {
+ int handle = 0;
+ CHECK(args->GetInteger("handle", &handle));
+ int signals = 0;
+ CHECK(args->GetInteger("signals", &signals));
+ std::string callback;
+ CHECK(args->GetString("callback", &callback_id));
+
+ uintptr_t context = WatchCallbackHolder::GetInstance()->Add(^{
+ [script_evaluator_ executeJavaScript:base::SysUTF8ToNSString(callback)
+ completionHandler:nil];
+ });
+
+ watch_contexts_.push_back(context);
+
+ return ValueFromMojoInteger(
+ MojoWatch(handle, signals, &MojoWatchCallback, context));
+}
+
+} // namespace web
« 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