diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-12 01:07:24 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-12 01:07:24 +0000 |
commit | 50307586363272bb8b133004889772b4919ad8fd (patch) | |
tree | a7e73d040cbd3d846e60570abd68c731f85b3e48 /chrome | |
parent | 7e8a83c5f13b6ed0c5be202f5697efc07cee06ce (diff) | |
download | chromium_src-50307586363272bb8b133004889772b4919ad8fd.zip chromium_src-50307586363272bb8b133004889772b4919ad8fd.tar.gz chromium_src-50307586363272bb8b133004889772b4919ad8fd.tar.bz2 |
ServiceProcessControl to launch a service process and communicate through IPC.
Added two class for use with service process:
ServiceProcessControl
Used by the browser to launch and connect to the service process, also used
to receive messages from the service process.
ServiceProcessControlManager
A singleton to manage multiple ServicProcessControl.
BUG=50244
TEST=browser_tests --gtest_filter=ServiceProcess*
Review URL: http://codereview.chromium.org/3032061
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55826 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/browser.cc | 4 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control.cc | 212 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control.h | 116 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control_browsertest.cc | 70 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control_manager.cc | 45 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control_manager.h | 45 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | chrome/chrome_common.gypi | 3 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/service_messages_internal.h | 9 | ||||
-rw-r--r-- | chrome/common/service_process_type.h | 17 | ||||
-rw-r--r-- | chrome/common/service_process_util.cc | 55 | ||||
-rw-r--r-- | chrome/common/service_process_util.h | 43 | ||||
-rw-r--r-- | chrome/service/service_ipc_server.cc | 9 | ||||
-rw-r--r-- | chrome/service/service_ipc_server.h | 2 | ||||
-rw-r--r-- | chrome/service/service_process.cc | 38 | ||||
-rw-r--r-- | chrome/service/service_process.h | 5 |
17 files changed, 664 insertions, 14 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 8fdd799..a5f65d2 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -66,6 +66,7 @@ #endif #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/service/service_process_control_manager.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/session_types.h" #include "chrome/browser/status_bubble.h" @@ -844,6 +845,9 @@ void Browser::OnWindowClosing() { Source<Browser>(this), Details<bool>(&exiting)); + // Shutdown all IPC channels to service processes. + ServiceProcessControlManager::instance()->Shutdown(); + CloseAllTabs(); } diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc new file mode 100644 index 0000000..6cf649b --- /dev/null +++ b/chrome/browser/service/service_process_control.cc @@ -0,0 +1,212 @@ +// Copyright (c) 2010 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 "chrome/browser/service/service_process_control.h" + +#include "base/command_line.h" +#include "base/process_util.h" +#include "base/thread.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/io_thread.h" +#include "chrome/common/child_process_host.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/service_messages.h" +#include "chrome/common/service_process_util.h" + +// ServiceProcessControl::Launcher implementation. +// This class is responsible for launching the service process on the +// PROCESS_LAUNCHER thread. +class ServiceProcessControl::Launcher + : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> { + public: + Launcher(ServiceProcessControl* process, CommandLine* cmd_line) + : process_(process), + cmd_line_(cmd_line), + launched_(false) { + } + + // Execute the command line to start the process asynchronously. + // After the comamnd is executed |task| is called with the process handle on + // the UI thread. + void Run(Task* task) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + ChromeThread::PostTask(ChromeThread::PROCESS_LAUNCHER, FROM_HERE, + NewRunnableMethod(this, &Launcher::DoRun, task)); + } + + bool launched() const { return launched_; } + + private: + void DoRun(Task* task) { + launched_ = base::LaunchApp(*cmd_line_.get(), false, true, NULL); + + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &Launcher::DoDetectLaunched, task)); + } + + void DoDetectLaunched(Task* task) { + // TODO(hclam): We need to improve the method we are using to connect to + // the service process. The approach we are using here is to check for + // the existence of the service process lock file created after the service + // process is fully launched. + if (CheckServiceProcessRunning(kServiceProcessCloudPrint)) { + // After the process is launched we listen on the file system for the + // service process lock file to detect the service process has launched. + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &Launcher::Notify, task)); + return; + } + + // If the service process is not launched yet then check again in 2 seconds. + const int kDetectLaunchRetry = 2000; + ChromeThread::PostDelayedTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &Launcher::DoDetectLaunched, task), + kDetectLaunchRetry); + } + + void Notify(Task* task) { + task->Run(); + delete task; + } + + ServiceProcessControl* process_; + scoped_ptr<CommandLine> cmd_line_; + bool launched_; +}; + +// ServiceProcessControl implementation. +ServiceProcessControl::ServiceProcessControl(Profile* profile, + ServiceProcessType type) + : profile_(profile), + type_(type), + message_handler_(NULL) { +} + +ServiceProcessControl::~ServiceProcessControl() { +} + +void ServiceProcessControl::Connect(Task* task) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (channel_.get()) { + task->Run(); + delete task; + return; + } + + // Saves the task. + connect_done_task_.reset(task); + ConnectInternal(); +} + +void ServiceProcessControl::ConnectInternal() { + LOG(INFO) << "Connecting to Service Process IPC Server"; + // Run the IPC channel on the shared IO thread. + base::Thread* io_thread = g_browser_process->io_thread(); + + // TODO(hclam): Determine the the channel id from profile and type. + const std::string channel_id = GetServiceProcessChannelName(type_); + channel_.reset( + new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL, + io_thread->message_loop(), true, + g_browser_process->shutdown_event())); + channel_->set_sync_messages_with_no_timeout_allowed(false); +} + +void ServiceProcessControl::Launch(Task* task) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (channel_.get()) { + task->Run(); + delete task; + return; + } + + // A service process should have a different mechanism for starting, but now + // we start it as if it is a child process. + FilePath exe_path = ChildProcessHost::GetChildPath(true); + if (exe_path.empty()) { + NOTREACHED() << "Unable to get service process binary name."; + } + + CommandLine* cmd_line = new CommandLine(exe_path); + cmd_line->AppendSwitchASCII(switches::kProcessType, + switches::kServiceProcess); + + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + FilePath user_data_dir = + browser_command_line.GetSwitchValuePath(switches::kUserDataDir); + if (!user_data_dir.empty()) + cmd_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir); + + std::string logging_level = browser_command_line.GetSwitchValueASCII( + switches::kLoggingLevel); + if (!logging_level.empty()) + cmd_line->AppendSwitchASCII(switches::kLoggingLevel, logging_level); + + // And then start the process asynchronously. + launcher_ = new Launcher(this, cmd_line); + launcher_->Run( + NewRunnableMethod(this, &ServiceProcessControl::OnProcessLaunched, task)); +} + +void ServiceProcessControl::OnProcessLaunched(Task* task) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (launcher_->launched()) { + // Now use the launch task as the connect task. + connect_done_task_.reset(task); + + // After we have successfully created the service process we try to connect + // to it. The launch task is transfered to a connect task. + ConnectInternal(); + } else { + // If we don't have process handle that means launching the service process + // has failed. + task->Run(); + delete task; + } + + // We don't need the launcher anymore. + launcher_ = NULL; +} + +void ServiceProcessControl::OnMessageReceived(const IPC::Message& message) { + if (!message_handler_) + return; + + if (message.type() == ServiceHostMsg_GoodDay::ID) + message_handler_->OnGoodDay(); +} + +void ServiceProcessControl::OnChannelConnected(int32 peer_pid) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + connect_done_task_->Run(); + connect_done_task_.reset(); +} + +void ServiceProcessControl::OnChannelError() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + channel_.reset(); + connect_done_task_->Run(); + connect_done_task_.reset(); +} + +bool ServiceProcessControl::Send(IPC::Message* message) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + return channel_->Send(message); +} + +bool ServiceProcessControl::SendHello() { + return Send(new ServiceMsg_Hello()); +} + +bool ServiceProcessControl::Shutdown() { + bool ret = Send(new ServiceMsg_Shutdown()); + channel_.reset(); + return ret; +} + +DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl); diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h new file mode 100644 index 0000000..469b17d --- /dev/null +++ b/chrome/browser/service/service_process_control.h @@ -0,0 +1,116 @@ +// Copyright (c) 2010 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 CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_H_ +#define CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_H_ + +#include <queue> + +#include "base/id_map.h" +#include "base/process.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "chrome/common/service_process_type.h" +#include "ipc/ipc_sync_channel.h" + +class Profile; + +// A ServiceProcessControl works as a portal between the service process and +// the browser process. +// +// It is used to start and terminate the service process. It is also used +// to send and receive IPC messages from the service process. +// +// THREADING +// +// This class is accessed on the UI thread through some UI actions. It then +// talks to the IPC channel on the IO thread. +class ServiceProcessControl : public IPC::Channel::Sender, + public IPC::Channel::Listener { + public: + typedef IDMap<ServiceProcessControl>::iterator iterator; + typedef std::queue<IPC::Message> MessageQueue; + + // An interface for handling messages received from the service process. + class MessageHandler { + public: + virtual ~MessageHandler() {} + // This is a test signal sent from the service process. This can be used + // the healthiness of the service. + virtual void OnGoodDay() = 0; + }; + + // Construct a ServiceProcessControl with |profile| and a specific |type|. + ServiceProcessControl(Profile* profile, ServiceProcessType type); + virtual ~ServiceProcessControl(); + + // Return the user profile associated with this service process. + Profile* profile() const { return profile_; } + + // Return the type of this object. + ServiceProcessType type() const { return type_; } + + // Return true if this object is connected to the service. + bool is_connected() const { return channel_.get() != NULL; } + + // Initialize the connection to the service process. + // |connect_done_task| is invoked if the connection has succeeded or failed. + // User should call is_connected() to check the connection status. + void Connect(Task* connect_done_task); + + // Create a new service process and connects to it. + // |launch_done_task| is called if launching the service process has failed + // or we have successfully launched the process and connected to it. + void Launch(Task* launch_done_task); + + // IPC::Channel::Listener implementation. + virtual void OnMessageReceived(const IPC::Message& message); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelError(); + + // IPC::Channel::Sender implementation + virtual bool Send(IPC::Message* message); + + // Send a hello message to the service process for testing purpose. + // Return true if the message was sent. + bool SendHello(); + + // Send a shutdown message to the service process. IPC channel will be + // destroyed after calling this method. + // Return true if the message was sent. + bool Shutdown(); + + // Set the message handler for receiving messages from the service process. + // TODO(hclam): Allow more than 1 handler. + void SetMessageHandler(MessageHandler* message_handler) { + message_handler_ = message_handler; + } + + private: + class Launcher; + + // Method called by Launcher when the service process is launched. + void OnProcessLaunched(Task* launch_done_task); + + // Used internally to connect to the service process. + void ConnectInternal(); + + Profile* profile_; + ServiceProcessType type_; + + // IPC channel to the service process. + scoped_ptr<IPC::SyncChannel> channel_; + + // Service process launcher. + scoped_refptr<Launcher> launcher_; + + // Callback that gets invoked when the channel is connected or failed to + // connect. + scoped_ptr<Task> connect_done_task_; + + // Handler for messages from service process. + MessageHandler* message_handler_; +}; + +#endif // CHROME_BROWSER_SERVICE_SERVICE_PROCESS_H_ diff --git a/chrome/browser/service/service_process_control_browsertest.cc b/chrome/browser/service/service_process_control_browsertest.cc new file mode 100644 index 0000000..0dda5fa --- /dev/null +++ b/chrome/browser/service/service_process_control_browsertest.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2010 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 "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/service/service_process_control.h" +#include "chrome/browser/service/service_process_control_manager.h" +#include "chrome/common/service_process_type.h" + +class ServiceProcessControlBrowserTest + : public InProcessBrowserTest, + public ServiceProcessControl::MessageHandler { + protected: + void LaunchServiceProcessControl() { + ServiceProcessControl* process = + ServiceProcessControlManager::instance()->GetProcessControl( + browser()->profile(), kServiceProcessCloudPrint); + process_ = process; + + // Launch the process asynchronously. + process->Launch( + NewRunnableMethod( + this, + &ServiceProcessControlBrowserTest::ProcessControlLaunched)); + + // Then run the message loop to keep things running. + ui_test_utils::RunMessageLoop(); + } + + void SayHelloAndWait() { + // Send a hello message to the service process and wait for a reply. + process()->SendHello(); + ui_test_utils::RunMessageLoop(); + } + + void ProcessControlLaunched() { + process()->SetMessageHandler(this); + // Quit the current message. + MessageLoop::current()->Quit(); + } + + // ServiceProcessControl::MessageHandler implementations. + virtual void OnGoodDay() { + MessageLoop::current()->Quit(); + } + + ServiceProcessControl* process() { return process_; } + + private: + ServiceProcessControl* process_; +}; + +#if defined(OS_WIN) +// They way that the IPC is implemented only works on windows. This has to +// change when we implement a different scheme for IPC. +IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchAndIPC) { + LaunchServiceProcessControl(); + + // Make sure we are connected to the service process. + EXPECT_TRUE(process()->is_connected()); + SayHelloAndWait(); + + // And then shutdown the service process. + EXPECT_TRUE(process()->Shutdown()); +} +#endif + +DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest); diff --git a/chrome/browser/service/service_process_control_manager.cc b/chrome/browser/service/service_process_control_manager.cc new file mode 100644 index 0000000..821de9a --- /dev/null +++ b/chrome/browser/service/service_process_control_manager.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2010 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 "chrome/browser/service/service_process_control_manager.h" + +#include "base/singleton.h" +#include "base/stl_util-inl.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/service/service_process_control.h" + +ServiceProcessControlManager::ServiceProcessControlManager() { +} + +ServiceProcessControlManager::~ServiceProcessControlManager() { + DCHECK(process_control_list_.empty()); +} + +ServiceProcessControl* ServiceProcessControlManager::GetProcessControl( + Profile* profile, ServiceProcessType type) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + // TODO(hclam): We will have different service process for different types of + // service, but now we only create a new process for a different profile. + for (ServiceProcessControlList::iterator i = process_control_list_.begin(); + i != process_control_list_.end(); ++i) { + if ((*i)->profile() == profile) + return *i; + } + + // Couldn't find a ServiceProcess so construct a new one. + ServiceProcessControl* process = new ServiceProcessControl(profile, type); + process_control_list_.push_back(process); + return process; +} + +void ServiceProcessControlManager::Shutdown() { + STLDeleteElements(&process_control_list_); +} + +// static +ServiceProcessControlManager* ServiceProcessControlManager::instance() { + return Singleton<ServiceProcessControlManager>::get(); +} diff --git a/chrome/browser/service/service_process_control_manager.h b/chrome/browser/service/service_process_control_manager.h new file mode 100644 index 0000000..c57f65c --- /dev/null +++ b/chrome/browser/service/service_process_control_manager.h @@ -0,0 +1,45 @@ +// Copyright (c) 2010 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 CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_MANAGER_H_ +#define CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_MANAGER_H_ + +#include <vector> + +#include "chrome/common/service_process_type.h" + +class Profile; +class ServiceProcessControl; + +// ServiceProcessControlManager is a registrar for all ServiceProcess created +// in the browser process. It is also a factory for creating new +// ServiceProcess. +class ServiceProcessControlManager { + public: + typedef std::vector<ServiceProcessControl*> ServiceProcessControlList; + + ServiceProcessControlManager(); + ~ServiceProcessControlManager(); + + // Get the ServiceProcess instance corresponding to |profile| and |type|. + // If such an instance doesn't exist a new instance is created. + // + // There will be at most one ServiceProcess for a |profile| and |type| + // pair. + // + // This method should only be accessed on the UI thread. + ServiceProcessControl* GetProcessControl(Profile* profile, + ServiceProcessType type); + + // Destroy all ServiceProcess objects created. + void Shutdown(); + + // Return the instance of ServiceProcessControlManager. + static ServiceProcessControlManager* instance(); + + private: + ServiceProcessControlList process_control_list_; +}; + +#endif // CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_MANAGER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 6ff3ee1..c9ad4c9 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2330,6 +2330,10 @@ 'browser/search_engines/template_url_table_model.h', 'browser/search_engines/util.cc', 'browser/search_engines/util.h', + 'browser/service/service_process_control_manager.cc', + 'browser/service/service_process_control_manager.h', + 'browser/service/service_process_control.cc', + 'browser/service/service_process_control.h', 'browser/session_startup_pref.cc', 'browser/session_startup_pref.h', 'browser/sessions/base_session_service.cc', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 28135c5c3..5719444 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -265,6 +265,9 @@ 'common/service_messages.cc', 'common/service_messages.h', 'common/services_messages_internal.h', + 'common/service_process_type.h', + 'common/service_process_util.cc', + 'common/service_process_util.h', 'common/socket_stream_dispatcher.cc', 'common/socket_stream_dispatcher.h', 'common/spellcheck_common.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 4e3ff33..0c558d3 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1626,6 +1626,7 @@ 'browser/renderer_host/test/render_process_host_browsertest.cc', 'browser/renderer_host/test/render_view_host_manager_browsertest.cc', 'browser/safe_browsing/safe_browsing_browsertest.cc', + 'browser/service/service_process_control_browsertest.cc', 'browser/sessions/session_restore_browsertest.cc', 'browser/speech/enable_speech_input_switch_browsertest.cc', 'browser/speech/speech_input_browsertest.cc', diff --git a/chrome/common/service_messages_internal.h b/chrome/common/service_messages_internal.h index 4968db0..99d1dd8 100644 --- a/chrome/common/service_messages_internal.h +++ b/chrome/common/service_messages_internal.h @@ -29,6 +29,12 @@ IPC_BEGIN_MESSAGES(Service) // Tell the service process to disable the cloud proxy. IPC_MESSAGE_CONTROL0(ServiceMsg_DisableCloudPrintProxy) + // This message is for testing purpose. + IPC_MESSAGE_CONTROL0(ServiceMsg_Hello) + + // Tell the service process to shutdown. + IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown) + IPC_END_MESSAGES(Service) //------------------------------------------------------------------------------ @@ -39,5 +45,8 @@ IPC_BEGIN_MESSAGES(ServiceHost) // Sent when the cloud print proxy has an authentication error. IPC_MESSAGE_CONTROL0(ServiceHostMsg_CloudPrintProxy_AuthError) + // Sent from the service process in response to a Hello message. + IPC_MESSAGE_CONTROL0(ServiceHostMsg_GoodDay) + IPC_END_MESSAGES(ServiceHost) diff --git a/chrome/common/service_process_type.h b/chrome/common/service_process_type.h new file mode 100644 index 0000000..7f80ede --- /dev/null +++ b/chrome/common/service_process_type.h @@ -0,0 +1,17 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SERVICE_PROCESS_TYPE_H_ +#define CHROME_COMMON_SERVICE_PROCESS_TYPE_H_ + +// Defines different types of service process. +enum ServiceProcessType { + // A service process that hosts a cloud print proxy. + kServiceProcessCloudPrint, + + // A service process that hosts a remoting host process. + kServiceProcessRemoting, +}; + +#endif // CHROME_COMMON_SERVICE_PROCESS_TYPE_H_ diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc new file mode 100644 index 0000000..4be6991 --- /dev/null +++ b/chrome/common/service_process_util.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2010 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 "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/service_process_util.h" + +// TODO(hclam): |type| is not used at all. Different types of service process +// should have a different instance of process and channel. +std::string GetServiceProcessChannelName(ServiceProcessType type) { + FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + + // TODO(sanjeevr): We need to actually figure out the right way to determine + // a channel name. The below is to facilitate testing only. +#if defined(OS_WIN) + std::string channel_name = WideToUTF8(user_data_dir.value()); +#elif defined(OS_POSIX) + std::string channel_name = user_data_dir.value(); +#endif // defined(OS_WIN) + std::replace(channel_name.begin(), channel_name.end(), '\\', '!'); + channel_name.append("_service_ipc"); + return channel_name; +} + +// Gets the name of the lock file for service process. +static FilePath GetServiceProcessLockFilePath(ServiceProcessType type) { + FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + return user_data_dir.Append(FILE_PATH_LITERAL("Service Process.Lock")); +} + +bool CreateServiceProcessLockFile(ServiceProcessType type) { + const FilePath path = GetServiceProcessLockFilePath(type); + FILE* file = file_util::OpenFile(path, "wb+"); + if (!file) + return false; + LOG(INFO) << "Created Service Process lock file: " << path.value(); + return file_util::TruncateFile(file) && file_util::CloseFile(file); +} + +bool DeleteServiceProcessLockFile(ServiceProcessType type) { + const FilePath path = GetServiceProcessLockFilePath(type); + return file_util::Delete(path, false); +} + +bool CheckServiceProcessRunning(ServiceProcessType type) { + const FilePath path = GetServiceProcessLockFilePath(type); + return file_util::PathExists(path); +} diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h new file mode 100644 index 0000000..9894b1e --- /dev/null +++ b/chrome/common/service_process_util.h @@ -0,0 +1,43 @@ +// Copyright (c) 2010 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 CHROME_COMMON_SERVICE_PROCESS_UTIL_H_ +#define CHROME_COMMON_SERVICE_PROCESS_UTIL_H_ + +#include <string> + +#include "chrome/common/service_process_type.h" + +class Profile; + +// Return the IPC channel to connect to the service process with |profile| +// and |type|. +// +// TODO(hclam): Need more information to come up with the channel name. +std::string GetServiceProcessChannelName(ServiceProcessType type); + +// The following methods are used as a mechanism to signal a service process +// is running properly and all initialized. +// +// The way it works is that we will create a file on the file system to indicate +// that service process is running. This way the browser process will know that +// it can connect to it without problem. +// +// When the service process this lock file is deleted. + +// This method is called when the service process is running and initialized. +// Return true if lock file was created. +bool CreateServiceProcessLockFile(ServiceProcessType type); + +// This method deletes the lock file created by this above method. +// Return true if lock file was deleted. +bool DeleteServiceProcessLockFile(ServiceProcessType type); + +// This method checks that if the service process lock file exists. This means +// that the service process is running. +// TODO(hclam): We should use a better mechanism to detect that a service +// process is running. +bool CheckServiceProcessRunning(ServiceProcessType type); + +#endif // CHROME_COMMON_SERVICE_PROCESS_UTIL_H_ diff --git a/chrome/service/service_ipc_server.cc b/chrome/service/service_ipc_server.cc index 2199d00..116374f 100644 --- a/chrome/service/service_ipc_server.cc +++ b/chrome/service/service_ipc_server.cc @@ -66,6 +66,8 @@ void ServiceIPCServer::OnMessageReceived(const IPC::Message& msg) { OnEnableCloudPrintProxyWithTokens) IPC_MESSAGE_HANDLER(ServiceMsg_DisableCloudPrintProxy, OnDisableCloudPrintProxy) + IPC_MESSAGE_HANDLER(ServiceMsg_Hello, OnHello); + IPC_MESSAGE_HANDLER(ServiceMsg_Shutdown, OnShutdown); IPC_END_MESSAGE_MAP() } @@ -83,3 +85,10 @@ void ServiceIPCServer::OnDisableCloudPrintProxy() { g_service_process->GetCloudPrintProxy()->DisableForUser(); } +void ServiceIPCServer::OnHello() { + channel_->Send(new ServiceHostMsg_GoodDay()); +} + +void ServiceIPCServer::OnShutdown() { + g_service_process->Shutdown(); +} diff --git a/chrome/service/service_ipc_server.h b/chrome/service/service_ipc_server.h index 9e9b355..521830e 100644 --- a/chrome/service/service_ipc_server.h +++ b/chrome/service/service_ipc_server.h @@ -41,6 +41,8 @@ class ServiceIPCServer : public IPC::Channel::Listener, void OnEnableCloudPrintProxyWithTokens(const std::string& cloud_print_token, const std::string& talk_token); void OnDisableCloudPrintProxy(); + void OnHello(); + void OnShutdown(); std::string channel_name_; scoped_ptr<IPC::SyncChannel> channel_; diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc index fbd9c8d..77e8cf0 100644 --- a/chrome/service/service_process.cc +++ b/chrome/service/service_process.cc @@ -11,6 +11,8 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/json_pref_store.h" +#include "chrome/common/service_process_type.h" +#include "chrome/common/service_process_util.h" #include "chrome/service/cloud_print/cloud_print_proxy.h" #include "chrome/service/service_ipc_server.h" #include "net/base/network_change_notifier.h" @@ -62,22 +64,24 @@ bool ServiceProcess::Initialize(MessageLoop* message_loop) { service_prefs_.reset(new JsonPrefStore(pref_path, file_thread_->message_loop_proxy())); service_prefs_->ReadPrefs(); - // TODO(sanjeevr): We need to actually figure out the right way to determine - // a channel name. The below is to facilitate testing only. -#if defined(OS_WIN) - std::string channel_name = WideToUTF8(user_data_dir.value()); -#elif defined(OS_POSIX) - std::string channel_name = user_data_dir.value(); -#endif // defined(OS_WIN) - - std::replace(channel_name.begin(), channel_name.end(), '\\', '!'); - channel_name.append("_service_ipc"); - ipc_server_.reset(new ServiceIPCServer(channel_name)); + + // TODO(hclam): Each type of service process should has it own instance of + // process and thus channel, but now we have only one process for all types + // so the type parameter doesn't matter now. + LOG(INFO) << "Starting Service Process IPC Server"; + ipc_server_.reset(new ServiceIPCServer( + GetServiceProcessChannelName(kServiceProcessCloudPrint))); ipc_server_->Init(); - return true; + + // After the IPC server has started we can create the lock file to indicate + // that we have started. + bool ret = CreateServiceProcessLockFile(kServiceProcessCloudPrint); + DCHECK(ret) << "Failed to create service process lock file."; + return ret; } bool ServiceProcess::Teardown() { + // TODO(hclam): Remove this as this looks like dead code. if (service_prefs_.get()) { service_prefs_->WritePrefs(); service_prefs_.reset(); @@ -98,7 +102,15 @@ bool ServiceProcess::Teardown() { // might use it have been shut down. network_change_notifier_.reset(); - return true; + // Delete the service process lock file when it shuts down. + bool ret = DeleteServiceProcessLockFile(kServiceProcessCloudPrint); + DCHECK(ret) << "Failed to delete service process lock file."; + return ret; +} + +void ServiceProcess::Shutdown() { + // Quit the main message loop. + main_message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); } CloudPrintProxy* ServiceProcess::GetCloudPrintProxy() { diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h index d4babce..55c7c19 100644 --- a/chrome/service/service_process.h +++ b/chrome/service/service_process.h @@ -65,6 +65,9 @@ class ServiceProcess { return &shutdown_event_; } + // Shutdown the service process. This is likely triggered by a IPC message. + void Shutdown(); + CloudPrintProxy* GetCloudPrintProxy(); #if defined(ENABLE_REMOTING) @@ -116,7 +119,7 @@ class ServiceProcess { // An event that will be signalled when we shutdown. base::WaitableEvent shutdown_event_; - // The main message loop for the service process. + // Pointer to the main message loop that host this object. MessageLoop* main_message_loop_; DISALLOW_COPY_AND_ASSIGN(ServiceProcess); |