summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/common/common_param_traits.cc31
-rw-r--r--chrome/common/common_param_traits.h9
-rw-r--r--chrome/common/common_param_traits_unittest.cc22
-rw-r--r--chrome/common/utility_messages_internal.h20
-rw-r--r--chrome/service/cloud_print/cloud_print_proxy_backend.cc148
-rw-r--r--chrome/service/cloud_print/print_system.h13
-rw-r--r--chrome/service/cloud_print/print_system_cups.cc87
-rw-r--r--chrome/service/cloud_print/print_system_win.cc79
-rw-r--r--chrome/service/cloud_print/printer_job_handler.cc46
-rw-r--r--chrome/service/cloud_print/printer_job_handler.h6
-rw-r--r--chrome/service/service_child_process_host.cc13
-rw-r--r--chrome/service/service_child_process_host.h6
-rw-r--r--chrome/service/service_utility_process_host.cc20
-rw-r--r--chrome/service/service_utility_process_host.h25
-rw-r--r--chrome/utility/utility_main.cc14
-rw-r--r--chrome/utility/utility_thread.cc17
-rw-r--r--chrome/utility/utility_thread.h6
17 files changed, 442 insertions, 120 deletions
diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc
index 3564780..40417fc 100644
--- a/chrome/common/common_param_traits.cc
+++ b/chrome/common/common_param_traits.cc
@@ -13,6 +13,7 @@
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "net/base/upload_data.h"
+#include "printing/backend/print_backend.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
@@ -646,4 +647,34 @@ void ParamTraits<base::PlatformFileInfo>::Log(
l->append(")");
}
+void ParamTraits<printing::PrinterCapsAndDefaults>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.printer_capabilities);
+ WriteParam(m, p.caps_mime_type);
+ WriteParam(m, p.printer_defaults);
+ WriteParam(m, p.defaults_mime_type);
+}
+
+bool ParamTraits<printing::PrinterCapsAndDefaults>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->printer_capabilities) &&
+ ReadParam(m, iter, &p->caps_mime_type) &&
+ ReadParam(m, iter, &p->printer_defaults) &&
+ ReadParam(m, iter, &p->defaults_mime_type);
+}
+
+void ParamTraits<printing::PrinterCapsAndDefaults>::Log(
+ const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.printer_capabilities, l);
+ l->append(",");
+ LogParam(p.caps_mime_type, l);
+ l->append(",");
+ LogParam(p.printer_defaults, l);
+ l->append(",");
+ LogParam(p.defaults_mime_type, l);
+ l->append(")");
+}
+
} // namespace IPC
diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h
index 5b0c07e..3638443 100644
--- a/chrome/common/common_param_traits.h
+++ b/chrome/common/common_param_traits.h
@@ -56,6 +56,7 @@ class UploadData;
namespace printing {
struct PageRange;
+struct PrinterCapsAndDefaults;
} // namespace printing
namespace webkit_glue {
@@ -334,6 +335,14 @@ struct SimilarTypeTraits<base::PlatformFileError> {
typedef int Type;
};
+template <>
+struct ParamTraits<printing::PrinterCapsAndDefaults> {
+ typedef printing::PrinterCapsAndDefaults param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // CHROME_COMMON_COMMON_PARAM_TRAITS_H_
diff --git a/chrome/common/common_param_traits_unittest.cc b/chrome/common/common_param_traits_unittest.cc
index 6086c12..8446158 100644
--- a/chrome/common/common_param_traits_unittest.cc
+++ b/chrome/common/common_param_traits_unittest.cc
@@ -13,6 +13,7 @@
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
+#include "printing/backend/print_backend.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -264,3 +265,24 @@ TEST(IPCMessageTest, Metafile) {
}
#endif // defined(OS_WIN)
+// Tests printing::PrinterCapsAndDefaults serialization
+TEST(IPCMessageTest, PrinterCapsAndDefaults) {
+ printing::PrinterCapsAndDefaults input;
+ input.printer_capabilities = "Test Capabilities";
+ input.caps_mime_type = "text/plain";
+ input.printer_defaults = "Test Defaults";
+ input.defaults_mime_type = "text/plain";
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::ParamTraits<printing::PrinterCapsAndDefaults>::Write(&msg, input);
+
+ printing::PrinterCapsAndDefaults output;
+ void* iter = NULL;
+ EXPECT_TRUE(IPC::ParamTraits<printing::PrinterCapsAndDefaults>::Read(
+ &msg, &iter, &output));
+ EXPECT_TRUE(input.printer_capabilities == output.printer_capabilities);
+ EXPECT_TRUE(input.caps_mime_type == output.caps_mime_type);
+ EXPECT_TRUE(input.printer_defaults == output.printer_defaults);
+ EXPECT_TRUE(input.defaults_mime_type == output.defaults_mime_type);
+}
+
diff --git a/chrome/common/utility_messages_internal.h b/chrome/common/utility_messages_internal.h
index 62d329a..5381155 100644
--- a/chrome/common/utility_messages_internal.h
+++ b/chrome/common/utility_messages_internal.h
@@ -8,6 +8,7 @@
#include "base/platform_file.h"
#include "gfx/rect.h"
#include "ipc/ipc_message_macros.h"
+#include "printing/backend/print_backend.h"
#include "printing/page_range.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -60,6 +61,13 @@ IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Started)
// Tells the utility process that it can shutdown.
IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Finished)
+// Tells the utility process to get capabilities and defaults for the specified
+// printer. Used on Windows to isolate the service process from printer driver
+// crashes by executing this in a separate process. This does not run in a
+// sandbox.
+IPC_MESSAGE_CONTROL1(UtilityMsg_GetPrinterCapsAndDefaults,
+ std::string /* printer name */)
+
//------------------------------------------------------------------------------
// Utility process host messages:
// These are messages from the utility process to the browser.
@@ -128,3 +136,15 @@ IPC_MESSAGE_CONTROL2(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded,
// IDBKeyPath.
IPC_MESSAGE_CONTROL1(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
int /* id */)
+
+// Reply when the utility process has succeeded in obtaining the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL2(UtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
+ std::string /* printer name */,
+ printing::PrinterCapsAndDefaults)
+
+// Reply when the utility process has failed to obtain the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
+ std::string /* printer name */)
+
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
index 1fa5814..61c824e 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
@@ -136,6 +136,12 @@ class CloudPrintProxyBackend::Core
// printer and print them.
void InitJobHandlerForPrinter(DictionaryValue* printer_data);
+ // Callback method for GetPrinterCapsAndDefaults.
+ void OnReceivePrinterCaps(
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults);
+
void HandlePrinterNotification(const std::string& printer_id);
void PollForJobs();
// Schedules a task to poll for jobs. Does nothing if a task is already
@@ -424,78 +430,96 @@ void CloudPrintProxyBackend::Core::RegisterNextPrinter() {
if (next_upload_index_ < printer_list_.size()) {
const printing::PrinterBasicInfo& info =
printer_list_.at(next_upload_index_);
- bool have_printer_info = true;
// If we are retrying a previous upload, we don't need to fetch the caps
// and defaults again.
if (info.printer_name != last_uploaded_printer_name_) {
- have_printer_info =
- print_system_->GetPrinterCapsAndDefaults(
- info.printer_name.c_str(), &last_uploaded_printer_info_);
- }
- if (have_printer_info) {
- last_uploaded_printer_name_ = info.printer_name;
- std::string mime_boundary;
- CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
- std::string post_data;
- CloudPrintHelpers::AddMultipartValueForUpload(kProxyIdValue, proxy_id_,
- mime_boundary,
- std::string(), &post_data);
- CloudPrintHelpers::AddMultipartValueForUpload(kPrinterNameValue,
- info.printer_name,
- mime_boundary,
- std::string(), &post_data);
- CloudPrintHelpers::AddMultipartValueForUpload(kPrinterDescValue,
- info.printer_description,
- mime_boundary,
- std::string() , &post_data);
- CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterStatusValue, StringPrintf("%d", info.printer_status),
- mime_boundary, std::string(), &post_data);
- // Add printer options as tags.
- CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(info.options,
- mime_boundary,
- &post_data);
-
- CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterCapsValue, last_uploaded_printer_info_.printer_capabilities,
- mime_boundary, last_uploaded_printer_info_.caps_mime_type,
- &post_data);
- CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterDefaultsValue, last_uploaded_printer_info_.printer_defaults,
- mime_boundary, last_uploaded_printer_info_.defaults_mime_type,
- &post_data);
- // Send a hash of the printer capabilities to the server. We will use this
- // later to check if the capabilities have changed
- CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterCapsHashValue,
- MD5String(last_uploaded_printer_info_.printer_capabilities),
- mime_boundary, std::string(), &post_data);
- // Terminate the request body
- post_data.append("--" + mime_boundary + "--\r\n");
- std::string mime_type("multipart/form-data; boundary=");
- mime_type += mime_boundary;
- GURL register_url = CloudPrintHelpers::GetUrlForPrinterRegistration(
- cloud_print_server_url_);
-
- next_response_handler_ =
- &CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse;
- request_ = new CloudPrintURLFetcher;
- request_->StartPostRequest(register_url, this, auth_token_,
- kCloudPrintAPIMaxRetryCount, mime_type,
- post_data);
-
+ cloud_print::PrintSystem::PrinterCapsAndDefaultsCallback* callback =
+ NewCallback(this,
+ &CloudPrintProxyBackend::Core::OnReceivePrinterCaps);
+ // Asnchronously fetch the printer caps and defaults. The story will
+ // continue in OnReceivePrinterCaps.
+ print_system_->GetPrinterCapsAndDefaults(
+ info.printer_name.c_str(), callback);
} else {
- LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " <<
- info.printer_name;
- next_upload_index_++;
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &CloudPrintProxyBackend::Core::RegisterNextPrinter));
+ OnReceivePrinterCaps(true,
+ last_uploaded_printer_name_,
+ last_uploaded_printer_info_);
}
} else {
EndRegistration();
}
}
+void CloudPrintProxyBackend::Core::OnReceivePrinterCaps(
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults) {
+ DCHECK(next_upload_index_ < printer_list_.size());
+ if (succeeded) {
+ const printing::PrinterBasicInfo& info =
+ printer_list_.at(next_upload_index_);
+
+ last_uploaded_printer_name_ = info.printer_name;
+ last_uploaded_printer_info_ = caps_and_defaults;
+
+ std::string mime_boundary;
+ CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
+ std::string post_data;
+ CloudPrintHelpers::AddMultipartValueForUpload(kProxyIdValue, proxy_id_,
+ mime_boundary,
+ std::string(), &post_data);
+ CloudPrintHelpers::AddMultipartValueForUpload(kPrinterNameValue,
+ info.printer_name,
+ mime_boundary,
+ std::string(), &post_data);
+ CloudPrintHelpers::AddMultipartValueForUpload(kPrinterDescValue,
+ info.printer_description,
+ mime_boundary,
+ std::string() , &post_data);
+ CloudPrintHelpers::AddMultipartValueForUpload(
+ kPrinterStatusValue, StringPrintf("%d", info.printer_status),
+ mime_boundary, std::string(), &post_data);
+ // Add printer options as tags.
+ CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(info.options,
+ mime_boundary,
+ &post_data);
+
+ CloudPrintHelpers::AddMultipartValueForUpload(
+ kPrinterCapsValue, last_uploaded_printer_info_.printer_capabilities,
+ mime_boundary, last_uploaded_printer_info_.caps_mime_type,
+ &post_data);
+ CloudPrintHelpers::AddMultipartValueForUpload(
+ kPrinterDefaultsValue, last_uploaded_printer_info_.printer_defaults,
+ mime_boundary, last_uploaded_printer_info_.defaults_mime_type,
+ &post_data);
+ // Send a hash of the printer capabilities to the server. We will use this
+ // later to check if the capabilities have changed
+ CloudPrintHelpers::AddMultipartValueForUpload(
+ kPrinterCapsHashValue,
+ MD5String(last_uploaded_printer_info_.printer_capabilities),
+ mime_boundary, std::string(), &post_data);
+ // Terminate the request body
+ post_data.append("--" + mime_boundary + "--\r\n");
+ std::string mime_type("multipart/form-data; boundary=");
+ mime_type += mime_boundary;
+ GURL register_url = CloudPrintHelpers::GetUrlForPrinterRegistration(
+ cloud_print_server_url_);
+
+ next_response_handler_ =
+ &CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse;
+ request_ = new CloudPrintURLFetcher;
+ request_->StartPostRequest(register_url, this, auth_token_,
+ kCloudPrintAPIMaxRetryCount, mime_type,
+ post_data);
+ } else {
+ LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " <<
+ printer_name;
+ next_upload_index_++;
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &CloudPrintProxyBackend::Core::RegisterNextPrinter));
+ }
+}
+
void CloudPrintProxyBackend::Core::HandlePrinterNotification(
const std::string& printer_id) {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
diff --git a/chrome/service/cloud_print/print_system.h b/chrome/service/cloud_print/print_system.h
index 620004c..517a665 100644
--- a/chrome/service/cloud_print/print_system.h
+++ b/chrome/service/cloud_print/print_system.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/ref_counted.h"
#include "printing/backend/print_backend.h"
@@ -130,6 +131,12 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> {
JobSpooler::Delegate* delegate) = 0;
};
+ typedef Callback3<
+ bool,
+ const std::string&,
+ const printing::PrinterCapsAndDefaults&>::Type
+ PrinterCapsAndDefaultsCallback;
+
virtual ~PrintSystem();
// Initialize print system. This need to be called before any other function
@@ -139,10 +146,10 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> {
// Enumerates the list of installed local and network printers.
virtual void EnumeratePrinters(printing::PrinterList* printer_list) = 0;
- // Gets the capabilities and defaults for a specific printer.
- virtual bool GetPrinterCapsAndDefaults(
+ // Gets the capabilities and defaults for a specific printer asynchronously.
+ virtual void GetPrinterCapsAndDefaults(
const std::string& printer_name,
- printing::PrinterCapsAndDefaults* printer_info) = 0;
+ PrinterCapsAndDefaultsCallback* callback) = 0;
// Returns true if printer_name points to a valid printer.
virtual bool IsValidPrinter(const std::string& printer_name) = 0;
diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc
index 0df7ac6..1a8e7d7 100644
--- a/chrome/service/cloud_print/print_system_cups.cc
+++ b/chrome/service/cloud_print/print_system_cups.cc
@@ -76,9 +76,9 @@ class PrintSystemCUPS : public PrintSystem {
virtual void EnumeratePrinters(printing::PrinterList* printer_list);
- virtual bool GetPrinterCapsAndDefaults(
+ virtual void GetPrinterCapsAndDefaults(
const std::string& printer_name,
- printing::PrinterCapsAndDefaults* printer_info);
+ PrinterCapsAndDefaultsCallback* callback);
virtual bool IsValidPrinter(const std::string& printer_name);
@@ -107,6 +107,11 @@ class PrintSystemCUPS : public PrintSystem {
bool ParsePrintTicket(const std::string& print_ticket,
std::map<std::string, std::string>* options);
+ // Synchronous version of GetPrinterCapsAndDefaults.
+ bool GetPrinterCapsAndDefaults(
+ const std::string& printer_name,
+ printing::PrinterCapsAndDefaults* printer_info);
+
int GetUpdateTimeoutMs() const {
return update_timeout_;
}
@@ -133,6 +138,13 @@ class PrintSystemCUPS : public PrintSystem {
PrintServerInfoCUPS* FindServerByFullName(
const std::string& full_printer_name, std::string* short_printer_name);
+ // Helper method to invoke a PrinterCapsAndDefaultsCallback.
+ static void RunCapsCallback(
+ PrinterCapsAndDefaultsCallback* callback,
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& printer_info);
+
// PrintServerList contains information about all print servers and backends
// this proxy is connected to.
typedef std::list<PrintServerInfoCUPS> PrintServerList;
@@ -430,31 +442,18 @@ void PrintSystemCUPS::EnumeratePrinters(printing::PrinterList* printer_list) {
VLOG(1) << "CUPS: Total " << printer_list->size() << " printers enumerated.";
}
-bool PrintSystemCUPS::GetPrinterCapsAndDefaults(
+void PrintSystemCUPS::GetPrinterCapsAndDefaults(
const std::string& printer_name,
- printing::PrinterCapsAndDefaults* printer_info) {
- DCHECK(initialized_);
- std::string short_printer_name;
- PrintServerInfoCUPS* server_info =
- FindServerByFullName(printer_name, &short_printer_name);
- if (!server_info)
- return false;
-
- PrintServerInfoCUPS::CapsMap::iterator caps_it =
- server_info->caps_cache.find(printer_name);
- if (caps_it != server_info->caps_cache.end()) {
- *printer_info = caps_it->second;
- return true;
- }
-
- // TODO(gene): Retry multiple times in case of error.
- if (!server_info->backend->GetPrinterCapsAndDefaults(short_printer_name,
- printer_info) ) {
- return false;
- }
-
- server_info->caps_cache[printer_name] = *printer_info;
- return true;
+ PrinterCapsAndDefaultsCallback* callback) {
+ printing::PrinterCapsAndDefaults printer_info;
+ bool succeeded = GetPrinterCapsAndDefaults(printer_name, &printer_info);
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&PrintSystemCUPS::RunCapsCallback,
+ callback,
+ succeeded,
+ printer_name,
+ printer_info));
}
bool PrintSystemCUPS::IsValidPrinter(const std::string& printer_name) {
@@ -492,6 +491,33 @@ bool PrintSystemCUPS::ParsePrintTicket(const std::string& print_ticket,
return true;
}
+bool PrintSystemCUPS::GetPrinterCapsAndDefaults(
+ const std::string& printer_name,
+ printing::PrinterCapsAndDefaults* printer_info) {
+ DCHECK(initialized_);
+ std::string short_printer_name;
+ PrintServerInfoCUPS* server_info =
+ FindServerByFullName(printer_name, &short_printer_name);
+ if (!server_info)
+ return false;
+
+ PrintServerInfoCUPS::CapsMap::iterator caps_it =
+ server_info->caps_cache.find(printer_name);
+ if (caps_it != server_info->caps_cache.end()) {
+ *printer_info = caps_it->second;
+ return true;
+ }
+
+ // TODO(gene): Retry multiple times in case of error.
+ if (!server_info->backend->GetPrinterCapsAndDefaults(short_printer_name,
+ printer_info) ) {
+ return false;
+ }
+
+ server_info->caps_cache[printer_name] = *printer_info;
+ return true;
+}
+
bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name,
PlatformJobId job_id,
PrintJobDetails *job_details) {
@@ -737,4 +763,13 @@ PrintServerInfoCUPS* PrintSystemCUPS::FindServerByFullName(
return NULL;
}
+void PrintSystemCUPS::RunCapsCallback(
+ PrinterCapsAndDefaultsCallback* callback,
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& printer_info) {
+ callback->Run(succeeded, printer_name, printer_info);
+ delete callback;
+}
+
} // namespace cloud_print
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc
index 571b677..4369b54 100644
--- a/chrome/service/cloud_print/print_system_win.cc
+++ b/chrome/service/cloud_print/print_system_win.cc
@@ -245,9 +245,9 @@ class PrintSystemWin : public PrintSystem {
virtual void EnumeratePrinters(printing::PrinterList* printer_list);
- virtual bool GetPrinterCapsAndDefaults(
+ virtual void GetPrinterCapsAndDefaults(
const std::string& printer_name,
- printing::PrinterCapsAndDefaults* printer_info);
+ PrinterCapsAndDefaultsCallback* callback);
virtual bool IsValidPrinter(const std::string& printer_name);
@@ -516,6 +516,69 @@ class PrintSystemWin : public PrintSystem {
DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
};
+ // A helper class to handle the response from the utility process to the
+ // request to fetch printer capabilities and defaults.
+ class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
+ public:
+ PrinterCapsHandler(
+ const std::string& printer_name,
+ PrinterCapsAndDefaultsCallback* callback)
+ : printer_name_(printer_name), callback_(callback) {
+ }
+ virtual void Start() {
+ g_service_process->io_thread()->message_loop_proxy()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl,
+ base::MessageLoopProxy::CreateForCurrentThread()));
+ }
+
+ virtual void OnChildDied() {
+ OnGetPrinterCapsAndDefaultsFailed(printer_name_);
+ }
+ virtual void OnGetPrinterCapsAndDefaultsSucceeded(
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults) {
+ callback_->Run(true, printer_name, caps_and_defaults);
+ callback_.reset();
+ Release();
+ }
+
+ virtual void OnGetPrinterCapsAndDefaultsFailed(
+ const std::string& printer_name) {
+ printing::PrinterCapsAndDefaults caps_and_defaults;
+ callback_->Run(false, printer_name, caps_and_defaults);
+ callback_.reset();
+ Release();
+ }
+ private:
+ // Called on the service process IO thread.
+ void GetPrinterCapsAndDefaultsImpl(
+ const scoped_refptr<base::MessageLoopProxy>&
+ client_message_loop_proxy) {
+ DCHECK(g_service_process->io_thread()->message_loop_proxy()->
+ BelongsToCurrentThread());
+ scoped_ptr<ServiceUtilityProcessHost> utility_host(
+ new ServiceUtilityProcessHost(this, client_message_loop_proxy));
+ if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
+ // The object will self-destruct when the child process dies.
+ utility_host.release();
+ } else {
+ client_message_loop_proxy->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &PrinterCapsHandler::OnGetPrinterCapsAndDefaultsFailed,
+ printer_name_));
+ }
+ }
+
+ std::string printer_name_;
+ scoped_ptr<PrinterCapsAndDefaultsCallback> callback_;
+ };
+
+
virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
const std::string& printer_name);
@@ -536,10 +599,16 @@ void PrintSystemWin::EnumeratePrinters(printing::PrinterList* printer_list) {
print_backend_->EnumeratePrinters(printer_list);
}
-bool PrintSystemWin::GetPrinterCapsAndDefaults(
+void PrintSystemWin::GetPrinterCapsAndDefaults(
const std::string& printer_name,
- printing::PrinterCapsAndDefaults* printer_info) {
- return print_backend_->GetPrinterCapsAndDefaults(printer_name, printer_info);
+ PrinterCapsAndDefaultsCallback* callback) {
+ // Launch as child process to retrieve the capabilities and defaults because
+ // this involves invoking a printer driver DLL and crashes have been known to
+ // occur.
+ PrinterCapsHandler* handler =
+ new PrinterCapsHandler(printer_name, callback);
+ handler->AddRef();
+ handler->Start();
}
bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc
index 5c772ef..6013411 100644
--- a/chrome/service/cloud_print/printer_job_handler.cc
+++ b/chrome/service/cloud_print/printer_job_handler.cc
@@ -160,31 +160,54 @@ bool PrinterJobHandler::UpdatePrinterInfo() {
<< printer_info_cloud_.printer_id;
// We need to update the parts of the printer info that have changed
// (could be printer name, description, status or capabilities).
+ // First asynchronously fetch the capabilities.
printing::PrinterBasicInfo printer_info;
printer_watcher_->GetCurrentPrinterInfo(&printer_info);
- printing::PrinterCapsAndDefaults printer_caps;
+ cloud_print::PrintSystem::PrinterCapsAndDefaultsCallback* callback =
+ NewCallback(this,
+ &PrinterJobHandler::OnReceivePrinterCaps);
+ // Asnchronously fetch the printer caps and defaults. The story will
+ // continue in OnReceivePrinterCaps.
+ print_system_->GetPrinterCapsAndDefaults(
+ printer_info.printer_name.c_str(), callback);
+ // While we are waiting for the data, pretend we have work to do and return
+ // true.
+ return true;
+}
+
+void PrinterJobHandler::OnReceivePrinterCaps(
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults) {
+ printing::PrinterBasicInfo printer_info;
+ printer_watcher_->GetCurrentPrinterInfo(&printer_info);
+
std::string post_data;
std::string mime_boundary;
CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
- if (print_system_->GetPrinterCapsAndDefaults(
- printer_info.printer_name, &printer_caps)) {
- std::string caps_hash = MD5String(printer_caps.printer_capabilities);
+
+ if (succeeded) {
+ std::string caps_hash = MD5String(caps_and_defaults.printer_capabilities);
if (caps_hash != printer_info_cloud_.caps_hash) {
// Hashes don't match, we need to upload new capabilities (the defaults
// go for free along with the capabilities)
printer_info_cloud_.caps_hash = caps_hash;
CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterCapsValue, printer_caps.printer_capabilities,
- mime_boundary, printer_caps.caps_mime_type, &post_data);
+ kPrinterCapsValue, caps_and_defaults.printer_capabilities,
+ mime_boundary, caps_and_defaults.caps_mime_type, &post_data);
CloudPrintHelpers::AddMultipartValueForUpload(
- kPrinterDefaultsValue, printer_caps.printer_defaults,
- mime_boundary, printer_caps.defaults_mime_type,
+ kPrinterDefaultsValue, caps_and_defaults.printer_defaults,
+ mime_boundary, caps_and_defaults.defaults_mime_type,
&post_data);
CloudPrintHelpers::AddMultipartValueForUpload(
kPrinterCapsHashValue, caps_hash, mime_boundary, std::string(),
&post_data);
}
+ } else {
+ LOG(ERROR) << "Failed to get printer caps and defaults for printer: "
+ << printer_name;
}
+
std::string tags_hash =
CloudPrintHelpers::GenerateHashOfStringMap(printer_info.options);
if (tags_hash != printer_info_cloud_.tags_hash) {
@@ -216,7 +239,6 @@ bool PrinterJobHandler::UpdatePrinterInfo() {
mime_boundary, std::string(), &post_data);
}
printer_info_ = printer_info;
- bool ret = false;
if (!post_data.empty()) {
// Terminate the request body
post_data.append("--" + mime_boundary + "--\r\n");
@@ -228,9 +250,11 @@ bool PrinterJobHandler::UpdatePrinterInfo() {
CloudPrintHelpers::GetUrlForPrinterUpdate(
cloud_print_server_url_, printer_info_cloud_.printer_id),
this, auth_token_, kCloudPrintAPIMaxRetryCount, mime_type, post_data);
- ret = true;
+ } else {
+ // We are done here. Go to the Stop state
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
}
- return ret;
}
// CloudPrintURLFetcher::Delegate implementation.
diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h
index 9ffc887..f32c1d9 100644
--- a/chrome/service/cloud_print/printer_job_handler.h
+++ b/chrome/service/cloud_print/printer_job_handler.h
@@ -230,6 +230,12 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
bool HavePendingTasks();
void FailedFetchingJobData();
+ // Callback that asynchronously receives printer caps and defaults.
+ void OnReceivePrinterCaps(
+ bool succeeded,
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults);
+
// Called on print_thread_.
void DoPrint(const JobDetails& job_details,
const std::string& printer_name);
diff --git a/chrome/service/service_child_process_host.cc b/chrome/service/service_child_process_host.cc
index 00dfacc..472b18b 100644
--- a/chrome/service/service_child_process_host.cc
+++ b/chrome/service/service_child_process_host.cc
@@ -4,8 +4,10 @@
#include "chrome/service/service_child_process_host.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/process_util.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
#if defined(OS_WIN)
@@ -23,13 +25,22 @@ ServiceChildProcessHost::~ServiceChildProcessHost() {
}
bool ServiceChildProcessHost::Launch(CommandLine* cmd_line,
+ bool no_sandbox,
const FilePath& exposed_dir) {
#if !defined(OS_WIN)
// TODO(sanjeevr): Implement for non-Windows OSes.
NOTIMPLEMENTED();
return false;
#else // !defined(OS_WIN)
- set_handle(sandbox::StartProcessWithAccess(cmd_line, exposed_dir));
+
+ if (no_sandbox) {
+ base::ProcessHandle process = base::kNullProcessHandle;
+ cmd_line->AppendSwitch(switches::kNoSandbox);
+ base::LaunchApp(*cmd_line, false, false, &process);
+ set_handle(process);
+ } else {
+ set_handle(sandbox::StartProcessWithAccess(cmd_line, exposed_dir));
+ }
return (handle() != base::kNullProcessHandle);
#endif // !defined(OS_WIN)
}
diff --git a/chrome/service/service_child_process_host.h b/chrome/service/service_child_process_host.h
index fe8b5df..b69d3db 100644
--- a/chrome/service/service_child_process_host.h
+++ b/chrome/service/service_child_process_host.h
@@ -23,7 +23,11 @@ class ServiceChildProcessHost : public ChildProcessHost,
explicit ServiceChildProcessHost(ProcessType type);
// Derived classes call this to launch the child process synchronously.
// TODO(sanjeevr): Determine whether we need to make the launch asynchronous.
- bool Launch(CommandLine* cmd_line, const FilePath& exposed_dir);
+ // |exposed_dir| is the path to tbe exposed to the sandbox. This is ignored
+ // if |no_sandbox| is true.
+ bool Launch(CommandLine* cmd_line,
+ bool no_sandbox,
+ const FilePath& exposed_dir);
};
#endif // CHROME_SERVICE_SERVICE_CHILD_PROCESS_HOST_H_
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index 696ba79..d6b4dbe 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -47,7 +47,7 @@ bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile(
return false;
}
- if (!StartProcess(scratch_metafile_dir_->path()))
+ if (!StartProcess(false, scratch_metafile_dir_->path()))
return false;
ScopedHandle pdf_file(
@@ -76,7 +76,17 @@ bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile(
#endif // !defined(OS_WIN)
}
-bool ServiceUtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
+bool ServiceUtilityProcessHost::StartGetPrinterCapsAndDefaults(
+ const std::string& printer_name) {
+ FilePath exposed_path;
+ if (!StartProcess(true, exposed_path))
+ return false;
+ waiting_for_reply_ = true;
+ return Send(new UtilityMsg_GetPrinterCapsAndDefaults(printer_name));
+}
+
+bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox,
+ const FilePath& exposed_dir) {
// Name must be set or metrics_service will crash in any test which
// launches a UtilityProcessHost.
set_name(L"utility process");
@@ -95,7 +105,7 @@ bool ServiceUtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id());
cmd_line.AppendSwitch(switches::kLang);
- return Launch(&cmd_line, exposed_dir);
+ return Launch(&cmd_line, no_sandbox, exposed_dir);
}
FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() {
@@ -167,6 +177,10 @@ void ServiceUtilityProcessHost::Client::OnMessageReceived(
IPC_BEGIN_MESSAGE_MAP(ServiceUtilityProcessHost, message)
IPC_MESSAGE_HANDLER(UtilityHostMsg_RenderPDFPagesToMetafile_Failed,
Client::OnRenderPDFPagesToMetafileFailed)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
+ Client::OnGetPrinterCapsAndDefaultsSucceeded)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
+ Client::OnGetPrinterCapsAndDefaultsFailed)
IPC_END_MESSAGE_MAP_EX()
}
diff --git a/chrome/service/service_utility_process_host.h b/chrome/service/service_utility_process_host.h
index 40bae54..54e039c 100644
--- a/chrome/service/service_utility_process_host.h
+++ b/chrome/service/service_utility_process_host.h
@@ -12,6 +12,7 @@
#include <windows.h>
#endif // defined(OS_WIN)
+#include <string>
#include <vector>
#include "base/basictypes.h"
@@ -35,6 +36,7 @@ class Rect;
namespace printing {
struct PageRange;
+struct PrinterCapsAndDefaults;
} // namespace printing
// Acts as the service-side host to a utility child process. A
@@ -60,6 +62,17 @@ class ServiceUtilityProcessHost : public ServiceChildProcessHost {
// Called when no page in the passed in PDF could be rendered.
virtual void OnRenderPDFPagesToMetafileFailed() {}
+ // Called when the printer capabilities and defaults have been
+ // retrieved successfully.
+ virtual void OnGetPrinterCapsAndDefaultsSucceeded(
+ const std::string& printer_name,
+ const printing::PrinterCapsAndDefaults& caps_and_defaults) {}
+
+ // Called when the printer capabilities and defaults could not be
+ // retrieved successfully.
+ virtual void OnGetPrinterCapsAndDefaultsFailed(
+ const std::string& printer_name) {}
+
protected:
virtual ~Client() {}
@@ -88,6 +101,12 @@ class ServiceUtilityProcessHost : public ServiceChildProcessHost {
int render_dpi,
const std::vector<printing::PageRange>& page_ranges);
+ // Starts a process to get capabilities and defaults for the specified
+ // printer. Used on Windows to isolate the service process from printer driver
+ // crashes by executing this in a separate process. The process does not run
+ // in a sandbox.
+ bool StartGetPrinterCapsAndDefaults(const std::string& printer_name);
+
protected:
// Allows this method to be overridden for tests.
virtual FilePath GetUtilityProcessCmd();
@@ -97,8 +116,10 @@ class ServiceUtilityProcessHost : public ServiceChildProcessHost {
virtual void OnChildDied();
private:
- // Starts a process. Returns true iff it succeeded.
- bool StartProcess(const FilePath& exposed_dir);
+ // Starts a process. Returns true iff it succeeded. |exposed_dir| is the
+ // path to tbe exposed to the sandbox. This is ignored if |no_sandbox| is
+ // true.
+ bool StartProcess(bool no_sandbox, const FilePath& exposed_dir);
// IPC messages:
virtual void OnMessageReceived(const IPC::Message& message);
diff --git a/chrome/utility/utility_main.cc b/chrome/utility/utility_main.cc
index 09d0156..0fa6777 100644
--- a/chrome/utility/utility_main.cc
+++ b/chrome/utility/utility_main.cc
@@ -45,12 +45,14 @@ int UtilityMain(const MainFunctionParams& parameters) {
DCHECK(rv) << "Couldn't load PDF plugin";
}
- sandbox::TargetServices* target_services =
- parameters.sandbox_info_.TargetServices();
- if (!target_services)
- return false;
-
- target_services->LowerToken();
+ bool no_sandbox = parameters.command_line_.HasSwitch(switches::kNoSandbox);
+ if (!no_sandbox) {
+ sandbox::TargetServices* target_services =
+ parameters.sandbox_info_.TargetServices();
+ if (!target_services)
+ return false;
+ target_services->LowerToken();
+ }
#endif
CommandLine* command_line = CommandLine::ForCurrentProcess();
diff --git a/chrome/utility/utility_thread.cc b/chrome/utility/utility_thread.cc
index 81e7ff4..baf831f 100644
--- a/chrome/utility/utility_thread.cc
+++ b/chrome/utility/utility_thread.cc
@@ -63,6 +63,8 @@ void UtilityThread::OnControlMessageReceived(const IPC::Message& msg) {
OnIDBKeysFromValuesAndKeyPath)
IPC_MESSAGE_HANDLER(UtilityMsg_BatchMode_Started, OnBatchModeStarted)
IPC_MESSAGE_HANDLER(UtilityMsg_BatchMode_Finished, OnBatchModeFinished)
+ IPC_MESSAGE_HANDLER(UtilityMsg_GetPrinterCapsAndDefaults,
+ OnGetPrinterCapsAndDefaults)
IPC_END_MESSAGE_MAP()
}
@@ -306,7 +308,22 @@ void UtilityThread::OnBatchModeFinished() {
ChildProcess::current()->ReleaseProcess();
}
+void UtilityThread::OnGetPrinterCapsAndDefaults(
+ const std::string& printer_name) {
+ scoped_refptr<printing::PrintBackend> print_backend =
+ printing::PrintBackend::CreateInstance(NULL);
+ printing::PrinterCapsAndDefaults printer_info;
+ if (print_backend->GetPrinterCapsAndDefaults(printer_name, &printer_info)) {
+ Send(new UtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded(printer_name,
+ printer_info));
+ } else {
+ Send(new UtilityHostMsg_GetPrinterCapsAndDefaults_Failed(printer_name));
+ }
+ ReleaseProcessIfNeeded();
+}
+
void UtilityThread::ReleaseProcessIfNeeded() {
if (!batch_mode_)
ChildProcess::current()->ReleaseProcess();
}
+
diff --git a/chrome/utility/utility_thread.h b/chrome/utility/utility_thread.h
index 36419aa..187f914 100644
--- a/chrome/utility/utility_thread.h
+++ b/chrome/utility/utility_thread.h
@@ -84,6 +84,12 @@ class UtilityThread : public ChildThread {
// IPC to notify batch mode has finished and we should now quit.
void OnBatchModeFinished();
+ // IPC to get capabilities and defaults for the specified
+ // printer. Used on Windows to isolate the service process from printer driver
+ // crashes by executing this in a separate process. This does not run in a
+ // sandbox.
+ void OnGetPrinterCapsAndDefaults(const std::string& printer_name);
+
// Releases the process if we are not (or no longer) in batch mode.
void ReleaseProcessIfNeeded();