summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-12 01:07:24 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-12 01:07:24 +0000
commit50307586363272bb8b133004889772b4919ad8fd (patch)
treea7e73d040cbd3d846e60570abd68c731f85b3e48 /chrome
parent7e8a83c5f13b6ed0c5be202f5697efc07cee06ce (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/browser/service/service_process_control.cc212
-rw-r--r--chrome/browser/service/service_process_control.h116
-rw-r--r--chrome/browser/service/service_process_control_browsertest.cc70
-rw-r--r--chrome/browser/service/service_process_control_manager.cc45
-rw-r--r--chrome/browser/service/service_process_control_manager.h45
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_common.gypi3
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/service_messages_internal.h9
-rw-r--r--chrome/common/service_process_type.h17
-rw-r--r--chrome/common/service_process_util.cc55
-rw-r--r--chrome/common/service_process_util.h43
-rw-r--r--chrome/service/service_ipc_server.cc9
-rw-r--r--chrome/service/service_ipc_server.h2
-rw-r--r--chrome/service/service_process.cc38
-rw-r--r--chrome/service/service_process.h5
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);