blob: e465eb260e2627bb5ab0ccbefa5a0a208b58e901 [file] [log] [blame]
// 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/service/service_utility_process_host.h"
#include "app/app_switches.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/utility_messages.h"
#include "gfx/rect.h"
#include "ipc/ipc_switches.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
ServiceUtilityProcessHost::ServiceUtilityProcessHost(
Client* client, base::MessageLoopProxy* client_message_loop_proxy)
: ServiceChildProcessHost(ChildProcessInfo::UTILITY_PROCESS),
client_(client),
client_message_loop_proxy_(client_message_loop_proxy),
waiting_for_reply_(false) {
}
ServiceUtilityProcessHost::~ServiceUtilityProcessHost() {
}
bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile(
const FilePath& pdf_path,
const gfx::Rect& render_area,
int render_dpi,
const std::vector<printing::PageRange>& page_ranges) {
#if !defined(OS_WIN)
// This is only implemented on Windows (because currently it is only needed
// on Windows). Will add implementations on other platforms when needed.
NOTIMPLEMENTED();
return false;
#else // !defined(OS_WIN)
if (!StartProcess())
return false;
ScopedHandle pdf_file(
::CreateFile(pdf_path.value().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL));
if (pdf_file == INVALID_HANDLE_VALUE)
return false;
HANDLE pdf_file_in_utility_process = NULL;
::DuplicateHandle(::GetCurrentProcess(), pdf_file, handle(),
&pdf_file_in_utility_process, 0, false,
DUPLICATE_SAME_ACCESS);
if (!pdf_file_in_utility_process)
return false;
waiting_for_reply_ = true;
return SendOnChannel(
new UtilityMsg_RenderPDFPagesToMetafile(pdf_file_in_utility_process,
render_area,
render_dpi,
page_ranges));
#endif // !defined(OS_WIN)
}
bool ServiceUtilityProcessHost::StartProcess() {
// Name must be set or metrics_service will crash in any test which
// launches a UtilityProcessHost.
set_name(L"utility process");
if (!CreateChannel())
return false;
FilePath exe_path = GetUtilityProcessCmd();
if (exe_path.empty()) {
NOTREACHED() << "Unable to get utility process binary name.";
return false;
}
CommandLine cmd_line(exe_path);
cmd_line.AppendSwitchWithValue(switches::kProcessType,
switches::kUtilityProcess);
cmd_line.AppendSwitchWithValue(switches::kProcessChannelID,
ASCIIToWide(channel_id()));
cmd_line.AppendSwitch(switches::kLang);
return Launch(&cmd_line);
}
FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() {
return GetChildPath(true);
}
void ServiceUtilityProcessHost::OnChildDied() {
if (waiting_for_reply_) {
// If we are yet to receive a reply then notify the client that the
// child died.
client_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(client_.get(), &Client::OnChildDied));
}
// The base class implementation will delete |this|.
ServiceChildProcessHost::OnChildDied();
}
void ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
bool msg_is_ok = false;
IPC_BEGIN_MESSAGE_MAP_EX(ServiceUtilityProcessHost, message, msg_is_ok)
#if defined(OS_WIN) // This hack is Windows-specific.
IPC_MESSAGE_HANDLER(UtilityHostMsg_PreCacheFont, OnPreCacheFont)
#endif
IPC_MESSAGE_UNHANDLED(msg_is_ok__ = MessageForClient(message))
IPC_END_MESSAGE_MAP_EX()
}
bool ServiceUtilityProcessHost::MessageForClient(const IPC::Message& message) {
DCHECK(waiting_for_reply_);
bool ret = client_message_loop_proxy_->PostTask(
FROM_HERE,
NewRunnableMethod(client_.get(), &Client::OnMessageReceived,
message));
waiting_for_reply_ = false;
return ret;
}
#if defined(OS_WIN) // This hack is Windows-specific.
void ServiceUtilityProcessHost::OnPreCacheFont(LOGFONT font) {
PreCacheFont(font);
}
#endif // OS_WIN
void ServiceUtilityProcessHost::Client::OnMessageReceived(
const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(ServiceUtilityProcessHost, message)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(UtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
Client::OnRenderPDFPagesToMetafileSucceeded)
#endif // OS_WIN
IPC_MESSAGE_HANDLER(UtilityHostMsg_RenderPDFPagesToMetafile_Failed,
Client::OnRenderPDFPagesToMetafileFailed)
IPC_END_MESSAGE_MAP_EX()
}