| Index: chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
|
| diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
|
| index d333cb94627dfad9331afc59102276e97efb1daa..9806dd7b78c3109ecbe98cdaf53ebae273759849 100644
|
| --- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
|
| +++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
|
| @@ -33,6 +33,9 @@ namespace {
|
| // The rate in milliseconds at which we will poll CUPS for print job updates.
|
| const int kPollRate = 1000;
|
|
|
| +// Threshold for giving up on communicating with CUPS.
|
| +const int kRetryMax = 6;
|
| +
|
| // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState.
|
| chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) {
|
| using cpj = chromeos::CupsPrintJob::State;
|
| @@ -61,6 +64,13 @@ chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) {
|
| return cpj::STATE_NONE;
|
| }
|
|
|
| +chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
|
| + const std::vector<std::string>& printer_ids) {
|
| + chromeos::QueryResult result;
|
| + result.success = connection->GetJobs(printer_ids, &result.queues);
|
| + return result;
|
| +}
|
| +
|
| } // namespace
|
|
|
| namespace chromeos {
|
| @@ -134,6 +144,7 @@ bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name,
|
| total_page_number);
|
| std::string key = cpj->GetUniqueId();
|
| jobs_[key] = std::move(cpj);
|
| +
|
| CupsPrintJob* job = jobs_[key].get();
|
| NotifyJobCreated(job);
|
|
|
| @@ -153,36 +164,67 @@ void CupsPrintJobManagerImpl::ScheduleQuery() {
|
| void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
|
| if (!in_query_) {
|
| in_query_ = true;
|
| - content::BrowserThread::PostDelayedTask(
|
| - content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
|
| - base::Bind(&CupsPrintJobManagerImpl::QueryCups,
|
| +
|
| + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&CupsPrintJobManagerImpl::PostQuery,
|
| weak_ptr_factory_.GetWeakPtr()),
|
| - base::TimeDelta::FromMilliseconds(kPollRate));
|
| + delay);
|
| }
|
| }
|
|
|
| -// Query CUPS asynchronously. Post results back to UI thread.
|
| -void CupsPrintJobManagerImpl::QueryCups() {
|
| - std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs();
|
| +void CupsPrintJobManagerImpl::PostQuery() {
|
| + // The set of active printers is expected to be small.
|
| + std::set<std::string> printer_ids;
|
| + for (const auto& entry : jobs_) {
|
| + printer_ids.insert(entry.second->printer().id());
|
| + }
|
| + std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
|
|
|
| - content::BrowserThread::PostTask(
|
| - content::BrowserThread::ID::UI, FROM_HERE,
|
| + content::BrowserThread::PostTaskAndReplyWithResult(
|
| + content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
|
| + base::Bind(&QueryCups, &cups_connection_, ids),
|
| base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
|
| - weak_ptr_factory_.GetWeakPtr(), jobs));
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| // Use job information to update local job states. Previously completed jobs
|
| // could be in |jobs| but those are ignored as we will not emit updates for them
|
| // after they are completed.
|
| -void CupsPrintJobManagerImpl::UpdateJobs(
|
| - const std::vector<::printing::CupsJob>& jobs) {
|
| +void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
|
| + const std::vector<::printing::QueueStatus>& queues = result.queues;
|
| +
|
| + // Query has completed. Allow more queries.
|
| in_query_ = false;
|
|
|
| + // If the query failed, either retry or purge.
|
| + if (!result.success) {
|
| + retry_count_++;
|
| + LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry ("
|
| + << retry_count_ << ")";
|
| + if (retry_count_ > kRetryMax) {
|
| + LOG(ERROR) << "CUPS is unreachable. Giving up on all jobs.";
|
| + PurgeJobs();
|
| + } else {
|
| + // Schedule another query with a larger delay.
|
| + DCHECK_GE(1, retry_count_);
|
| + ScheduleQuery(
|
| + base::TimeDelta::FromMilliseconds(kPollRate * retry_count_));
|
| + }
|
| + return;
|
| + }
|
| +
|
| + // A query has completed. Reset retry counter.
|
| + retry_count_ = 0;
|
| +
|
| std::vector<std::string> active_jobs;
|
| - for (auto& job : jobs) {
|
| - std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
|
| - const auto& entry = jobs_.find(key);
|
| - if (entry != jobs_.end()) {
|
| + for (const auto& queue : queues) {
|
| + for (auto& job : queue.jobs) {
|
| + std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
|
| + const auto& entry = jobs_.find(key);
|
| + if (entry == jobs_.end())
|
| + continue;
|
| +
|
| CupsPrintJob* print_job = entry->second.get();
|
|
|
| // Update a job we're tracking.
|
| @@ -199,18 +241,23 @@ void CupsPrintJobManagerImpl::UpdateJobs(
|
|
|
| // Keep polling until all jobs complete or error.
|
| if (!active_jobs.empty()) {
|
| + // During normal operations, we poll at the default rate.
|
| ScheduleQuery();
|
| } else if (!jobs_.empty()) {
|
| // We're tracking jobs that we didn't receive an update for. Something bad
|
| // has happened.
|
| LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
|
| - for (const auto& entry : jobs_) {
|
| - // Declare all lost jobs errors.
|
| - JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
|
| - }
|
| + PurgeJobs();
|
| + }
|
| +}
|
|
|
| - jobs_.clear();
|
| +void CupsPrintJobManagerImpl::PurgeJobs() {
|
| + for (const auto& entry : jobs_) {
|
| + // Declare all lost jobs errors.
|
| + JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
|
| }
|
| +
|
| + jobs_.clear();
|
| }
|
|
|
| void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job,
|
|
|