Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc

Issue 2748253005: Cleanup jobs which have failed. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/printing/cups_print_job_manager_impl.h" 5 #include "chrome/browser/chromeos/printing/cups_print_job_manager_impl.h"
6 6
7 #include <cups/cups.h> 7 #include <cups/cups.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
11 #include <utility> 11 #include <utility>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/sequenced_task_runner_handle.h" 18 #include "base/threading/sequenced_task_runner_handle.h"
19 #include "base/threading/sequenced_worker_pool.h"
19 #include "chrome/browser/chrome_notification_types.h" 20 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/chromeos/printing/cups_print_job.h" 21 #include "chrome/browser/chromeos/printing/cups_print_job.h"
21 #include "chrome/browser/chromeos/printing/printers_manager.h" 22 #include "chrome/browser/chromeos/printing/printers_manager.h"
22 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" 23 #include "chrome/browser/chromeos/printing/printers_manager_factory.h"
23 #include "chrome/browser/printing/print_job.h" 24 #include "chrome/browser/printing/print_job.h"
24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile.h"
25 #include "content/public/browser/browser_context.h" 26 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_registrar.h" 28 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_service.h" 29 #include "content/public/browser/notification_service.h"
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 print_job->set_state(State::STATE_STARTED); 135 print_job->set_state(State::STATE_STARTED);
135 } else { 136 } else {
136 pages_updated = job.current_pages != print_job->printed_page_number(); 137 pages_updated = job.current_pages != print_job->printed_page_number();
137 print_job->set_printed_page_number(job.current_pages); 138 print_job->set_printed_page_number(job.current_pages);
138 print_job->set_state(State::STATE_PAGE_DONE); 139 print_job->set_state(State::STATE_PAGE_DONE);
139 } 140 }
140 141
141 return pages_updated; 142 return pages_updated;
142 } 143 }
143 144
144 // Updates the state of a print job based on |printer_status| and |job|. Returns
145 // true if observers need to be notified of an update.
146 bool UpdatePrintJob(const printing::PrinterStatus& printer_status,
147 const printing::CupsJob& job,
148 chromeos::CupsPrintJob* print_job) {
149 DCHECK_EQ(job.id, print_job->job_id());
150
151 State old_state = print_job->state();
152
153 bool pages_updated = false;
154 switch (job.state) {
155 case printing::CupsJob::PROCESSING:
156 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
157 if (EnforceTimeout(job, print_job)) {
158 LOG(WARNING) << "Connecting to printer timed out";
159 // TODO(skau): Purge job from queue.
160 }
161 break;
162 }
163 pages_updated = UpdateCurrentPage(job, print_job);
164 break;
165 case printing::CupsJob::COMPLETED:
166 DCHECK_GE(job.current_pages, print_job->total_page_number());
167 print_job->set_state(State::STATE_DOCUMENT_DONE);
168 break;
169 case printing::CupsJob::ABORTED:
170 case printing::CupsJob::CANCELED:
171 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
172 // fall through
173 default:
174 print_job->set_state(ConvertState(job.state));
175 break;
176 }
177
178 return print_job->state() != old_state || pages_updated;
179 }
180
181 } // namespace 145 } // namespace
182 146
183 namespace chromeos { 147 namespace chromeos {
184 148
185 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile) 149 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
186 : CupsPrintJobManager(profile), 150 : CupsPrintJobManager(profile),
187 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false), 151 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false),
188 weak_ptr_factory_(this) { 152 weak_ptr_factory_(this) {
189 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, 153 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
190 content::NotificationService::AllSources()); 154 content::NotificationService::AllSources());
191 } 155 }
192 156
193 CupsPrintJobManagerImpl::~CupsPrintJobManagerImpl() {} 157 CupsPrintJobManagerImpl::~CupsPrintJobManagerImpl() {}
194 158
195 bool CupsPrintJobManagerImpl::CancelPrintJob(CupsPrintJob* job) { 159 // Must be run from the UI thread or jobs_ could become inconsistent.
Carlson 2017/03/16 18:36:48 the "or jobs_ could become inconsistent" suffix he
skau 2017/03/16 22:14:36 Done.
196 std::string printer_id = job->printer().id(); 160 void CupsPrintJobManagerImpl::CancelPrintJob(CupsPrintJob* job) {
197 std::unique_ptr<::printing::CupsPrinter> printer = 161 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
198 cups_connection_.GetPrinter(printer_id);
199 if (!printer) {
200 LOG(WARNING) << "Printer not found";
201 return false;
202 }
203 162
204 return printer->CancelJob(job->job_id()); 163 const int job_id = job->job_id();
164
165 // Copy printer_id. |job| is about to be freed.
166 const std::string printer_id = job->printer().id();
167
168 // Stop montioring jobs after we cancel them. The user no longer cares.
169 jobs_.erase(job->GetUniqueId());
170
171 // Be sure to copy out all relevant fields. |job| may be destroyed after we
172 // exit this scope.
173 content::BrowserThread::GetBlockingPool()->PostTask(
174 FROM_HERE,
175 base::Bind(&CupsPrintJobManagerImpl::CancelJobImpl,
176 weak_ptr_factory_.GetWeakPtr(), printer_id, job_id));
205 } 177 }
206 178
207 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) { 179 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) {
208 NOTREACHED() << "Pause printer is not implemented"; 180 NOTREACHED() << "Pause printer is not implemented";
209 return false; 181 return false;
210 } 182 }
211 183
212 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) { 184 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) {
213 NOTREACHED() << "Resume printer is not implemented"; 185 NOTREACHED() << "Resume printer is not implemented";
214 return false; 186 return false;
(...skipping 16 matching lines...) Expand all
231 base::UTF16ToUTF8(document->settings().title()), 203 base::UTF16ToUTF8(document->settings().title()),
232 job_details->job_id(), document->page_count()); 204 job_details->job_id(), document->page_count());
233 } 205 }
234 } 206 }
235 207
236 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, 208 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name,
237 const std::string& title, 209 const std::string& title,
238 int job_id, 210 int job_id,
239 int total_page_number) { 211 int total_page_number) {
240 auto printer = 212 auto printer =
241 chromeos::PrintersManagerFactory::GetForBrowserContext(profile_) 213 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
242 ->GetPrinter(printer_name); 214 printer_name);
243 if (!printer) { 215 if (!printer) {
244 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " 216 LOG(WARNING) << "Printer was removed while job was in progress. It cannot "
245 "be tracked"; 217 "be tracked";
246 return false; 218 return false;
247 } 219 }
248 220
249 // Create a new print job. 221 // Create a new print job.
250 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title, 222 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title,
251 total_page_number); 223 total_page_number);
252 std::string key = cpj->GetUniqueId(); 224 std::string key = cpj->GetUniqueId();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 } 260 }
289 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()}; 261 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
290 262
291 content::BrowserThread::PostTaskAndReplyWithResult( 263 content::BrowserThread::PostTaskAndReplyWithResult(
292 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, 264 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
293 base::Bind(&QueryCups, &cups_connection_, ids), 265 base::Bind(&QueryCups, &cups_connection_, ids),
294 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, 266 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
295 weak_ptr_factory_.GetWeakPtr())); 267 weak_ptr_factory_.GetWeakPtr()));
296 } 268 }
297 269
270 bool CupsPrintJobManagerImpl::UpdatePrintJob(
271 const ::printing::PrinterStatus& printer_status,
272 const ::printing::CupsJob& job,
273 CupsPrintJob* print_job) {
274 DCHECK_EQ(job.id, print_job->job_id());
275
276 State old_state = print_job->state();
277
278 bool pages_updated = false;
279 switch (job.state) {
280 case ::printing::CupsJob::PROCESSING:
281 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
282 if (EnforceTimeout(job, print_job)) {
283 LOG(WARNING) << "Connecting to printer timed out";
284 print_job->set_expired(true);
285 }
286 break;
Carlson 2017/03/16 18:36:48 Nit: I think it would be slightly more natural to
skau 2017/03/16 22:14:36 Done.
287 }
288 pages_updated = UpdateCurrentPage(job, print_job);
289 break;
290 case ::printing::CupsJob::COMPLETED:
291 DCHECK_GE(job.current_pages, print_job->total_page_number());
292 print_job->set_state(State::STATE_DOCUMENT_DONE);
293 break;
294 case ::printing::CupsJob::ABORTED:
295 case ::printing::CupsJob::CANCELED:
296 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
297 // fall through
298 default:
299 print_job->set_state(ConvertState(job.state));
300 break;
301 }
302
303 return print_job->state() != old_state || pages_updated;
304 }
305
298 // Use job information to update local job states. Previously completed jobs 306 // Use job information to update local job states. Previously completed jobs
299 // could be in |jobs| but those are ignored as we will not emit updates for them 307 // could be in |jobs| but those are ignored as we will not emit updates for them
300 // after they are completed. 308 // after they are completed.
301 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) { 309 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
302 const std::vector<::printing::QueueStatus>& queues = result.queues; 310 const std::vector<::printing::QueueStatus>& queues = result.queues;
303 311
304 // Query has completed. Allow more queries. 312 // Query has completed. Allow more queries.
305 in_query_ = false; 313 in_query_ = false;
306 314
307 // If the query failed, either retry or purge. 315 // If the query failed, either retry or purge.
(...skipping 24 matching lines...) Expand all
332 if (entry == jobs_.end()) 340 if (entry == jobs_.end())
333 continue; 341 continue;
334 342
335 CupsPrintJob* print_job = entry->second.get(); 343 CupsPrintJob* print_job = entry->second.get();
336 344
337 if (UpdatePrintJob(queue.printer_status, job, print_job)) { 345 if (UpdatePrintJob(queue.printer_status, job, print_job)) {
338 // The state of the job changed, notify observers. 346 // The state of the job changed, notify observers.
339 NotifyJobStateUpdate(print_job); 347 NotifyJobStateUpdate(print_job);
340 } 348 }
341 349
342 // Cleanup completed jobs. 350 if (print_job->expired()) {
343 if (print_job->IsJobFinished()) { 351 // Job needs to be forcibly cancelled.
352 CancelPrintJob(print_job);
353 // Beware, print_job was removed from jobs_ and deleted.
354 } else if (print_job->IsJobFinished()) {
355 // Cleanup completed jobs.
344 jobs_.erase(entry); 356 jobs_.erase(entry);
345 } else { 357 } else {
346 active_jobs.push_back(key); 358 active_jobs.push_back(key);
347 } 359 }
348 } 360 }
349 } 361 }
350 362
351 // Keep polling until all jobs complete or error. 363 // Keep polling until all jobs complete or error.
352 if (!active_jobs.empty()) { 364 if (!active_jobs.empty()) {
353 // During normal operations, we poll at the default rate. 365 // During normal operations, we poll at the default rate.
(...skipping 10 matching lines...) Expand all
364 for (const auto& entry : jobs_) { 376 for (const auto& entry : jobs_) {
365 // Declare all lost jobs errors. 377 // Declare all lost jobs errors.
366 CupsPrintJob* job = entry.second.get(); 378 CupsPrintJob* job = entry.second.get();
367 job->set_state(CupsPrintJob::State::STATE_ERROR); 379 job->set_state(CupsPrintJob::State::STATE_ERROR);
368 NotifyJobStateUpdate(job); 380 NotifyJobStateUpdate(job);
369 } 381 }
370 382
371 jobs_.clear(); 383 jobs_.clear();
372 } 384 }
373 385
386 void CupsPrintJobManagerImpl::CancelJobImpl(const std::string& printer_id,
387 const int job_id) {
388 std::unique_ptr<::printing::CupsPrinter> printer =
389 cups_connection_.GetPrinter(printer_id);
390 if (!printer) {
391 LOG(WARNING) << "Printer not found";
Carlson 2017/03/16 18:36:48 Would it be useful to add printer_id and/or job_id
skau 2017/03/16 22:14:36 I'll log the printer_id. I don't think the job_id
392 return;
393 }
394
395 if (!printer->CancelJob(job_id)) {
396 // This is not expected to fail but log it if it does.
397 LOG(WARNING) << "Cancelling job failed. Job may be stuck in queue.";
398 }
399 }
400
374 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) { 401 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
375 switch (job->state()) { 402 switch (job->state()) {
376 case State::STATE_NONE: 403 case State::STATE_NONE:
377 // State does not require notification. 404 // State does not require notification.
378 break; 405 break;
379 case State::STATE_WAITING: 406 case State::STATE_WAITING:
380 NotifyJobUpdated(job); 407 NotifyJobUpdated(job);
381 break; 408 break;
382 case State::STATE_STARTED: 409 case State::STATE_STARTED:
383 NotifyJobStarted(job); 410 NotifyJobStarted(job);
(...skipping 18 matching lines...) Expand all
402 break; 429 break;
403 } 430 }
404 } 431 }
405 432
406 // static 433 // static
407 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 434 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
408 return new CupsPrintJobManagerImpl(profile); 435 return new CupsPrintJobManagerImpl(profile);
409 } 436 }
410 437
411 } // namespace chromeos 438 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698