diff options
-rw-r--r-- | chrome/common/common_param_traits.cc | 31 | ||||
-rw-r--r-- | chrome/common/common_param_traits.h | 9 | ||||
-rw-r--r-- | chrome/common/common_param_traits_unittest.cc | 22 | ||||
-rw-r--r-- | chrome/common/utility_messages_internal.h | 20 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_proxy_backend.cc | 148 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system.h | 13 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_cups.cc | 87 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_win.cc | 79 | ||||
-rw-r--r-- | chrome/service/cloud_print/printer_job_handler.cc | 46 | ||||
-rw-r--r-- | chrome/service/cloud_print/printer_job_handler.h | 6 | ||||
-rw-r--r-- | chrome/service/service_child_process_host.cc | 13 | ||||
-rw-r--r-- | chrome/service/service_child_process_host.h | 6 | ||||
-rw-r--r-- | chrome/service/service_utility_process_host.cc | 20 | ||||
-rw-r--r-- | chrome/service/service_utility_process_host.h | 25 | ||||
-rw-r--r-- | chrome/utility/utility_main.cc | 14 | ||||
-rw-r--r-- | chrome/utility/utility_thread.cc | 17 | ||||
-rw-r--r-- | chrome/utility/utility_thread.h | 6 |
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(); |