diff options
Diffstat (limited to 'chrome/browser/service')
-rw-r--r-- | chrome/browser/service/OWNERS | 5 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control.cc | 406 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control.h | 219 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control_browsertest.cc | 294 | ||||
-rw-r--r-- | chrome/browser/service/service_process_control_mac.mm | 28 |
5 files changed, 0 insertions, 952 deletions
diff --git a/chrome/browser/service/OWNERS b/chrome/browser/service/OWNERS deleted file mode 100644 index 0b59272..0000000 --- a/chrome/browser/service/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -ajwong@chromium.org -gene@chromium.org -hclam@chromium.org -scottbyer@chromium.org -vitalybuka@chromium.org diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc deleted file mode 100644 index 9dcd03e8f..0000000 --- a/chrome/browser/service/service_process_control.cc +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright (c) 2012 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/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_delta_serialization.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/stl_util.h" -#include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/upgrade_detector.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/service_messages.h" -#include "chrome/common/service_process_util.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" -#include "content/public/common/child_process_host.h" -#include "google_apis/gaia/gaia_switches.h" -#include "ui/base/ui_base_switches.h" - -using content::BrowserThread; -using content::ChildProcessHost; - -// ServiceProcessControl implementation. -ServiceProcessControl::ServiceProcessControl() { -} - -ServiceProcessControl::~ServiceProcessControl() { -} - -void ServiceProcessControl::ConnectInternal() { - // If the channel has already been established then we run the task - // and return. - if (channel_.get()) { - RunConnectDoneTasks(); - return; - } - - // Actually going to connect. - VLOG(1) << "Connecting to Service Process IPC Server"; - - // TODO(hclam): Handle error connecting to channel. - const IPC::ChannelHandle channel_id = GetServiceProcessChannel(); - SetChannel(new IPC::ChannelProxy( - channel_id, - IPC::Channel::MODE_NAMED_CLIENT, - this, - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get())); -} - -void ServiceProcessControl::SetChannel(IPC::ChannelProxy* channel) { - channel_.reset(channel); -} - -void ServiceProcessControl::RunConnectDoneTasks() { - // The tasks executed here may add more tasks to the vector. So copy - // them to the stack before executing them. This way recursion is - // avoided. - TaskList tasks; - - if (IsConnected()) { - tasks.swap(connect_success_tasks_); - RunAllTasksHelper(&tasks); - DCHECK(tasks.empty()); - connect_failure_tasks_.clear(); - } else { - tasks.swap(connect_failure_tasks_); - RunAllTasksHelper(&tasks); - DCHECK(tasks.empty()); - connect_success_tasks_.clear(); - } -} - -// static -void ServiceProcessControl::RunAllTasksHelper(TaskList* task_list) { - TaskList::iterator index = task_list->begin(); - while (index != task_list->end()) { - (*index).Run(); - index = task_list->erase(index); - } -} - -bool ServiceProcessControl::IsConnected() const { - return channel_ != NULL; -} - -void ServiceProcessControl::Launch(const base::Closure& success_task, - const base::Closure& failure_task) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - base::Closure failure = failure_task; - if (!success_task.is_null()) - connect_success_tasks_.push_back(success_task); - - if (!failure.is_null()) - connect_failure_tasks_.push_back(failure); - - // If we already in the process of launching, then we are done. - if (launcher_.get()) - return; - - // If the service process is already running then connects to it. - if (CheckServiceProcessReady()) { - ConnectInternal(); - return; - } - - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", SERVICE_EVENT_LAUNCH, - SERVICE_EVENT_MAX); - - // A service process should have a different mechanism for starting, but now - // we start it as if it is a child process. - -#if defined(OS_LINUX) - int flags = ChildProcessHost::CHILD_ALLOW_SELF; -#else - int flags = ChildProcessHost::CHILD_NORMAL; -#endif - - base::FilePath exe_path = ChildProcessHost::GetChildPath(flags); - 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); - - static const char* const kSwitchesToCopy[] = { - switches::kCloudPrintServiceURL, - switches::kCloudPrintSetupProxy, - switches::kEnableLogging, - switches::kIgnoreUrlFetcherCertRequests, - switches::kLang, - switches::kLoggingLevel, - switches::kLsoUrl, - switches::kNoServiceAutorun, - switches::kUserDataDir, - switches::kV, - switches::kVModule, - switches::kWaitForDebugger, - }; - cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), - kSwitchesToCopy, - arraysize(kSwitchesToCopy)); - - // And then start the process asynchronously. - launcher_ = new Launcher(this, cmd_line); - launcher_->Run(base::Bind(&ServiceProcessControl::OnProcessLaunched, - base::Unretained(this))); -} - -void ServiceProcessControl::Disconnect() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - channel_.reset(); -} - -void ServiceProcessControl::OnProcessLaunched() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (launcher_->launched()) { - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_LAUNCHED, SERVICE_EVENT_MAX); - // 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 { - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_LAUNCH_FAILED, SERVICE_EVENT_MAX); - // If we don't have process handle that means launching the service process - // has failed. - RunConnectDoneTasks(); - } - - // We don't need the launcher anymore. - launcher_ = NULL; -} - -bool ServiceProcessControl::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ServiceProcessControl, message) - IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_Info, - OnCloudPrintProxyInfo) - IPC_MESSAGE_HANDLER(ServiceHostMsg_Histograms, OnHistograms) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void ServiceProcessControl::OnChannelConnected(int32 peer_pid) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_CHANNEL_CONNECTED, SERVICE_EVENT_MAX); - - // We just established a channel with the service process. Notify it if an - // upgrade is available. - if (UpgradeDetector::GetInstance()->notify_upgrade()) { - Send(new ServiceMsg_UpdateAvailable); - } else { - if (registrar_.IsEmpty()) - registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED, - content::NotificationService::AllSources()); - } - RunConnectDoneTasks(); -} - -void ServiceProcessControl::OnChannelError() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_CHANNEL_ERROR, SERVICE_EVENT_MAX); - - channel_.reset(); - RunConnectDoneTasks(); -} - -bool ServiceProcessControl::Send(IPC::Message* message) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!channel_.get()) - return false; - return channel_->Send(message); -} - -// content::NotificationObserver implementation. -void ServiceProcessControl::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - if (type == chrome::NOTIFICATION_UPGRADE_RECOMMENDED) { - Send(new ServiceMsg_UpdateAvailable); - } -} - -void ServiceProcessControl::OnCloudPrintProxyInfo( - const cloud_print::CloudPrintProxyInfo& proxy_info) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_INFO_REPLY, SERVICE_EVENT_MAX); - if (!cloud_print_info_callback_.is_null()) { - cloud_print_info_callback_.Run(proxy_info); - cloud_print_info_callback_.Reset(); - } -} - -void ServiceProcessControl::OnHistograms( - const std::vector<std::string>& pickled_histograms) { - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_HISTOGRAMS_REPLY, SERVICE_EVENT_MAX); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - base::HistogramDeltaSerialization::DeserializeAndAddSamples( - pickled_histograms); - RunHistogramsCallback(); -} - -void ServiceProcessControl::RunHistogramsCallback() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!histograms_callback_.is_null()) { - histograms_callback_.Run(); - histograms_callback_.Reset(); - } - histograms_timeout_callback_.Cancel(); -} - -bool ServiceProcessControl::GetCloudPrintProxyInfo( - const CloudPrintProxyInfoHandler& cloud_print_info_callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(!cloud_print_info_callback.is_null()); - cloud_print_info_callback_.Reset(); - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_INFO_REQUEST, SERVICE_EVENT_MAX); - if (!Send(new ServiceMsg_GetCloudPrintProxyInfo())) - return false; - cloud_print_info_callback_ = cloud_print_info_callback; - return true; -} - -bool ServiceProcessControl::GetHistograms( - const base::Closure& histograms_callback, - const base::TimeDelta& timeout) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(!histograms_callback.is_null()); - histograms_callback_.Reset(); - - // If the service process is already running then connect to it. - if (!CheckServiceProcessReady()) - return false; - ConnectInternal(); - - UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", - SERVICE_EVENT_HISTOGRAMS_REQUEST, - SERVICE_EVENT_MAX); - - if (!Send(new ServiceMsg_GetHistograms())) - return false; - - // Run timeout task to make sure |histograms_callback| is called. - histograms_timeout_callback_.Reset( - base::Bind(&ServiceProcessControl::RunHistogramsCallback, - base::Unretained(this))); - BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, - histograms_timeout_callback_.callback(), - timeout); - - histograms_callback_ = histograms_callback; - return true; -} - -bool ServiceProcessControl::Shutdown() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - bool ret = Send(new ServiceMsg_Shutdown()); - channel_.reset(); - return ret; -} - -// static -ServiceProcessControl* ServiceProcessControl::GetInstance() { - return Singleton<ServiceProcessControl>::get(); -} - -ServiceProcessControl::Launcher::Launcher(ServiceProcessControl* process, - CommandLine* cmd_line) - : process_(process), - cmd_line_(cmd_line), - launched_(false), - retry_count_(0), - process_handle_(base::kNullProcessHandle) { -} - -// Execute the command line to start the process asynchronously. -// After the command is executed, |task| is called with the process handle on -// the UI thread. -void ServiceProcessControl::Launcher::Run(const base::Closure& task) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - notify_task_ = task; - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, - base::Bind(&Launcher::DoRun, this)); -} - -ServiceProcessControl::Launcher::~Launcher() { - CloseProcessHandle(); -} - - -void ServiceProcessControl::Launcher::Notify() { - DCHECK(!notify_task_.is_null()); - notify_task_.Run(); - notify_task_.Reset(); -} - -void ServiceProcessControl::Launcher::CloseProcessHandle() { - if (process_handle_ != base::kNullProcessHandle) { - base::CloseProcessHandle(process_handle_); - process_handle_ = base::kNullProcessHandle; - } -} - -#if !defined(OS_MACOSX) -void ServiceProcessControl::Launcher::DoDetectLaunched() { - DCHECK(!notify_task_.is_null()); - - const uint32 kMaxLaunchDetectRetries = 10; - launched_ = CheckServiceProcessReady(); - - int exit_code = 0; - if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries) || - base::WaitForExitCodeWithTimeout(process_handle_, &exit_code, - base::TimeDelta())) { - CloseProcessHandle(); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::Bind(&Launcher::Notify, this)); - return; - } - retry_count_++; - - // If the service process is not launched yet then check again in 2 seconds. - const base::TimeDelta kDetectLaunchRetry = base::TimeDelta::FromSeconds(2); - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, base::Bind(&Launcher::DoDetectLaunched, this), - kDetectLaunchRetry); -} - -void ServiceProcessControl::Launcher::DoRun() { - DCHECK(!notify_task_.is_null()); - - base::LaunchOptions options; -#if defined(OS_WIN) - options.start_hidden = true; -#endif - if (base::LaunchProcess(*cmd_line_, options, &process_handle_)) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&Launcher::DoDetectLaunched, this)); - } else { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::Bind(&Launcher::Notify, this)); - } -} -#endif // !OS_MACOSX diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h deleted file mode 100644 index 88a2731..0000000 --- a/chrome/browser/service/service_process_control.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2012 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 <set> -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/cancelable_callback.h" -#include "base/id_map.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/process/process.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_listener.h" -#include "ipc/ipc_sender.h" - -class CommandLine; - -namespace cloud_print { -struct CloudPrintProxyInfo; -} // namespace cloud_print - -// 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::Sender, - public IPC::Listener, - public content::NotificationObserver { - public: - enum ServiceProcessEvent { - SERVICE_EVENT_INITIALIZE, - SERVICE_EVENT_ENABLED_ON_LAUNCH, - SERVICE_EVENT_ENABLE, - SERVICE_EVENT_DISABLE, - SERVICE_EVENT_DISABLE_BY_POLICY, - SERVICE_EVENT_LAUNCH, - SERVICE_EVENT_LAUNCHED, - SERVICE_EVENT_LAUNCH_FAILED, - SERVICE_EVENT_CHANNEL_CONNECTED, - SERVICE_EVENT_CHANNEL_ERROR, - SERVICE_EVENT_INFO_REQUEST, - SERVICE_EVENT_INFO_REPLY, - SERVICE_EVENT_HISTOGRAMS_REQUEST, - SERVICE_EVENT_HISTOGRAMS_REPLY, - SERVICE_EVENT_MAX, - }; - - typedef IDMap<ServiceProcessControl>::iterator iterator; - typedef std::queue<IPC::Message> MessageQueue; - typedef base::Callback<void(const cloud_print::CloudPrintProxyInfo&)> - CloudPrintProxyInfoHandler; - - // Returns the singleton instance of this class. - static ServiceProcessControl* GetInstance(); - - // Return true if this object is connected to the service. - // Virtual for testing. - virtual bool IsConnected() const; - - // If no service process is currently running, creates a new service process - // and connects to it. If a service process is already running this method - // will try to connect to it. - // |success_task| is called when we have successfully launched the process - // and connected to it. - // |failure_task| is called when we failed to connect to the service process. - // It is OK to pass the same value for |success_task| and |failure_task|. In - // this case, the task is invoked on success or failure. - // Note that if we are already connected to service process then - // |success_task| can be invoked in the context of the Launch call. - // Virtual for testing. - virtual void Launch(const base::Closure& success_task, - const base::Closure& failure_task); - - // Disconnect the IPC channel from the service process. - // Virtual for testing. - virtual void Disconnect(); - - // IPC::Listener implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; - virtual void OnChannelError() OVERRIDE; - - // IPC::Sender implementation - virtual bool Send(IPC::Message* message) OVERRIDE; - - // content::NotificationObserver implementation. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - // Send a shutdown message to the service process. IPC channel will be - // destroyed after calling this method. - // Return true if the message was sent. - // Virtual for testing. - virtual bool Shutdown(); - - // Send request for cloud print proxy info (enabled state, email, proxy id). - // The callback gets the information when received. - // Returns true if request was sent. Callback will be called only in case of - // reply from service. The method resets any previous callback. - // This call starts service if needed. - bool GetCloudPrintProxyInfo( - const CloudPrintProxyInfoHandler& cloud_print_status_callback); - - // Send request for histograms collected in service process. - // Returns true if request was sent, and callback will be called in case of - // success or timeout. The method resets any previous callback. - // Returns false if service is not running or other failure, callback will not - // be called in this case. - bool GetHistograms(const base::Closure& cloud_print_status_callback, - const base::TimeDelta& timeout); - - private: - // This class is responsible for launching the service process on the - // PROCESS_LAUNCHER thread. - class Launcher - : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> { - public: - Launcher(ServiceProcessControl* process, CommandLine* cmd_line); - // Execute the command line to start the process asynchronously. After the - // command is executed |task| is called with the process handle on the UI - // thread. - void Run(const base::Closure& task); - - bool launched() const { return launched_; } - - private: - friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>; - virtual ~Launcher(); - -#if !defined(OS_MACOSX) - void DoDetectLaunched(); -#endif // !OS_MACOSX - - void DoRun(); - void Notify(); - void CloseProcessHandle(); - ServiceProcessControl* process_; - scoped_ptr<CommandLine> cmd_line_; - base::Closure notify_task_; - bool launched_; - uint32 retry_count_; - base::ProcessHandle process_handle_; - }; - - friend class MockServiceProcessControl; - friend class CloudPrintProxyPolicyStartupTest; - - ServiceProcessControl(); - virtual ~ServiceProcessControl(); - - friend struct DefaultSingletonTraits<ServiceProcessControl>; - - typedef std::vector<base::Closure> TaskList; - - // Message handlers - void OnCloudPrintProxyInfo( - const cloud_print::CloudPrintProxyInfo& proxy_info); - void OnHistograms(const std::vector<std::string>& pickled_histograms); - - // Runs callback provided in |GetHistograms()|. - void RunHistogramsCallback(); - - // Helper method to invoke all the callbacks based on success or failure. - void RunConnectDoneTasks(); - - // Method called by Launcher when the service process is launched. - void OnProcessLaunched(); - - // Used internally to connect to the service process. - void ConnectInternal(); - - // Takes ownership of the pointer. Split out for testing. - void SetChannel(IPC::ChannelProxy* channel); - - static void RunAllTasksHelper(TaskList* task_list); - - // IPC channel to the service process. - scoped_ptr<IPC::ChannelProxy> channel_; - - // Service process launcher. - scoped_refptr<Launcher> launcher_; - - // Callbacks that get invoked when the channel is successfully connected. - TaskList connect_success_tasks_; - // Callbacks that get invoked when there was a connection failure. - TaskList connect_failure_tasks_; - - // Callback that gets invoked when a status message is received from - // the cloud print proxy. - CloudPrintProxyInfoHandler cloud_print_info_callback_; - - // Callback that gets invoked when a message with histograms is received from - // the service process. - base::Closure histograms_callback_; - - content::NotificationRegistrar registrar_; - - // Callback that gets invoked if service didn't reply in time. - base::CancelableClosure histograms_timeout_callback_; -}; - -#endif // CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_H_ diff --git a/chrome/browser/service/service_process_control_browsertest.cc b/chrome/browser/service/service_process_control_browsertest.cc deleted file mode 100644 index 7ea8cc5..0000000 --- a/chrome/browser/service/service_process_control_browsertest.cc +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (c) 2012 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/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/path_service.h" -#include "base/process/kill.h" -#include "base/process/process_handle.h" -#include "base/process/process_iterator.h" -#include "base/test/test_timeouts.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_version_info.h" -#include "chrome/common/service_process_util.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/ui_test_utils.h" -#include "content/public/common/content_paths.h" -#include "content/public/common/content_switches.h" -#include "testing/gmock/include/gmock/gmock.h" - -class ServiceProcessControlBrowserTest - : public InProcessBrowserTest { - public: - ServiceProcessControlBrowserTest() - : service_process_handle_(base::kNullProcessHandle) { - } - virtual ~ServiceProcessControlBrowserTest() { - base::CloseProcessHandle(service_process_handle_); - service_process_handle_ = base::kNullProcessHandle; - } - - void HistogramsCallback() { - MockHistogramsCallback(); - QuitMessageLoop(); - } - - MOCK_METHOD0(MockHistogramsCallback, void()); - - protected: - void LaunchServiceProcessControl() { - // Launch the process asynchronously. - ServiceProcessControl::GetInstance()->Launch( - base::Bind(&ServiceProcessControlBrowserTest::ProcessControlLaunched, - this), - base::Bind( - &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed, - this)); - - // Then run the message loop to keep things running. - content::RunMessageLoop(); - } - - static void QuitMessageLoop() { - base::MessageLoop::current()->Quit(); - } - - static void CloudPrintInfoCallback( - const cloud_print::CloudPrintProxyInfo& proxy_info) { - QuitMessageLoop(); - } - - void Disconnect() { - // This will close the IPC connection. - ServiceProcessControl::GetInstance()->Disconnect(); - } - - virtual void SetUp() OVERRIDE { - service_process_handle_ = base::kNullProcessHandle; - } - - virtual void TearDown() OVERRIDE { - if (ServiceProcessControl::GetInstance()->IsConnected()) - EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); -#if defined(OS_MACOSX) - // ForceServiceProcessShutdown removes the process from launched on Mac. - ForceServiceProcessShutdown("", 0); -#endif // OS_MACOSX - if (service_process_handle_ != base::kNullProcessHandle) { - EXPECT_TRUE(base::WaitForSingleProcess( - service_process_handle_, - TestTimeouts::action_max_timeout())); - service_process_handle_ = base::kNullProcessHandle; - } - } - - void ProcessControlLaunched() { - base::ProcessId service_pid; - EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); - EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); - EXPECT_TRUE(base::OpenProcessHandleWithAccess( - service_pid, - base::kProcessAccessWaitForTermination | - // we need query permission to get exit code - base::kProcessAccessQueryInformation, - &service_process_handle_)); - // Quit the current message. Post a QuitTask instead of just calling Quit() - // because this can get invoked in the context of a Launch() call and we - // may not be in Run() yet. - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::QuitClosure()); - } - - void ProcessControlLaunchFailed() { - ADD_FAILURE(); - // Quit the current message. - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::QuitClosure()); - } - - private: - base::ProcessHandle service_process_handle_; -}; - -class RealServiceProcessControlBrowserTest - : public ServiceProcessControlBrowserTest { - public: - virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { - ServiceProcessControlBrowserTest::SetUpCommandLine(command_line); - base::FilePath exe; - PathService::Get(base::DIR_EXE, &exe); -#if defined(OS_MACOSX) - exe = exe.DirName().DirName().DirName(); -#endif - exe = exe.Append(chrome::kHelperProcessExecutablePath); - // Run chrome instead of browser_tests.exe. - EXPECT_TRUE(base::PathExists(exe)); - command_line->AppendSwitchPath(switches::kBrowserSubprocessPath, exe); - } -}; - -#if defined(OS_MACOSX) -// Does not work on MACOSX. -#define MAYBE_LaunchAndIPC DISABLED_LaunchAndIPC -#else -#define MAYBE_LaunchAndIPC LaunchAndIPC -#endif - -IN_PROC_BROWSER_TEST_F(RealServiceProcessControlBrowserTest, - MAYBE_LaunchAndIPC) { - LaunchServiceProcessControl(); - - // Make sure we are connected to the service process. - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( - base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)); - content::RunMessageLoop(); - - // And then shutdown the service process. - EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchAndIPC) { - LaunchServiceProcessControl(); - - // Make sure we are connected to the service process. - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( - base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback)); - content::RunMessageLoop(); - - // And then shutdown the service process. - EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); -} - -// This tests the case when a service process is launched when the browser -// starts but we try to launch it again while setting up Cloud Print. -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchTwice) { - // Launch the service process the first time. - LaunchServiceProcessControl(); - - // Make sure we are connected to the service process. - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( - base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback))); - content::RunMessageLoop(); - - // Launch the service process again. - LaunchServiceProcessControl(); - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetCloudPrintProxyInfo( - base::Bind(&ServiceProcessControlBrowserTest::CloudPrintInfoCallback))); - content::RunMessageLoop(); -} - -static void DecrementUntilZero(int* count) { - (*count)--; - if (!(*count)) - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::QuitClosure()); -} - -// Invoke multiple Launch calls in succession and ensure that all the tasks -// get invoked. -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, - MultipleLaunchTasks) { - ServiceProcessControl* process = ServiceProcessControl::GetInstance(); - int launch_count = 5; - for (int i = 0; i < launch_count; i++) { - // Launch the process asynchronously. - process->Launch(base::Bind(&DecrementUntilZero, &launch_count), - base::MessageLoop::QuitClosure()); - } - // Then run the message loop to keep things running. - content::RunMessageLoop(); - EXPECT_EQ(0, launch_count); -} - -// Make sure using the same task for success and failure tasks works. -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) { - ServiceProcessControl* process = ServiceProcessControl::GetInstance(); - int launch_count = 5; - for (int i = 0; i < launch_count; i++) { - // Launch the process asynchronously. - base::Closure task = base::Bind(&DecrementUntilZero, &launch_count); - process->Launch(task, task); - } - // Then run the message loop to keep things running. - content::RunMessageLoop(); - EXPECT_EQ(0, launch_count); -} - -// Tests whether disconnecting from the service IPC causes the service process -// to die. -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DieOnDisconnect) { - // Launch the service process. - LaunchServiceProcessControl(); - // Make sure we are connected to the service process. - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - Disconnect(); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, ForceShutdown) { - // Launch the service process. - LaunchServiceProcessControl(); - // Make sure we are connected to the service process. - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - base::ProcessId service_pid; - EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); - EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); - chrome::VersionInfo version_info; - ForceServiceProcessShutdown(version_info.Version(), service_pid); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) { - base::ProcessId service_pid; - EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid)); - // Launch the service process. - LaunchServiceProcessControl(); - EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid)); - EXPECT_NE(static_cast<base::ProcessId>(0), service_pid); - // Disconnect from service process. - Disconnect(); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsNoService) { - ASSERT_FALSE(ServiceProcessControl::GetInstance()->IsConnected()); - EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); - EXPECT_FALSE(ServiceProcessControl::GetInstance()->GetHistograms( - base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, - base::Unretained(this)), - base::TimeDelta())); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, HistogramsTimeout) { - LaunchServiceProcessControl(); - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - // Callback should not be called during GetHistograms call. - EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); - EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms( - base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, - base::Unretained(this)), - base::TimeDelta::FromMilliseconds(100))); - EXPECT_CALL(*this, MockHistogramsCallback()).Times(1); - EXPECT_TRUE(ServiceProcessControl::GetInstance()->Shutdown()); - content::RunMessageLoop(); -} - -IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, Histograms) { - LaunchServiceProcessControl(); - ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected()); - // Callback should not be called during GetHistograms call. - EXPECT_CALL(*this, MockHistogramsCallback()).Times(0); - // Wait for real callback by providing large timeout value. - EXPECT_TRUE(ServiceProcessControl::GetInstance()->GetHistograms( - base::Bind(&ServiceProcessControlBrowserTest::HistogramsCallback, - base::Unretained(this)), - base::TimeDelta::FromHours(1))); - EXPECT_CALL(*this, MockHistogramsCallback()).Times(1); - content::RunMessageLoop(); -} diff --git a/chrome/browser/service/service_process_control_mac.mm b/chrome/browser/service/service_process_control_mac.mm deleted file mode 100644 index 96c0e8b..0000000 --- a/chrome/browser/service/service_process_control_mac.mm +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2011 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/bind.h" -#include "base/command_line.h" -#include "base/mac/scoped_cftyperef.h" -#include "chrome/common/service_process_util_posix.h" -#include "content/public/browser/browser_thread.h" -#include "third_party/GTM/Foundation/GTMServiceManagement.h" - -using content::BrowserThread; - -void ServiceProcessControl::Launcher::DoRun() { - base::ScopedCFTypeRef<CFDictionaryRef> launchd_plist( - CreateServiceProcessLaunchdPlist(cmd_line_.get(), false)); - CFErrorRef error = NULL; - if (!GTMSMJobSubmit(launchd_plist, &error)) { - LOG(ERROR) << error; - CFRelease(error); - } else { - launched_ = true; - } - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&Launcher::Notify, this)); -} |