diff options
author | kelvinp <kelvinp@chromium.org> | 2014-10-07 14:49:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-07 21:50:09 +0000 |
commit | 3b73f509613829b8b0719ee739292228a83c00ac (patch) | |
tree | cdfe05d42e75e712d41e911b80671e831c12169e | |
parent | d57fab48d959e58fc0b1e643eed05be7927b2318 (diff) | |
download | chromium_src-3b73f509613829b8b0719ee739292228a83c00ac.zip chromium_src-3b73f509613829b8b0719ee739292228a83c00ac.tar.gz chromium_src-3b73f509613829b8b0719ee739292228a83c00ac.tar.bz2 |
Remote Assistance on Chrome OS Part III - NativeMessageHost
This CL extracts the NativeMessageHost interface from the NativeMessageProcessHost
A NativeMessageHost hosts a native component, which can be
running in the same process as chrome or in a separate
process.
Committed: https://crrev.com/ba722a2a8ddf967dcadb483ea32d5ad31fc4bdf6
Cr-Commit-Position: refs/heads/master@{#298366}
Review URL: https://codereview.chromium.org/591463003
Cr-Commit-Position: refs/heads/master@{#298579}
28 files changed, 759 insertions, 309 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 4fe90bd..4603928 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -13863,6 +13863,12 @@ Do you accept? <message name="IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_DESCRIPTION" desc="Description of about::flags option to enable experimental features for IME input-views"> Enable experimental features for IME input views. </message> + <message name="IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_NAME" desc="Name of about::flags option to enable remote assistance on Chrome OS"> + Enable Remote Assistance + </message> + <message name="IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_DESCRIPTION" desc="Description of about::flags option to enable remote assistance on Chrome OS."> + Accepts remote assistance connections to this machine via the Chrome Remote Desktop app. + </message> </if> <!-- Simple Cache Backend experiment. --> diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 4549449..413ff41 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -1961,7 +1961,15 @@ const Experiment kExperiments[] = { SINGLE_VALUE_TYPE(switches::kEnablePluginPowerSaver) }, #endif - +#if defined(OS_CHROMEOS) + { + "enable-remote-assistance", + IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_NAME, + IDS_FLAGS_ENABLE_REMOTE_ASSISTANCE_DESCRIPTION, + kOsCrOS, + SINGLE_VALUE_TYPE(extensions::switches::kEnableRemoteAssistance) + }, +#endif // defined(OS_CHROMEOS) // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc index b648089..fb72711 100644 --- a/chrome/browser/extensions/api/messaging/message_service.cc +++ b/chrome/browser/extensions/api/messaging/message_service.cc @@ -10,6 +10,7 @@ #include "base/json/json_writer.h" #include "base/lazy_instance.h" #include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" #include "base/stl_util.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" @@ -33,6 +34,7 @@ #include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/lazy_background_task_queue.h" +#include "extensions/browser/pref_names.h" #include "extensions/browser/process_manager.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_constants.h" @@ -61,6 +63,44 @@ using content::WebContents; namespace extensions { +MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed( + const PrefService* pref_service, + const std::string& native_host_name) { + PolicyPermission allow_result = ALLOW_ALL; + if (pref_service->IsManagedPreference( + pref_names::kNativeMessagingUserLevelHosts)) { + if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts)) + allow_result = ALLOW_SYSTEM_ONLY; + } + + // All native messaging hosts are allowed if there is no blacklist. + if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist)) + return allow_result; + const base::ListValue* blacklist = + pref_service->GetList(pref_names::kNativeMessagingBlacklist); + if (!blacklist) + return allow_result; + + // Check if the name or the wildcard is in the blacklist. + base::StringValue name_value(native_host_name); + base::StringValue wildcard_value("*"); + if (blacklist->Find(name_value) == blacklist->end() && + blacklist->Find(wildcard_value) == blacklist->end()) { + return allow_result; + } + + // The native messaging host is blacklisted. Check the whitelist. + if (pref_service->IsManagedPreference( + pref_names::kNativeMessagingWhitelist)) { + const base::ListValue* whitelist = + pref_service->GetList(pref_names::kNativeMessagingWhitelist); + if (whitelist && whitelist->Find(name_value) != whitelist->end()) + return allow_result; + } + + return DISALLOW; +} + const char kReceivingEndDoesntExistError[] = "Could not establish connection. Receiving end does not exist."; #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) @@ -371,9 +411,9 @@ void MessageService::OpenChannelToNativeApp( PrefService* pref_service = profile->GetPrefs(); // Verify that the host is not blocked by policies. - NativeMessageProcessHost::PolicyPermission policy_permission = - NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name); - if (policy_permission == NativeMessageProcessHost::DISALLOW) { + PolicyPermission policy_permission = + IsNativeMessagingHostAllowed(pref_service, native_app_name); + if (policy_permission == DISALLOW) { DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError); return; } @@ -387,22 +427,23 @@ void MessageService::OpenChannelToNativeApp( content::RenderWidgetHost::FromID(source_process_id, source_routing_id)-> GetView()->GetNativeView(); - scoped_ptr<NativeMessageProcessHost> native_process = - NativeMessageProcessHost::Create( - native_view, - base::WeakPtr<NativeMessageProcessHost::Client>( - weak_factory_.GetWeakPtr()), - source_extension_id, native_app_name, receiver_port_id, - policy_permission == NativeMessageProcessHost::ALLOW_ALL); + std::string error = kReceivingEndDoesntExistError; + scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create( + native_view, + source_extension_id, + native_app_name, + policy_permission == ALLOW_ALL, + &error); // Abandon the channel. - if (!native_process.get()) { + if (!native_host.get()) { LOG(ERROR) << "Failed to create native process."; DispatchOnDisconnect( - source, receiver_port_id, kReceivingEndDoesntExistError); + source, receiver_port_id, error); return; } - channel->receiver.reset(new NativeMessagePort(native_process.release())); + channel->receiver.reset(new NativeMessagePort( + weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass())); // Keep the opener alive until the channel is closed. channel->opener->IncrementLazyKeepaliveCount(); @@ -562,11 +603,6 @@ void MessageService::PostMessage(int source_port_id, const Message& message) { DispatchMessage(source_port_id, iter->second, message); } -void MessageService::PostMessageFromNativeProcess(int port_id, - const std::string& message) { - PostMessage(port_id, Message(message, false /* user_gesture */)); -} - void MessageService::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h index 2fc5e80..23bf7e8 100644 --- a/chrome/browser/extensions/api/messaging/message_service.h +++ b/chrome/browser/extensions/api/messaging/message_service.h @@ -14,9 +14,9 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/extensions/api/messaging/message_property_provider.h" -#include "chrome/browser/extensions/api/messaging/native_message_process_host.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/common/api/messaging/message.h" @@ -60,8 +60,7 @@ class LazyBackgroundTaskQueue; // case that the port is a tab). The Process is usually either a // RenderProcessHost or a RenderViewHost. class MessageService : public BrowserContextKeyedAPI, - public content::NotificationObserver, - public NativeMessageProcessHost::Client { + public content::NotificationObserver { public: // A messaging channel. Note that the opening port can be the same as the // receiver, if an extension background page wants to talk to its tab (for @@ -105,6 +104,16 @@ class MessageService : public BrowserContextKeyedAPI, DISALLOW_COPY_AND_ASSIGN(MessagePort); }; + enum PolicyPermission { + DISALLOW, // The host is not allowed. + ALLOW_SYSTEM_ONLY, // Allowed only when installed on system level. + ALLOW_ALL, // Allowed when installed on system or user level. + }; + + static PolicyPermission IsNativeMessagingHostAllowed( + const PrefService* pref_service, + const std::string& native_host_name); + // Allocates a pair of port ids. // NOTE: this can be called from any thread. static void AllocatePortIdPair(int* port1, int* port2); @@ -146,18 +155,12 @@ class MessageService : public BrowserContextKeyedAPI, // Closes the message channel associated with the given port, and notifies // the other side. - virtual void CloseChannel(int port_id, - const std::string& error_message) override; + void CloseChannel(int port_id, const std::string& error_message); // Enqueues a message on a pending channel, or sends a message to the given // port if the channel isn't pending. void PostMessage(int port_id, const Message& message); - // NativeMessageProcessHost::Client - virtual void PostMessageFromNativeProcess( - int port_id, - const std::string& message) override; - private: friend class MockMessageService; friend class BrowserContextKeyedAPIFactory<MessageService>; diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc new file mode 100644 index 0000000..e42b014 --- /dev/null +++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc @@ -0,0 +1,155 @@ +// Copyright 2014 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. + +#include "extensions/browser/api/messaging/native_message_host.h" + +#include <string> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/location.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/values.h" +#include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h" +#include "extensions/common/constants.h" +#include "extensions/common/url_pattern.h" +#include "ui/gfx/native_widget_types.h" +#include "url/gurl.h" + +namespace extensions { + +namespace { + +// A simple NativeMesageHost that echoes the received message. It is currently +// used for testing. +// TODO(kelvinp): Replace this class once Remote Assistance in process host +// is implemented. + +const char* const kEchoHostOrigins[] = { + // ScopedTestNativeMessagingHost::kExtensionId + "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"}; + +class EchoHost : public NativeMessageHost { + public: + static scoped_ptr<NativeMessageHost> Create() { + return scoped_ptr<NativeMessageHost>(new EchoHost()); + } + + EchoHost() : message_number_(0), client_(NULL) {} + + virtual void Start(Client* client) OVERRIDE { + client_ = client; + } + + virtual void OnMessage(const std::string& request_string) OVERRIDE { + scoped_ptr<base::Value> request_value( + base::JSONReader::Read(request_string)); + scoped_ptr<base::DictionaryValue> request( + static_cast<base::DictionaryValue*>(request_value.release())); + if (request_string.find("stopHostTest") != std::string::npos) { + client_->CloseChannel(kNativeHostExited); + } else if (request_string.find("bigMessageTest") != std::string::npos) { + client_->CloseChannel(kHostInputOuputError); + } else { + ProcessEcho(*request); + } + }; + + virtual scoped_refptr<base::SingleThreadTaskRunner> task_runner() + const OVERRIDE { + return base::MessageLoopProxy::current(); + }; + + private: + void ProcessEcho(const base::DictionaryValue& request) { + scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); + response->SetInteger("id", ++message_number_); + response->Set("echo", request.DeepCopy()); + response->SetString("caller_url", kEchoHostOrigins[0]); + std::string response_string; + base::JSONWriter::Write(response.get(), &response_string); + client_->PostMessageFromNativeHost(response_string); + } + + int message_number_; + Client* client_; + + DISALLOW_COPY_AND_ASSIGN(EchoHost); +}; + +struct BuiltInHost { + const char* const name; + const char* const* const allowed_origins; + int allowed_origins_count; + scoped_ptr<NativeMessageHost>(*create_function)(); +}; + +// If you modify the list of allowed_origins, don't forget to update +// remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 +// to keep the two lists in sync. +// TODO(kelvinp): Load the native messaging manifest as a resource file into +// chrome and fetch the list of allowed_origins from the manifest. +/*const char* const kRemotingIt2MeOrigins[] = { + "chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/", + "chrome-extension://gbchcmhmhahfdphkhkmpfmihenigjmpp/", + "chrome-extension://kgngmbheleoaphbjbaiobfdepmghbfah/", + "chrome-extension://odkaodonbgfohohmklejpjiejmcipmib/", + "chrome-extension://dokpleeekgeeiehdhmdkeimnkmoifgdd/", + "chrome-extension://ajoainacpilcemgiakehflpbkbfipojk/", + "chrome-extension://hmboipgjngjoiaeicfdifdoeacilalgc/"};*/ + +static const BuiltInHost kBuiltInHost[] = { + {"com.google.chrome.test.echo", // ScopedTestNativeMessagingHost::kHostName + kEchoHostOrigins, + arraysize(kEchoHostOrigins), + &EchoHost::Create}, +}; + +bool MatchesSecurityOrigin(const BuiltInHost& host, + const std::string& extension_id) { + GURL origin(std::string(kExtensionScheme) + "://" + extension_id); + for (int i = 0; i < host.allowed_origins_count; i++) { + URLPattern allowed_origin(URLPattern::SCHEME_ALL); + DCHECK_EQ(URLPattern::PARSE_SUCCESS, + allowed_origin.Parse(host.allowed_origins[i])); + LOG(ERROR) << "allowed_origin is " << allowed_origin.GetAsString() + << " and extension_id is " << extension_id; + if (allowed_origin.MatchesSecurityOrigin(origin)) { + LOG(ERROR) << "Pattern matched"; + return true; + } + } + LOG(ERROR) << "Pattern mismatched"; + return false; +} + +} // namespace + +scoped_ptr<NativeMessageHost> NativeMessageHost::Create( + gfx::NativeView native_view, + const std::string& source_extension_id, + const std::string& native_host_name, + bool allow_user_level, + std::string* error) { + for (unsigned int i = 0; i < arraysize(kBuiltInHost); i++) { + const BuiltInHost& host = kBuiltInHost[i]; + std::string name(host.name); + if (name == native_host_name) { + if (MatchesSecurityOrigin(host, source_extension_id)) { + return (*host.create_function)(); + } + *error = kForbiddenError; + return nullptr; + } + } + *error = kNotFoundError; + return nullptr; +} + +} // namespace extensions diff --git a/chrome/browser/extensions/api/messaging/native_message_port.cc b/chrome/browser/extensions/api/messaging/native_message_port.cc index a0a47d5..66b1674 100644 --- a/chrome/browser/extensions/api/messaging/native_message_port.cc +++ b/chrome/browser/extensions/api/messaging/native_message_port.cc @@ -5,27 +5,120 @@ #include "chrome/browser/extensions/api/messaging/native_message_port.h" #include "base/bind.h" +#include "base/single_thread_task_runner.h" #include "chrome/browser/extensions/api/messaging/native_message_process_host.h" #include "content/public/browser/browser_thread.h" namespace extensions { -NativeMessagePort::NativeMessagePort(NativeMessageProcessHost* native_process) - : native_process_(native_process) { +// Handles jumping between the |host_task_runner| and the +// |message_service_task_runner|. +// All methods on the host interface should be called on |host_task_runner|. +// All methods on |port| (that calls into MessageServices) should be called +// on |message_service_task_runner|. +class NativeMessagePort::Core : public NativeMessageHost::Client { + public: + Core( + scoped_ptr<NativeMessageHost> host, + base::WeakPtr<NativeMessagePort> port, + scoped_refptr<base::SingleThreadTaskRunner> message_service_task_runner_); + virtual ~Core(); + + void OnMessageFromChrome(const std::string& message); + + // NativeMessageHost::Client implementation. + virtual void PostMessageFromNativeHost(const std::string& message) OVERRIDE; + virtual void CloseChannel(const std::string& error_message) OVERRIDE; + + private: + scoped_ptr<NativeMessageHost> host_; + base::WeakPtr<NativeMessagePort> port_; + + scoped_refptr<base::SingleThreadTaskRunner> message_service_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> host_task_runner_; +}; + +NativeMessagePort::Core::Core( + scoped_ptr<NativeMessageHost> host, + base::WeakPtr<NativeMessagePort> port, + scoped_refptr<base::SingleThreadTaskRunner> message_service_task_runner) + : host_(host.Pass()), + port_(port), + message_service_task_runner_(message_service_task_runner), + host_task_runner_(host_->task_runner()) { + DCHECK(message_service_task_runner_->BelongsToCurrentThread()); + host_task_runner_->PostTask(FROM_HERE, + base::Bind(&NativeMessageHost::Start, + base::Unretained(host_.get()), + base::Unretained(this))); +} + +NativeMessagePort::Core::~Core() { + DCHECK(host_task_runner_->BelongsToCurrentThread()); +} + +void NativeMessagePort::Core::OnMessageFromChrome(const std::string& message) { + DCHECK(message_service_task_runner_->BelongsToCurrentThread()); + host_task_runner_->PostTask(FROM_HERE, + base::Bind(&NativeMessageHost::OnMessage, + base::Unretained(host_.get()), + message)); +} + +void NativeMessagePort::Core::PostMessageFromNativeHost( + const std::string& message) { + DCHECK(host_task_runner_->BelongsToCurrentThread()); + message_service_task_runner_->PostTask( + FROM_HERE, + base::Bind( + &NativeMessagePort::PostMessageFromNativeHost, port_, message)); +} + +void NativeMessagePort::Core::CloseChannel(const std::string& error_message) { + DCHECK(host_task_runner_->BelongsToCurrentThread()); + message_service_task_runner_->PostTask( + FROM_HERE, + base::Bind(&NativeMessagePort::CloseChannel, port_, error_message)); +} + +NativeMessagePort::NativeMessagePort( + base::WeakPtr<MessageService> message_service, + int port_id, + scoped_ptr<NativeMessageHost> native_message_host) + : weak_message_service_(message_service), + host_task_runner_(native_message_host->task_runner()), + port_id_(port_id), + weak_factory_(this) { + core_.reset(new Core(native_message_host.Pass(), + weak_factory_.GetWeakPtr(), + base::MessageLoopProxy::current())); } NativeMessagePort::~NativeMessagePort() { - content::BrowserThread::DeleteSoon( - content::BrowserThread::IO, FROM_HERE, native_process_); + DCHECK(thread_checker_.CalledOnValidThread()); + host_task_runner_->DeleteSoon(FROM_HERE, core_.release()); } void NativeMessagePort::DispatchOnMessage( const Message& message, int target_port_id) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&NativeMessageProcessHost::Send, - base::Unretained(native_process_), message.data)); + DCHECK(thread_checker_.CalledOnValidThread()); + core_->OnMessageFromChrome(message.data); +} + +void NativeMessagePort::PostMessageFromNativeHost(const std::string& message) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (weak_message_service_) { + weak_message_service_->PostMessage( + port_id_, Message(message, false /* user_gesture */)); + } +} + +void NativeMessagePort::CloseChannel(const std::string& error_message) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (weak_message_service_) { + weak_message_service_->CloseChannel(port_id_, error_message); + } } } // namespace extensions diff --git a/chrome/browser/extensions/api/messaging/native_message_port.h b/chrome/browser/extensions/api/messaging/native_message_port.h index b3f7605..65711ae 100644 --- a/chrome/browser/extensions/api/messaging/native_message_port.h +++ b/chrome/browser/extensions/api/messaging/native_message_port.h @@ -5,22 +5,36 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGE_PORT_H_ #define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGE_PORT_H_ +#include "base/threading/thread_checker.h" #include "chrome/browser/extensions/api/messaging/message_service.h" namespace extensions { class NativeMessageProcessHost; // A port that manages communication with a native application. +// All methods must be called on the UI Thread of the browser process. class NativeMessagePort : public MessageService::MessagePort { public: - // Takes ownership of |native_process|. - explicit NativeMessagePort(NativeMessageProcessHost* native_process); + NativeMessagePort(base::WeakPtr<MessageService> message_service, + int port_id, + scoped_ptr<NativeMessageHost> native_message_host); virtual ~NativeMessagePort(); + + // MessageService::MessagePort implementation. virtual void DispatchOnMessage(const Message& message, int target_port_id) override; - private: - NativeMessageProcessHost* native_process_; + class Core; + void PostMessageFromNativeHost(const std::string& message); + void CloseChannel(const std::string& error_message); + + base::ThreadChecker thread_checker_; + base::WeakPtr<MessageService> weak_message_service_; + scoped_refptr<base::SingleThreadTaskRunner> host_task_runner_; + int port_id_; + scoped_ptr<Core> core_; + + base::WeakPtrFactory<NativeMessagePort> weak_factory_; }; } // namespace extensions diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc index 7d7e37f..bc3808a 100644 --- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc +++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc @@ -7,15 +7,12 @@ #include "base/bind.h" #include "base/files/file_path.h" #include "base/logging.h" -#include "base/prefs/pref_service.h" #include "base/process/kill.h" #include "base/threading/sequenced_worker_pool.h" -#include "base/values.h" #include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h" #include "chrome/browser/extensions/api/messaging/native_process_launcher.h" #include "chrome/common/chrome_version_info.h" #include "content/public/browser/browser_thread.h" -#include "extensions/browser/pref_names.h" #include "extensions/common/constants.h" #include "extensions/common/features/feature.h" #include "net/base/file_stream.h" @@ -37,69 +34,16 @@ const size_t kMessageHeaderSize = 4; // Size of the buffer to be allocated for each read. const size_t kReadBufferSize = 4096; -const char kFailedToStartError[] = "Failed to start native messaging host."; -const char kInvalidNameError[] = - "Invalid native messaging host name specified."; -const char kNativeHostExited[] = "Native host has exited."; -const char kNotFoundError[] = "Specified native messaging host not found."; -const char kForbiddenError[] = - "Access to the specified native messaging host is forbidden."; -const char kHostInputOuputError[] = - "Error when communicating with the native messaging host."; - } // namespace namespace extensions { -// static -NativeMessageProcessHost::PolicyPermission -NativeMessageProcessHost::IsHostAllowed(const PrefService* pref_service, - const std::string& native_host_name) { - NativeMessageProcessHost::PolicyPermission allow_result = ALLOW_ALL; - if (pref_service->IsManagedPreference( - pref_names::kNativeMessagingUserLevelHosts)) { - if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts)) - allow_result = ALLOW_SYSTEM_ONLY; - } - - // All native messaging hosts are allowed if there is no blacklist. - if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist)) - return allow_result; - const base::ListValue* blacklist = - pref_service->GetList(pref_names::kNativeMessagingBlacklist); - if (!blacklist) - return allow_result; - - // Check if the name or the wildcard is in the blacklist. - base::StringValue name_value(native_host_name); - base::StringValue wildcard_value("*"); - if (blacklist->Find(name_value) == blacklist->end() && - blacklist->Find(wildcard_value) == blacklist->end()) { - return allow_result; - } - - // The native messaging host is blacklisted. Check the whitelist. - if (pref_service->IsManagedPreference( - pref_names::kNativeMessagingWhitelist)) { - const base::ListValue* whitelist = - pref_service->GetList(pref_names::kNativeMessagingWhitelist); - if (whitelist && whitelist->Find(name_value) != whitelist->end()) - return allow_result; - } - - return DISALLOW; -} - NativeMessageProcessHost::NativeMessageProcessHost( - base::WeakPtr<Client> weak_client_ui, const std::string& source_extension_id, const std::string& native_host_name, - int destination_port, scoped_ptr<NativeProcessLauncher> launcher) - : weak_client_ui_(weak_client_ui), - source_extension_id_(source_extension_id), + : source_extension_id_(source_extension_id), native_host_name_(native_host_name), - destination_port_(destination_port), launcher_(launcher.Pass()), closed_(false), process_handle_(base::kNullProcessHandle), @@ -110,51 +54,50 @@ NativeMessageProcessHost::NativeMessageProcessHost( write_pending_(false) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::IO); // It's safe to use base::Unretained() here because NativeMessagePort always // deletes us on the IO thread. - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + task_runner_->PostTask( + FROM_HERE, base::Bind(&NativeMessageProcessHost::LaunchHostProcess, base::Unretained(this))); } NativeMessageProcessHost::~NativeMessageProcessHost() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - Close(std::string()); + DCHECK(task_runner_->BelongsToCurrentThread()); } // static -scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create( +scoped_ptr<NativeMessageHost> NativeMessageHost::Create( gfx::NativeView native_view, - base::WeakPtr<Client> weak_client_ui, const std::string& source_extension_id, const std::string& native_host_name, - int destination_port, - bool allow_user_level) { - return CreateWithLauncher(weak_client_ui, source_extension_id, - native_host_name, destination_port, - NativeProcessLauncher::CreateDefault( - allow_user_level, native_view)); + bool allow_user_level, + std::string* error_message) { + return NativeMessageProcessHost::CreateWithLauncher( + source_extension_id, + native_host_name, + NativeProcessLauncher::CreateDefault(allow_user_level, native_view)); } // static -scoped_ptr<NativeMessageProcessHost> -NativeMessageProcessHost::CreateWithLauncher( - base::WeakPtr<Client> weak_client_ui, +scoped_ptr<NativeMessageHost> NativeMessageProcessHost::CreateWithLauncher( const std::string& source_extension_id, const std::string& native_host_name, - int destination_port, scoped_ptr<NativeProcessLauncher> launcher) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost( - weak_client_ui, source_extension_id, native_host_name, - destination_port, launcher.Pass())); + scoped_ptr<NativeMessageHost> process( + new NativeMessageProcessHost(source_extension_id, + native_host_name, + launcher.Pass())); return process.Pass(); } void NativeMessageProcessHost::LaunchHostProcess() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_); launcher_->Launch(origin, native_host_name_, @@ -167,7 +110,7 @@ void NativeMessageProcessHost::OnHostProcessLaunched( base::ProcessHandle process_handle, base::File read_file, base::File write_file) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); switch (result) { case NativeProcessLauncher::RESULT_INVALID_NAME: @@ -204,8 +147,8 @@ void NativeMessageProcessHost::OnHostProcessLaunched( DoWrite(); } -void NativeMessageProcessHost::Send(const std::string& json) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); +void NativeMessageProcessHost::OnMessage(const std::string& json) { + DCHECK(task_runner_->BelongsToCurrentThread()); if (closed_) return; @@ -229,6 +172,16 @@ void NativeMessageProcessHost::Send(const std::string& json) { DoWrite(); } +void NativeMessageProcessHost::Start(Client* client) { + DCHECK(task_runner_->BelongsToCurrentThread()); + client_ = client; +} + +scoped_refptr<base::SingleThreadTaskRunner> +NativeMessageProcessHost::task_runner() const { + return task_runner_; +} + #if defined(OS_POSIX) void NativeMessageProcessHost::OnFileCanReadWithoutBlocking(int fd) { DCHECK_EQ(fd, read_file_); @@ -264,7 +217,7 @@ void NativeMessageProcessHost::WaitRead() { } void NativeMessageProcessHost::DoRead() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); while (!closed_ && !read_pending_) { read_buffer_ = new net::IOBuffer(kReadBufferSize); @@ -277,7 +230,7 @@ void NativeMessageProcessHost::DoRead() { } void NativeMessageProcessHost::OnRead(int result) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(read_pending_); read_pending_ = false; @@ -286,7 +239,7 @@ void NativeMessageProcessHost::OnRead(int result) { } void NativeMessageProcessHost::HandleReadResult(int result) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); if (closed_) return; @@ -307,7 +260,7 @@ void NativeMessageProcessHost::HandleReadResult(int result) { void NativeMessageProcessHost::ProcessIncomingData( const char* data, int data_size) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); incoming_data_.append(data, data_size); @@ -328,17 +281,15 @@ void NativeMessageProcessHost::ProcessIncomingData( if (incoming_data_.size() < message_size + kMessageHeaderSize) return; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, - destination_port_, - incoming_data_.substr(kMessageHeaderSize, message_size))); + client_->PostMessageFromNativeHost( + incoming_data_.substr(kMessageHeaderSize, message_size)); incoming_data_.erase(0, kMessageHeaderSize + message_size); } } void NativeMessageProcessHost::DoWrite() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); while (!write_pending_ && !closed_) { if (!current_write_buffer_.get() || @@ -360,7 +311,7 @@ void NativeMessageProcessHost::DoWrite() { } void NativeMessageProcessHost::HandleWriteResult(int result) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); if (result <= 0) { if (result == net::ERR_IO_PENDING) { @@ -376,7 +327,7 @@ void NativeMessageProcessHost::HandleWriteResult(int result) { } void NativeMessageProcessHost::OnWritten(int result) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(write_pending_); write_pending_ = false; @@ -386,15 +337,13 @@ void NativeMessageProcessHost::OnWritten(int result) { } void NativeMessageProcessHost::Close(const std::string& error_message) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK(task_runner_->BelongsToCurrentThread()); if (!closed_) { closed_ = true; read_stream_.reset(); write_stream_.reset(); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&Client::CloseChannel, weak_client_ui_, - destination_port_, error_message)); + client_->CloseChannel(error_message); } if (process_handle_ != base::kNullProcessHandle) { diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.h b/chrome/browser/extensions/api/messaging/native_message_process_host.h index fb19240..58a202c 100644 --- a/chrome/browser/extensions/api/messaging/native_message_process_host.h +++ b/chrome/browser/extensions/api/messaging/native_message_process_host.h @@ -10,14 +10,12 @@ #include "base/files/file.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/process/process.h" #include "chrome/browser/extensions/api/messaging/native_process_launcher.h" +#include "extensions/browser/api/messaging/native_message_host.h" #include "ui/gfx/native_widget_types.h" -class PrefService; - namespace net { class DrainableIOBuffer; @@ -35,54 +33,25 @@ namespace extensions { // This class must only be created, called, and deleted on the IO thread. // Public methods typically accept callbacks which will be invoked on the UI // thread. -class NativeMessageProcessHost +class NativeMessageProcessHost : #if defined(OS_POSIX) - : public base::MessageLoopForIO::Watcher + public base::MessageLoopForIO::Watcher, #endif // !defined(OS_POSIX) -{ + public NativeMessageHost { public: - // Interface for the object that receives messages from the native process. - class Client { - public: - virtual ~Client() {} - // Called on the UI thread. - virtual void PostMessageFromNativeProcess(int port_id, - const std::string& message) = 0; - virtual void CloseChannel(int port_id, - const std::string& error_message) = 0; - }; - - // Result returned from IsHostAllowed(). - enum PolicyPermission { - DISALLOW, // The host is not allowed. - ALLOW_SYSTEM_ONLY, // Allowed only when installed on system level. - ALLOW_ALL, // Allowed when installed on system or user level. - }; - virtual ~NativeMessageProcessHost(); - // Returns policy permissions for the host with the specified name. - static PolicyPermission IsHostAllowed(const PrefService* pref_service, - const std::string& native_host_name); - - static scoped_ptr<NativeMessageProcessHost> Create( - gfx::NativeView native_view, - base::WeakPtr<Client> weak_client_ui, - const std::string& source_extension_id, - const std::string& native_host_name, - int destination_port, - bool allow_user_level); - // Create using specified |launcher|. Used in tests. - static scoped_ptr<NativeMessageProcessHost> CreateWithLauncher( - base::WeakPtr<Client> weak_client_ui, + static scoped_ptr<NativeMessageHost> CreateWithLauncher( const std::string& source_extension_id, const std::string& native_host_name, - int destination_port, scoped_ptr<NativeProcessLauncher> launcher); - // Send a message with the specified payload. - void Send(const std::string& json); + // extensions::NativeMessageHost implementation. + virtual void OnMessage(const std::string& message) OVERRIDE; + virtual void Start(Client* client) OVERRIDE; + virtual scoped_refptr<base::SingleThreadTaskRunner> task_runner() + const OVERRIDE; #if defined(OS_POSIX) // MessageLoopForIO::Watcher interface @@ -95,10 +64,8 @@ class NativeMessageProcessHost void ReadNowForTesting(); private: - NativeMessageProcessHost(base::WeakPtr<Client> weak_client_ui, - const std::string& source_extension_id, + NativeMessageProcessHost(const std::string& source_extension_id, const std::string& native_host_name, - int destination_port, scoped_ptr<NativeProcessLauncher> launcher); // Starts the host process. @@ -127,7 +94,7 @@ class NativeMessageProcessHost // The Client messages will be posted to. Should only be accessed from the // UI thread. - base::WeakPtr<Client> weak_client_ui_; + Client* client_; // ID of the calling extension. std::string source_extension_id_; @@ -135,10 +102,6 @@ class NativeMessageProcessHost // Name of the native messaging host. std::string native_host_name_; - // The id of the port on the other side of this connection. This is passed to - // |weak_client_ui_| when posting messages. - int destination_port_; - // Launcher used to launch the native process. scoped_ptr<NativeProcessLauncher> launcher_; @@ -177,6 +140,8 @@ class NativeMessageProcessHost // Set to true when a write is pending. bool write_pending_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + DISALLOW_COPY_AND_ASSIGN(NativeMessageProcessHost); }; diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc index bb9c7a0..958c9c5 100644 --- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc +++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc @@ -10,7 +10,6 @@ #include "base/files/scoped_temp_dir.h" #include "base/json/json_reader.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/rand_util.h" #include "base/run_loop.h" @@ -93,7 +92,7 @@ class FakeLauncher : public NativeProcessLauncher { }; class NativeMessagingTest : public ::testing::Test, - public NativeMessageProcessHost::Client, + public NativeMessageHost::Client, public base::SupportsWeakPtr<NativeMessagingTest> { protected: NativeMessagingTest() @@ -106,16 +105,14 @@ class NativeMessagingTest : public ::testing::Test, } virtual void TearDown() override { - if (native_message_process_host_.get()) { - BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, - native_message_process_host_.release()); + if (native_message_host_.get()) { + BrowserThread::DeleteSoon( + BrowserThread::IO, FROM_HERE, native_message_host_.release()); } base::RunLoop().RunUntilIdle(); } - virtual void PostMessageFromNativeProcess( - int port_id, - const std::string& message) override { + virtual void PostMessageFromNativeHost(const std::string& message) override { last_message_ = message; // Parse the message. @@ -133,8 +130,7 @@ class NativeMessagingTest : public ::testing::Test, run_loop_->Quit(); } - virtual void CloseChannel(int port_id, - const std::string& error_message) override { + virtual void CloseChannel(const std::string& error_message) override { channel_closed_ = true; if (run_loop_) run_loop_->Quit(); @@ -164,7 +160,7 @@ class NativeMessagingTest : public ::testing::Test, base::ScopedTempDir temp_dir_; // Force the channel to be dev. ScopedCurrentChannel current_channel_; - scoped_ptr<NativeMessageProcessHost> native_message_process_host_; + scoped_ptr<NativeMessageHost> native_message_host_; scoped_ptr<base::RunLoop> run_loop_; content::TestBrowserThreadBundle thread_bundle_; std::string last_message_; @@ -180,15 +176,19 @@ TEST_F(NativeMessagingTest, SingleSendMessageRead) { scoped_ptr<NativeProcessLauncher> launcher = FakeLauncher::Create(temp_input_file, temp_output_file).Pass(); - native_message_process_host_ = NativeMessageProcessHost::CreateWithLauncher( - AsWeakPtr(), ScopedTestNativeMessagingHost::kExtensionId, "empty_app.py", - 0, launcher.Pass()); - ASSERT_TRUE(native_message_process_host_.get()); + native_message_host_ = NativeMessageProcessHost::CreateWithLauncher( + ScopedTestNativeMessagingHost::kExtensionId, + "empty_app.py", + launcher.Pass()); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_.get()); run_loop_.reset(new base::RunLoop()); run_loop_->RunUntilIdle(); if (last_message_.empty()) { run_loop_.reset(new base::RunLoop()); + scoped_ptr<NativeMessageProcessHost> native_message_process_host_( + static_cast<NativeMessageProcessHost*>(native_message_host_.release())); native_message_process_host_->ReadNowForTesting(); run_loop_->Run(); } @@ -226,13 +226,15 @@ TEST_F(NativeMessagingTest, SingleSendMessageWrite) { scoped_ptr<NativeProcessLauncher> launcher = FakeLauncher::CreateWithPipeInput(read_file.Pass(), temp_output_file).Pass(); - native_message_process_host_ = NativeMessageProcessHost::CreateWithLauncher( - AsWeakPtr(), ScopedTestNativeMessagingHost::kExtensionId, "empty_app.py", - 0, launcher.Pass()); - ASSERT_TRUE(native_message_process_host_.get()); + native_message_host_ = NativeMessageProcessHost::CreateWithLauncher( + ScopedTestNativeMessagingHost::kExtensionId, + "empty_app.py", + launcher.Pass()); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_.get()); base::RunLoop().RunUntilIdle(); - native_message_process_host_->Send(kTestMessage); + native_message_host_->OnMessage(kTestMessage); base::RunLoop().RunUntilIdle(); std::string output; @@ -252,13 +254,17 @@ TEST_F(NativeMessagingTest, SingleSendMessageWrite) { TEST_F(NativeMessagingTest, EchoConnect) { ScopedTestNativeMessagingHost test_host; ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(false)); - - native_message_process_host_ = NativeMessageProcessHost::Create( - NULL, AsWeakPtr(), ScopedTestNativeMessagingHost::kExtensionId, - ScopedTestNativeMessagingHost::kHostName, 0, false); - ASSERT_TRUE(native_message_process_host_.get()); - - native_message_process_host_->Send("{\"text\": \"Hello.\"}"); + std::string error_message; + native_message_host_ = NativeMessageProcessHost::Create( + NULL, + ScopedTestNativeMessagingHost::kExtensionId, + ScopedTestNativeMessagingHost::kHostName, + false, + &error_message); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_.get()); + + native_message_host_->OnMessage("{\"text\": \"Hello.\"}"); run_loop_.reset(new base::RunLoop()); run_loop_->Run(); ASSERT_FALSE(last_message_.empty()); @@ -276,7 +282,7 @@ TEST_F(NativeMessagingTest, EchoConnect) { EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url)); EXPECT_EQ(expected_url, url); - native_message_process_host_->Send("{\"foo\": \"bar\"}"); + native_message_host_->OnMessage("{\"foo\": \"bar\"}"); run_loop_.reset(new base::RunLoop()); run_loop_->Run(); EXPECT_TRUE(last_message_parsed_->GetInteger("id", &id)); @@ -291,12 +297,17 @@ TEST_F(NativeMessagingTest, UserLevel) { ScopedTestNativeMessagingHost test_host; ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(true)); - native_message_process_host_ = NativeMessageProcessHost::Create( - NULL, AsWeakPtr(), ScopedTestNativeMessagingHost::kExtensionId, - ScopedTestNativeMessagingHost::kHostName, 0, true); - ASSERT_TRUE(native_message_process_host_.get()); - - native_message_process_host_->Send("{\"text\": \"Hello.\"}"); + std::string error_message; + native_message_host_ = NativeMessageProcessHost::Create( + NULL, + ScopedTestNativeMessagingHost::kExtensionId, + ScopedTestNativeMessagingHost::kHostName, + true, + &error_message); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_.get()); + + native_message_host_->OnMessage("{\"text\": \"Hello.\"}"); run_loop_.reset(new base::RunLoop()); run_loop_->Run(); ASSERT_FALSE(last_message_.empty()); @@ -307,10 +318,15 @@ TEST_F(NativeMessagingTest, DisallowUserLevel) { ScopedTestNativeMessagingHost test_host; ASSERT_NO_FATAL_FAILURE(test_host.RegisterTestHost(true)); - native_message_process_host_ = NativeMessageProcessHost::Create( - NULL, AsWeakPtr(), ScopedTestNativeMessagingHost::kExtensionId, - ScopedTestNativeMessagingHost::kHostName, 0, false); - ASSERT_TRUE(native_message_process_host_.get()); + std::string error_message; + native_message_host_ = NativeMessageProcessHost::Create( + NULL, + ScopedTestNativeMessagingHost::kExtensionId, + ScopedTestNativeMessagingHost::kHostName, + false, + &error_message); + native_message_host_->Start(this); + ASSERT_TRUE(native_message_host_.get()); run_loop_.reset(new base::RunLoop()); run_loop_->Run(); diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index e2cab92..1f7adc0 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc @@ -34,7 +34,7 @@ #include "chrome/browser/content_settings/tab_specific_content_settings.h" #include "chrome/browser/devtools/devtools_window_testing.h" #include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/extensions/api/messaging/native_message_process_host.h" +#include "chrome/browser/extensions/api/messaging/message_service.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/unpacked_installer.h" @@ -3171,9 +3171,9 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, NativeMessagingBlacklistSelective) { UpdateProviderPolicy(policies); PrefService* prefs = browser()->profile()->GetPrefs(); - EXPECT_FALSE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_FALSE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "host.name")); - EXPECT_TRUE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_TRUE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "other.host.name")); } @@ -3186,9 +3186,9 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, NativeMessagingBlacklistWildcard) { UpdateProviderPolicy(policies); PrefService* prefs = browser()->profile()->GetPrefs(); - EXPECT_FALSE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_FALSE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "host.name")); - EXPECT_FALSE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_FALSE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "other.host.name")); } @@ -3205,9 +3205,9 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, NativeMessagingWhitelist) { UpdateProviderPolicy(policies); PrefService* prefs = browser()->profile()->GetPrefs(); - EXPECT_TRUE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_TRUE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "host.name")); - EXPECT_FALSE(extensions::NativeMessageProcessHost::IsHostAllowed( + EXPECT_FALSE(extensions::MessageService::IsNativeMessagingHostAllowed( prefs, "other.host.name")); } diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 25b5a99..021c9f8 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -22,6 +22,7 @@ 'browser/extensions/api/log_private/log_private_api_chromeos.cc', 'browser/extensions/api/log_private/syslog_parser.cc', 'browser/extensions/api/log_private/syslog_parser.h', + 'browser/extensions/api/messaging/native_message_host_chromeos.cc', 'browser/extensions/api/terminal/terminal_extension_helper.cc', 'browser/extensions/api/terminal/terminal_extension_helper.h', 'browser/extensions/api/terminal/terminal_private_api.cc', @@ -38,6 +39,12 @@ 'browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc', 'browser/extensions/api/image_writer_private/operation_nonchromeos.cc', 'browser/extensions/api/image_writer_private/removable_storage_provider_linux.cc', + 'browser/extensions/api/messaging/native_message_process_host.cc', + 'browser/extensions/api/messaging/native_message_process_host.h', + 'browser/extensions/api/messaging/native_process_launcher.cc', + 'browser/extensions/api/messaging/native_process_launcher.h', + 'browser/extensions/api/messaging/native_process_launcher_posix.cc', + 'browser/extensions/api/messaging/native_process_launcher_win.cc', ], 'chrome_browser_extensions_enabled_sources': [ 'browser/apps/app_launch_for_metro_restart_win.cc', @@ -325,16 +332,10 @@ 'browser/extensions/api/messaging/message_service.h', 'browser/extensions/api/messaging/native_message_port.cc', 'browser/extensions/api/messaging/native_message_port.h', - 'browser/extensions/api/messaging/native_message_process_host.cc', - 'browser/extensions/api/messaging/native_message_process_host.h', 'browser/extensions/api/messaging/native_messaging_host_manifest.cc', 'browser/extensions/api/messaging/native_messaging_host_manifest.h', 'browser/extensions/api/messaging/native_messaging_policy_handler.cc', 'browser/extensions/api/messaging/native_messaging_policy_handler.h', - 'browser/extensions/api/messaging/native_process_launcher.cc', - 'browser/extensions/api/messaging/native_process_launcher.h', - 'browser/extensions/api/messaging/native_process_launcher_posix.cc', - 'browser/extensions/api/messaging/native_process_launcher_win.cc', 'browser/extensions/api/metrics_private/metrics_private_api.cc', 'browser/extensions/api/metrics_private/metrics_private_api.h', 'browser/extensions/api/module/module.cc', diff --git a/chrome/test/data/extensions/api_test/native_messaging/test.js b/chrome/test/data/extensions/api_test/native_messaging/test.js index 408c032..ab747a1 100644 --- a/chrome/test/data/extensions/api_test/native_messaging/test.js +++ b/chrome/test/data/extensions/api_test/native_messaging/test.js @@ -87,11 +87,8 @@ chrome.test.getConfig(function(config) { function stopHost() { port = chrome.extension.connectNative(appName); - port.onMessage.addListener(function(message) { - port.onDisconnect.addListener(chrome.test.callback( - function() {}, - "Native host has exited.")); - }); + port.onDisconnect.addListener( + chrome.test.callback(function() {}, "Native host has exited.")); // Send first message that should stop the host. port.postMessage({ "stopHostTest": true }); diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 9ea3e4f..1825783 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn @@ -141,6 +141,7 @@ source_set("browser") { "api/hid/hid_connection_resource.h", "api/hid/hid_device_manager.cc", "api/hid/hid_device_manager.h", + "api/messaging/native_message_host.cc", "api/power/power_api.cc", "api/power/power_api.h", "api/power/power_api_manager.cc", diff --git a/extensions/browser/api/messaging/native_message_host.cc b/extensions/browser/api/messaging/native_message_host.cc new file mode 100644 index 0000000..f3bb082 --- /dev/null +++ b/extensions/browser/api/messaging/native_message_host.cc @@ -0,0 +1,21 @@ +// Copyright 2014 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. + +#include "extensions/browser/api/messaging/native_message_host.h" + +namespace extensions { + +const char NativeMessageHost::kFailedToStartError[] = + "Failed to start native messaging host."; +const char NativeMessageHost::kInvalidNameError[] = + "Invalid native messaging host name specified."; +const char NativeMessageHost::kNativeHostExited[] = "Native host has exited."; +const char NativeMessageHost::kNotFoundError[] = + "Specified native messaging host not found."; +const char NativeMessageHost::kForbiddenError[] = + "Access to the specified native messaging host is forbidden."; +const char NativeMessageHost::kHostInputOuputError[] = + "Error when communicating with the native messaging host."; + +} // extensions diff --git a/extensions/browser/api/messaging/native_message_host.h b/extensions/browser/api/messaging/native_message_host.h new file mode 100644 index 0000000..da241e0 --- /dev/null +++ b/extensions/browser/api/messaging/native_message_host.h @@ -0,0 +1,62 @@ +// Copyright 2014 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. + +#ifndef EXTENSIONS_BROWSER_API_MESSAGING_NATIVE_MESSAGE_HOST_H_ +#define EXTENSIONS_BROWSER_API_MESSAGING_NATIVE_MESSAGE_HOST_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" +#include "ui/gfx/native_widget_types.h" + +namespace extensions { + +// An interface for receiving messages from MessageService (Chrome) using the +// Native Messaging API. A NativeMessageHost object hosts a native component, +// which can run in the browser-process or in a separate process (See +// NativeMessageProcessHost). +class NativeMessageHost { + public: + static const char kFailedToStartError[]; + static const char kInvalidNameError[]; + static const char kNativeHostExited[]; + static const char kNotFoundError[]; + static const char kForbiddenError[]; + static const char kHostInputOuputError[]; + + // Callback interface for receiving messages from the native host. + class Client { + public: + virtual ~Client() {} + + // Called on the UI thread. + virtual void PostMessageFromNativeHost(const std::string& message) = 0; + virtual void CloseChannel(const std::string& error_message) = 0; + }; + + // Creates the NativeMessageHost based on the |native_host_name|. + static scoped_ptr<NativeMessageHost> Create( + gfx::NativeView native_view, + const std::string& source_extension_id, + const std::string& native_host_name, + bool allow_user_level, + std::string* error); + + virtual ~NativeMessageHost() {} + + // Called when a message is received from MessageService (Chrome). + virtual void OnMessage(const std::string& message) = 0; + + // Sets the client to start receiving messages from the native host. + virtual void Start(Client* client) = 0; + + // Returns the task runner that the host runs on. The Client should only + // invoke OnMessage() on this task runner. + virtual scoped_refptr<base::SingleThreadTaskRunner> task_runner() const = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_MESSAGING_NATIVE_MESSAGE_HOST_H_ diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc index 5c44c84..d9eba9e 100644 --- a/extensions/common/switches.cc +++ b/extensions/common/switches.cc @@ -62,6 +62,10 @@ const char kEnableMimeHandlerView[] = "enable-mime-handler-view"; // Enables extensions to hide bookmarks UI elements. const char kEnableOverrideBookmarksUI[] = "enable-override-bookmarks-ui"; +// Allows remote assistance connection to this computer using the Chrome Remote +// Desktop app on Chrome OS. +const char kEnableRemoteAssistance[] = "enable-remote-assistance"; + // Allows the ErrorConsole to collect runtime and manifest errors, and display // them in the chrome:extensions page. const char kErrorConsole[] = "error-console"; diff --git a/extensions/common/switches.h b/extensions/common/switches.h index 4aa10ea..59fadb2 100644 --- a/extensions/common/switches.h +++ b/extensions/common/switches.h @@ -25,6 +25,7 @@ extern const char kEnableExtensionActionRedesign[]; extern const char kEnableExtensionInfoDialog[]; extern const char kEnableMimeHandlerView[]; extern const char kEnableOverrideBookmarksUI[]; +extern const char kEnableRemoteAssistance[]; extern const char kErrorConsole[]; extern const char kExtensionActionRedesign[]; extern const char kExtensionProcess[]; diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 0a80101..ac1eb6e 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -426,6 +426,7 @@ 'browser/api/hid/hid_connection_resource.h', 'browser/api/hid/hid_device_manager.cc', 'browser/api/hid/hid_device_manager.h', + 'browser/api/messaging/native_message_host.cc', 'browser/api/power/power_api.cc', 'browser/api/power/power_api.h', 'browser/api/power/power_api_manager.cc', diff --git a/remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 b/remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 index 9c90357..5545dc8 100644 --- a/remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 +++ b/remoting/host/it2me/com.google.chrome.remote_assistance.json.jinja2 @@ -3,6 +3,9 @@ "description": "{{ IT2ME_HOST_DESCRIPTION }}", "type": "stdio", "path": "{{ IT2ME_HOST_PATH }}", + // If you modify the list of allowed_origins, don't forget to update + // chrome/browser/extensions/messaging/native_message_host_chromeos.cc + // to keep the two lists in sync. "allowed_origins": [ "chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/", "chrome-extension://gbchcmhmhahfdphkhkmpfmihenigjmpp/", diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc index 8d0d131..24ddc1b 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.cc +++ b/remoting/host/it2me/it2me_native_messaging_host.cc @@ -9,9 +9,8 @@ #include "base/basictypes.h" #include "base/bind.h" #include "base/callback.h" -#include "base/callback_helpers.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringize_macros.h" #include "base/threading/thread.h" @@ -42,9 +41,8 @@ const remoting::protocol::NameMapElement<It2MeHostState> kIt2MeHostStates[] = { It2MeNativeMessagingHost::It2MeNativeMessagingHost( scoped_refptr<AutoThreadTaskRunner> task_runner, - scoped_ptr<extensions::NativeMessagingChannel> channel, scoped_ptr<It2MeHostFactory> factory) - : channel_(channel.Pass()), + : client_(NULL), factory_(factory.Pass()), weak_factory_(this) { weak_ptr_ = weak_factory_.GetWeakPtr(); @@ -75,27 +73,19 @@ It2MeNativeMessagingHost::~It2MeNativeMessagingHost() { } } -void It2MeNativeMessagingHost::Start(const base::Closure& quit_closure) { +void It2MeNativeMessagingHost::OnMessage(const std::string& message) { DCHECK(task_runner()->BelongsToCurrentThread()); - DCHECK(!quit_closure.is_null()); - quit_closure_ = quit_closure; - - channel_->Start(this); -} - -void It2MeNativeMessagingHost::OnMessage(scoped_ptr<base::Value> message) { - DCHECK(task_runner()->BelongsToCurrentThread()); - - if (!message->IsType(base::Value::TYPE_DICTIONARY)) { + scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); + scoped_ptr<base::Value> message_value(base::JSONReader::Read(message)); + if (!message_value->IsType(base::Value::TYPE_DICTIONARY)) { LOG(ERROR) << "Received a message that's not a dictionary."; - channel_->SendMessage(nullptr); + client_->CloseChannel(std::string()); return; } scoped_ptr<base::DictionaryValue> message_dict( - static_cast<base::DictionaryValue*>(message.release())); - scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); + static_cast<base::DictionaryValue*>(message_value.release())); // If the client supplies an ID, it will expect it in the response. This // might be a string or a number, so cope with both. @@ -122,9 +112,17 @@ void It2MeNativeMessagingHost::OnMessage(scoped_ptr<base::Value> message) { } } -void It2MeNativeMessagingHost::OnDisconnect() { - if (!quit_closure_.is_null()) - base::ResetAndReturn(&quit_closure_).Run(); +void It2MeNativeMessagingHost::Start(Client* client) { + DCHECK(task_runner()->BelongsToCurrentThread()); + client_ = client; +} + +void It2MeNativeMessagingHost::SendMessageToClient( + scoped_ptr<base::DictionaryValue> message) const { + DCHECK(task_runner()->BelongsToCurrentThread()); + std::string message_json; + base::JSONWriter::Write(message.get(), &message_json); + client_->PostMessageFromNativeHost(message_json); } void It2MeNativeMessagingHost::ProcessHello( @@ -138,7 +136,7 @@ void It2MeNativeMessagingHost::ProcessHello( scoped_ptr<base::ListValue> supported_features_list(new base::ListValue()); response->Set("supportedFeatures", supported_features_list.release()); - channel_->SendMessage(response.Pass()); + SendMessageToClient(response.Pass()); } void It2MeNativeMessagingHost::ProcessConnect( @@ -212,7 +210,7 @@ void It2MeNativeMessagingHost::ProcessConnect( directory_bot_jid_); it2me_host_->Connect(); - channel_->SendMessage(response.Pass()); + SendMessageToClient(response.Pass()); } void It2MeNativeMessagingHost::ProcessDisconnect( @@ -224,7 +222,7 @@ void It2MeNativeMessagingHost::ProcessDisconnect( it2me_host_->Disconnect(); it2me_host_ = NULL; } - channel_->SendMessage(response.Pass()); + SendMessageToClient(response.Pass()); } void It2MeNativeMessagingHost::SendErrorAndExit( @@ -236,10 +234,10 @@ void It2MeNativeMessagingHost::SendErrorAndExit( response->SetString("type", "error"); response->SetString("description", description); - channel_->SendMessage(response.Pass()); + SendMessageToClient(response.Pass()); - // Trigger a host shutdown by sending a NULL message. - channel_->SendMessage(nullptr); + // Trigger a host shutdown by sending an empty message. + client_->CloseChannel(std::string()); } void It2MeNativeMessagingHost::OnStateChanged(It2MeHostState state) { @@ -272,7 +270,7 @@ void It2MeNativeMessagingHost::OnStateChanged(It2MeHostState state) { ; } - channel_->SendMessage(message.Pass()); + SendMessageToClient(message.Pass()); } void It2MeNativeMessagingHost::OnNatPolicyChanged(bool nat_traversal_enabled) { @@ -282,7 +280,7 @@ void It2MeNativeMessagingHost::OnNatPolicyChanged(bool nat_traversal_enabled) { message->SetString("type", "natPolicyChanged"); message->SetBoolean("natTraversalEnabled", nat_traversal_enabled); - channel_->SendMessage(message.Pass()); + SendMessageToClient(message.Pass()); } // Stores the Access Code for the web-app to query. @@ -303,7 +301,7 @@ void It2MeNativeMessagingHost::OnClientAuthenticated( client_username_ = client_username; } -scoped_refptr<AutoThreadTaskRunner> +scoped_refptr<base::SingleThreadTaskRunner> It2MeNativeMessagingHost::task_runner() const { return host_context_->ui_task_runner(); } diff --git a/remoting/host/it2me/it2me_native_messaging_host.h b/remoting/host/it2me/it2me_native_messaging_host.h index f9d8ac9..18e738b 100644 --- a/remoting/host/it2me/it2me_native_messaging_host.h +++ b/remoting/host/it2me/it2me_native_messaging_host.h @@ -8,40 +8,38 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "extensions/browser/api/messaging/native_messaging_channel.h" +#include "extensions/browser/api/messaging/native_message_host.h" #include "remoting/base/auto_thread_task_runner.h" #include "remoting/host/it2me/it2me_host.h" namespace base { class DictionaryValue; +class Value; } // namespace base namespace remoting { // Implementation of the native messaging host process. -class It2MeNativeMessagingHost - : public It2MeHost::Observer, - public extensions::NativeMessagingChannel::EventHandler { +class It2MeNativeMessagingHost : public It2MeHost::Observer, + public extensions::NativeMessageHost { public: - It2MeNativeMessagingHost( - scoped_refptr<AutoThreadTaskRunner> task_runner, - scoped_ptr<extensions::NativeMessagingChannel> channel, - scoped_ptr<It2MeHostFactory> factory); + It2MeNativeMessagingHost(scoped_refptr<AutoThreadTaskRunner> task_runner, + scoped_ptr<It2MeHostFactory> factory); virtual ~It2MeNativeMessagingHost(); - void Start(const base::Closure& quit_closure); - - // extensions::NativeMessagingChannel::EventHandler implementation. - virtual void OnMessage(scoped_ptr<base::Value> message) OVERRIDE; - virtual void OnDisconnect() OVERRIDE; + // extensions::NativeMessageHost implementation. + virtual void OnMessage(const std::string& message) override; + virtual void Start(Client* client) override; + virtual scoped_refptr<base::SingleThreadTaskRunner> task_runner() + const override; // It2MeHost::Observer implementation. virtual void OnClientAuthenticated(const std::string& client_username) - OVERRIDE; + override; virtual void OnStoreAccessCode(const std::string& access_code, - base::TimeDelta access_code_lifetime) OVERRIDE; - virtual void OnNatPolicyChanged(bool nat_traversal_enabled) OVERRIDE; - virtual void OnStateChanged(It2MeHostState state) OVERRIDE; + base::TimeDelta access_code_lifetime) override; + virtual void OnNatPolicyChanged(bool nat_traversal_enabled) override; + virtual void OnStateChanged(It2MeHostState state) override; static std::string HostStateToString(It2MeHostState host_state); @@ -57,12 +55,9 @@ class It2MeNativeMessagingHost scoped_ptr<base::DictionaryValue> response); void SendErrorAndExit(scoped_ptr<base::DictionaryValue> response, const std::string& description) const; + void SendMessageToClient(scoped_ptr<base::DictionaryValue> message) const; - base::Closure quit_closure_; - - scoped_refptr<AutoThreadTaskRunner> task_runner() const; - - scoped_ptr<extensions::NativeMessagingChannel> channel_; + Client* client_; scoped_ptr<It2MeHostFactory> factory_; scoped_ptr<ChromotingHostContext> host_context_; scoped_refptr<It2MeHost> it2me_host_; diff --git a/remoting/host/it2me/it2me_native_messaging_host_main.cc b/remoting/host/it2me/it2me_native_messaging_host_main.cc index 25f5021..7d27d19 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_main.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_main.cc @@ -16,6 +16,7 @@ #include "remoting/host/host_exit_codes.h" #include "remoting/host/it2me/it2me_native_messaging_host.h" #include "remoting/host/logging.h" +#include "remoting/host/native_messaging/native_messaging_pipe.h" #include "remoting/host/native_messaging/pipe_messaging_channel.h" #include "remoting/host/usage_stats_consent.h" @@ -117,13 +118,21 @@ int StartIt2MeNativeMessagingHost() { scoped_ptr<It2MeHostFactory> factory(new It2MeHostFactory()); + scoped_ptr<NativeMessagingPipe> native_messaging_pipe( + new NativeMessagingPipe()); + // Set up the native messaging channel. scoped_ptr<extensions::NativeMessagingChannel> channel( new PipeMessagingChannel(read_file.Pass(), write_file.Pass())); - scoped_ptr<It2MeNativeMessagingHost> host(new It2MeNativeMessagingHost( - task_runner, channel.Pass(), factory.Pass())); - host->Start(run_loop.QuitClosure()); + scoped_ptr<extensions::NativeMessageHost> host(new It2MeNativeMessagingHost( + task_runner, + factory.Pass())); + + host->Start(native_messaging_pipe.get()); + + native_messaging_pipe->Start( + host.Pass(), channel.Pass(), run_loop.QuitClosure()); // Run the loop until channel is alive. run_loop.Run(); diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc index 56515a9..61334cf 100644 --- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc +++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc @@ -17,6 +17,7 @@ #include "net/base/net_util.h" #include "remoting/base/auto_thread_task_runner.h" #include "remoting/host/chromoting_host_context.h" +#include "remoting/host/native_messaging/native_messaging_pipe.h" #include "remoting/host/native_messaging/pipe_messaging_channel.h" #include "remoting/host/setup/test_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -78,9 +79,9 @@ class MockIt2MeHost : public It2MeHost { directory_bot_jid) {} // It2MeHost overrides - virtual void Connect() OVERRIDE; - virtual void Disconnect() OVERRIDE; - virtual void RequestNatPolicy() OVERRIDE; + virtual void Connect() override; + virtual void Disconnect() override; + virtual void RequestNatPolicy() override; private: virtual ~MockIt2MeHost() {} @@ -153,7 +154,7 @@ class MockIt2MeHostFactory : public It2MeHostFactory { scoped_refptr<base::SingleThreadTaskRunner> task_runner, base::WeakPtr<It2MeHost::Observer> observer, const XmppSignalStrategy::XmppServerConfig& xmpp_server_config, - const std::string& directory_bot_jid) OVERRIDE { + const std::string& directory_bot_jid) override { return new MockIt2MeHost( context, task_runner, observer, xmpp_server_config, directory_bot_jid); } @@ -167,8 +168,8 @@ class It2MeNativeMessagingHostTest : public testing::Test { It2MeNativeMessagingHostTest() {} virtual ~It2MeNativeMessagingHostTest() {} - virtual void SetUp() OVERRIDE; - virtual void TearDown() OVERRIDE; + virtual void SetUp() override; + virtual void TearDown() override; protected: scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe(); @@ -209,7 +210,7 @@ class It2MeNativeMessagingHostTest : public testing::Test { // Task runner of the host thread. scoped_refptr<AutoThreadTaskRunner> host_task_runner_; - scoped_ptr<remoting::It2MeNativeMessagingHost> host_; + scoped_ptr<remoting::NativeMessagingPipe> pipe_; DISALLOW_COPY_AND_ASSIGN(It2MeNativeMessagingHostTest); }; @@ -431,15 +432,21 @@ void It2MeNativeMessagingHostTest::StartHost() { // Creating a native messaging host with a mock It2MeHostFactory. scoped_ptr<It2MeHostFactory> factory(new MockIt2MeHostFactory()); + pipe_.reset(new NativeMessagingPipe()); + scoped_ptr<extensions::NativeMessagingChannel> channel( new PipeMessagingChannel(input_read_file.Pass(), output_write_file.Pass())); - host_.reset(new It2MeNativeMessagingHost( - host_task_runner_, - channel.Pass(), - factory.Pass())); - host_->Start(base::Bind(&It2MeNativeMessagingHostTest::StopHost, + scoped_ptr<extensions::NativeMessageHost> it2me_host( + new It2MeNativeMessagingHost( + host_task_runner_, + factory.Pass())); + it2me_host->Start(pipe_.get()); + + pipe_->Start(it2me_host.Pass(), + channel.Pass(), + base::Bind(&It2MeNativeMessagingHostTest::StopHost, base::Unretained(this))); // Notify the test that the host has finished starting up. @@ -450,7 +457,7 @@ void It2MeNativeMessagingHostTest::StartHost() { void It2MeNativeMessagingHostTest::StopHost() { DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); - host_.reset(); + pipe_.reset(); // Wait till all shutdown tasks have completed. base::RunLoop().RunUntilIdle(); diff --git a/remoting/host/native_messaging/native_messaging_pipe.cc b/remoting/host/native_messaging/native_messaging_pipe.cc new file mode 100644 index 0000000..13abc35 --- /dev/null +++ b/remoting/host/native_messaging/native_messaging_pipe.cc @@ -0,0 +1,52 @@ +// Copyright 2014 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. + +#include "remoting/host/native_messaging/native_messaging_pipe.h" + +#include "base/callback_helpers.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/values.h" + +namespace remoting { + +NativeMessagingPipe::NativeMessagingPipe() { +} + +NativeMessagingPipe::~NativeMessagingPipe() { +} + +void NativeMessagingPipe::Start( + scoped_ptr<extensions::NativeMessageHost> host, + scoped_ptr<extensions::NativeMessagingChannel> channel, + const base::Closure& quit_closure) { + host_ = host.Pass(); + channel_ = channel.Pass(); + quit_closure_ = quit_closure; + channel_->Start(this); +} + +void NativeMessagingPipe::OnMessage(scoped_ptr<base::Value> message) { + std::string message_json; + base::JSONWriter::Write(message.get(), &message_json); + host_->OnMessage(message_json); +} + +void NativeMessagingPipe::OnDisconnect() { + if (!quit_closure_.is_null()) + base::ResetAndReturn(&quit_closure_).Run(); +} + +void NativeMessagingPipe::PostMessageFromNativeHost( + const std::string& message) { + scoped_ptr<base::Value> json(base::JSONReader::Read(message)); + channel_->SendMessage(json.Pass()); +} + +void NativeMessagingPipe::CloseChannel(const std::string& error_message) { + if (!quit_closure_.is_null()) + base::ResetAndReturn(&quit_closure_).Run(); +} + +} // namespace remoting diff --git a/remoting/host/native_messaging/native_messaging_pipe.h b/remoting/host/native_messaging/native_messaging_pipe.h new file mode 100644 index 0000000..24a16f7 --- /dev/null +++ b/remoting/host/native_messaging/native_messaging_pipe.h @@ -0,0 +1,50 @@ +// Copyright 2014 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. + +#ifndef REMOTING_HOST_NATIVE_MESSAGING_NATIVE_MESSAGING_PIPE_H_ +#define REMOTING_HOST_NATIVE_MESSAGING_NATIVE_MESSAGING_PIPE_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "extensions/browser/api/messaging/native_message_host.h" +#include "extensions/browser/api/messaging/native_messaging_channel.h" + +namespace base { +class Value; +} + +namespace remoting { + +// Connects a extensions::NativeMessageHost to a PipeMessagingChannel. +class NativeMessagingPipe + : public extensions::NativeMessagingChannel::EventHandler, + public extensions::NativeMessageHost::Client { + public: + NativeMessagingPipe(); + virtual ~NativeMessagingPipe(); + + // Starts processing messages from the pipe. + void Start(scoped_ptr<extensions::NativeMessageHost> host, + scoped_ptr<extensions::NativeMessagingChannel> channel, + const base::Closure& quit_closure); + + // extensions::NativeMessageHost::Client implementation. + virtual void PostMessageFromNativeHost(const std::string& message) override; + virtual void CloseChannel(const std::string& error_message) override; + + // extensions::NativeMessagingChannel::EventHandler implementation. + virtual void OnMessage(scoped_ptr<base::Value> message) override; + virtual void OnDisconnect() override; + + private: + base::Closure quit_closure_; + scoped_ptr<extensions::NativeMessagingChannel> channel_; + scoped_ptr<extensions::NativeMessageHost> host_; + + DISALLOW_COPY_AND_ASSIGN(NativeMessagingPipe); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_NATIVE_MESSAGING_NATIVE_MESSAGING_PIPE_H_ diff --git a/remoting/remoting_host.gypi b/remoting/remoting_host.gypi index eca5646..5538700 100644 --- a/remoting/remoting_host.gypi +++ b/remoting/remoting_host.gypi @@ -431,6 +431,8 @@ 'sources': [ 'host/native_messaging/pipe_messaging_channel.cc', 'host/native_messaging/pipe_messaging_channel.h', + 'host/native_messaging/native_messaging_pipe.cc', + 'host/native_messaging/native_messaging_pipe.h', 'host/native_messaging/native_messaging_reader.cc', 'host/native_messaging/native_messaging_reader.h', 'host/native_messaging/native_messaging_writer.cc', diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b40c638..ce268d5 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -45886,6 +45886,7 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="880510010" label="enable-permissions-bubbles"/> <int value="887011602" label="enable-spelling-auto-correct"/> <int value="909439558" label="disable-device-discovery"/> + <int value="952558794" label="enable-remote-assistance"/> <int value="1022992701" label="enable-origin-chip-always"/> <int value="1033597574" label="disable-layer-squashing"/> <int value="1050321458" label="new-profile-management"/> |