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

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

Issue 2748253005: Cleanup jobs which have failed. (Closed)
Patch Set: fix fake 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.
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 // Copy job_id and printer_id. |job| is about to be freed.
164 const int job_id = job->job_id();
165 const std::string printer_id = job->printer().id();
166
167 // Stop montioring jobs after we cancel them. The user no longer cares.
168 jobs_.erase(job->GetUniqueId());
169
170 // Be sure to copy out all relevant fields. |job| may be destroyed after we
171 // exit this scope.
172 content::BrowserThread::GetBlockingPool()->PostTask(
173 FROM_HERE,
174 base::Bind(&CupsPrintJobManagerImpl::CancelJobImpl,
175 weak_ptr_factory_.GetWeakPtr(), printer_id, job_id));
205 } 176 }
206 177
207 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) { 178 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) {
208 NOTREACHED() << "Pause printer is not implemented"; 179 NOTREACHED() << "Pause printer is not implemented";
209 return false; 180 return false;
210 } 181 }
211 182
212 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) { 183 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) {
213 NOTREACHED() << "Resume printer is not implemented"; 184 NOTREACHED() << "Resume printer is not implemented";
214 return false; 185 return false;
(...skipping 16 matching lines...) Expand all
231 base::UTF16ToUTF8(document->settings().title()), 202 base::UTF16ToUTF8(document->settings().title()),
232 job_details->job_id(), document->page_count()); 203 job_details->job_id(), document->page_count());
233 } 204 }
234 } 205 }
235 206
236 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, 207 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name,
237 const std::string& title, 208 const std::string& title,
238 int job_id, 209 int job_id,
239 int total_page_number) { 210 int total_page_number) {
240 auto printer = 211 auto printer =
241 chromeos::PrintersManagerFactory::GetForBrowserContext(profile_) 212 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
242 ->GetPrinter(printer_name); 213 printer_name);
243 if (!printer) { 214 if (!printer) {
244 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " 215 LOG(WARNING) << "Printer was removed while job was in progress. It cannot "
245 "be tracked"; 216 "be tracked";
246 return false; 217 return false;
247 } 218 }
248 219
249 // Create a new print job. 220 // Create a new print job.
250 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title, 221 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title,
251 total_page_number); 222 total_page_number);
252 std::string key = cpj->GetUniqueId(); 223 std::string key = cpj->GetUniqueId();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 } 259 }
289 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()}; 260 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
290 261
291 content::BrowserThread::PostTaskAndReplyWithResult( 262 content::BrowserThread::PostTaskAndReplyWithResult(
292 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, 263 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
293 base::Bind(&QueryCups, &cups_connection_, ids), 264 base::Bind(&QueryCups, &cups_connection_, ids),
294 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, 265 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
295 weak_ptr_factory_.GetWeakPtr())); 266 weak_ptr_factory_.GetWeakPtr()));
296 } 267 }
297 268
269 bool CupsPrintJobManagerImpl::UpdatePrintJob(
270 const ::printing::PrinterStatus& printer_status,
271 const ::printing::CupsJob& job,
272 CupsPrintJob* print_job) {
273 DCHECK_EQ(job.id, print_job->job_id());
274
275 State old_state = print_job->state();
276
277 bool pages_updated = false;
278 switch (job.state) {
279 case ::printing::CupsJob::PROCESSING:
280 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
281 if (EnforceTimeout(job, print_job)) {
282 LOG(WARNING) << "Connecting to printer timed out";
283 print_job->set_expired(true);
284 }
285 } else {
286 pages_updated = UpdateCurrentPage(job, print_job);
287 }
288 break;
289 case ::printing::CupsJob::COMPLETED:
290 DCHECK_GE(job.current_pages, print_job->total_page_number());
291 print_job->set_state(State::STATE_DOCUMENT_DONE);
292 break;
293 case ::printing::CupsJob::ABORTED:
294 case ::printing::CupsJob::CANCELED:
295 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
296 // fall through
297 default:
298 print_job->set_state(ConvertState(job.state));
299 break;
300 }
301
302 return print_job->state() != old_state || pages_updated;
303 }
304
298 // Use job information to update local job states. Previously completed jobs 305 // 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 306 // could be in |jobs| but those are ignored as we will not emit updates for them
300 // after they are completed. 307 // after they are completed.
301 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) { 308 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) {
302 const std::vector<::printing::QueueStatus>& queues = result.queues; 309 const std::vector<::printing::QueueStatus>& queues = result.queues;
303 310
304 // Query has completed. Allow more queries. 311 // Query has completed. Allow more queries.
305 in_query_ = false; 312 in_query_ = false;
306 313
307 // If the query failed, either retry or purge. 314 // If the query failed, either retry or purge.
(...skipping 24 matching lines...) Expand all
332 if (entry == jobs_.end()) 339 if (entry == jobs_.end())
333 continue; 340 continue;
334 341
335 CupsPrintJob* print_job = entry->second.get(); 342 CupsPrintJob* print_job = entry->second.get();
336 343
337 if (UpdatePrintJob(queue.printer_status, job, print_job)) { 344 if (UpdatePrintJob(queue.printer_status, job, print_job)) {
338 // The state of the job changed, notify observers. 345 // The state of the job changed, notify observers.
339 NotifyJobStateUpdate(print_job); 346 NotifyJobStateUpdate(print_job);
340 } 347 }
341 348
342 // Cleanup completed jobs. 349 if (print_job->expired()) {
343 if (print_job->IsJobFinished()) { 350 // Job needs to be forcibly cancelled.
351 CancelPrintJob(print_job);
352 // Beware, print_job was removed from jobs_ and deleted.
353 } else if (print_job->IsJobFinished()) {
354 // Cleanup completed jobs.
344 jobs_.erase(entry); 355 jobs_.erase(entry);
345 } else { 356 } else {
346 active_jobs.push_back(key); 357 active_jobs.push_back(key);
347 } 358 }
348 } 359 }
349 } 360 }
350 361
351 // Keep polling until all jobs complete or error. 362 // Keep polling until all jobs complete or error.
352 if (!active_jobs.empty()) { 363 if (!active_jobs.empty()) {
353 // During normal operations, we poll at the default rate. 364 // During normal operations, we poll at the default rate.
(...skipping 10 matching lines...) Expand all
364 for (const auto& entry : jobs_) { 375 for (const auto& entry : jobs_) {
365 // Declare all lost jobs errors. 376 // Declare all lost jobs errors.
366 CupsPrintJob* job = entry.second.get(); 377 CupsPrintJob* job = entry.second.get();
367 job->set_state(CupsPrintJob::State::STATE_ERROR); 378 job->set_state(CupsPrintJob::State::STATE_ERROR);
368 NotifyJobStateUpdate(job); 379 NotifyJobStateUpdate(job);
369 } 380 }
370 381
371 jobs_.clear(); 382 jobs_.clear();
372 } 383 }
373 384
385 void CupsPrintJobManagerImpl::CancelJobImpl(const std::string& printer_id,
386 const int job_id) {
387 std::unique_ptr<::printing::CupsPrinter> printer =
388 cups_connection_.GetPrinter(printer_id);
389 if (!printer) {
390 LOG(WARNING) << "Printer not found: " << printer_id;
391 return;
392 }
393
394 if (!printer->CancelJob(job_id)) {
395 // This is not expected to fail but log it if it does.
396 LOG(WARNING) << "Cancelling job failed. Job may be stuck in queue.";
397 }
398 }
399
374 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) { 400 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
375 switch (job->state()) { 401 switch (job->state()) {
376 case State::STATE_NONE: 402 case State::STATE_NONE:
377 // State does not require notification. 403 // State does not require notification.
378 break; 404 break;
379 case State::STATE_WAITING: 405 case State::STATE_WAITING:
380 NotifyJobUpdated(job); 406 NotifyJobUpdated(job);
381 break; 407 break;
382 case State::STATE_STARTED: 408 case State::STATE_STARTED:
383 NotifyJobStarted(job); 409 NotifyJobStarted(job);
(...skipping 18 matching lines...) Expand all
402 break; 428 break;
403 } 429 }
404 } 430 }
405 431
406 // static 432 // static
407 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 433 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
408 return new CupsPrintJobManagerImpl(profile); 434 return new CupsPrintJobManagerImpl(profile);
409 } 435 }
410 436
411 } // namespace chromeos 437 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698