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

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

Issue 2943843002: Convert to CupsPrintJobManagerImpl to TaskScheduler. (Closed)
Patch Set: strong pointers and DCHECKs Created 3 years, 5 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
« no previous file with comments | « chrome/browser/chromeos/printing/cups_print_job_manager_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
17 #include "base/sequenced_task_runner.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/sequenced_task_runner_handle.h" 20 #include "base/task_runner_util.h"
20 #include "base/threading/sequenced_worker_pool.h" 21 #include "base/task_scheduler/post_task.h"
22 #include "base/threading/thread_task_runner_handle.h"
21 #include "chrome/browser/chrome_notification_types.h" 23 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/chromeos/printing/cups_print_job.h" 24 #include "chrome/browser/chromeos/printing/cups_print_job.h"
23 #include "chrome/browser/chromeos/printing/printers_manager.h" 25 #include "chrome/browser/chromeos/printing/printers_manager.h"
24 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" 26 #include "chrome/browser/chromeos/printing/printers_manager_factory.h"
25 #include "chrome/browser/printing/print_job.h" 27 #include "chrome/browser/printing/print_job.h"
26 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/profiles/profile.h"
27 #include "content/public/browser/browser_context.h" 29 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/notification_registrar.h" 31 #include "content/public/browser/notification_registrar.h"
30 #include "content/public/browser/notification_service.h" 32 #include "content/public/browser/notification_service.h"
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 return State::STATE_ERROR; 97 return State::STATE_ERROR;
96 case printing::CupsJob::UNKNOWN: 98 case printing::CupsJob::UNKNOWN:
97 break; 99 break;
98 } 100 }
99 101
100 NOTREACHED(); 102 NOTREACHED();
101 103
102 return State::STATE_NONE; 104 return State::STATE_NONE;
103 } 105 }
104 106
105 chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
106 const std::vector<std::string>& printer_ids) {
107 chromeos::QueryResult result;
108 result.success = connection->GetJobs(printer_ids, &result.queues);
109 return result;
110 }
111
112 // Returns true if |printer_status|.reasons contains |reason|. 107 // Returns true if |printer_status|.reasons contains |reason|.
113 bool ContainsReason(const printing::PrinterStatus printer_status, 108 bool ContainsReason(const printing::PrinterStatus printer_status,
114 PrinterReason::Reason reason) { 109 PrinterReason::Reason reason) {
115 return std::find_if(printer_status.reasons.begin(), 110 return std::find_if(printer_status.reasons.begin(),
116 printer_status.reasons.end(), 111 printer_status.reasons.end(),
117 [&reason](const PrinterReason& r) { 112 [&reason](const PrinterReason& r) {
118 return r.reason == reason; 113 return r.reason == reason;
119 }) != printer_status.reasons.end(); 114 }) != printer_status.reasons.end();
120 } 115 }
121 116
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 print_job->set_state(State::STATE_STARTED); 160 print_job->set_state(State::STATE_STARTED);
166 } else { 161 } else {
167 pages_updated = job.current_pages != print_job->printed_page_number(); 162 pages_updated = job.current_pages != print_job->printed_page_number();
168 print_job->set_printed_page_number(job.current_pages); 163 print_job->set_printed_page_number(job.current_pages);
169 print_job->set_state(State::STATE_PAGE_DONE); 164 print_job->set_state(State::STATE_PAGE_DONE);
170 } 165 }
171 166
172 return pages_updated; 167 return pages_updated;
173 } 168 }
174 169
170 // Updates the state of a print job based on |printer_status| and |job|.
171 // Returns true if observers need to be notified of an update.
172 bool UpdatePrintJob(const ::printing::PrinterStatus& printer_status,
173 const ::printing::CupsJob& job,
174 chromeos::CupsPrintJob* print_job) {
175 DCHECK_EQ(job.id, print_job->job_id());
176
177 State old_state = print_job->state();
178
179 bool pages_updated = false;
180 switch (job.state) {
181 case ::printing::CupsJob::PROCESSING:
182 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
183 if (EnforceTimeout(job, print_job)) {
184 LOG(WARNING) << "Connecting to printer timed out";
185 print_job->set_expired(true);
186 }
187 } else {
188 pages_updated = UpdateCurrentPage(job, print_job);
189 }
190 break;
191 case ::printing::CupsJob::COMPLETED:
192 DCHECK_GE(job.current_pages, print_job->total_page_number());
193 print_job->set_state(State::STATE_DOCUMENT_DONE);
194 break;
195 case ::printing::CupsJob::ABORTED:
196 case ::printing::CupsJob::CANCELED:
197 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
198 // fall through
199 default:
200 print_job->set_state(ConvertState(job.state));
201 break;
202 }
203
204 return print_job->state() != old_state || pages_updated;
205 }
206
175 } // namespace 207 } // namespace
176 208
177 namespace chromeos { 209 namespace chromeos {
178 210
179 QueryResult::QueryResult() = default; 211 QueryResult::QueryResult() = default;
180 212
181 QueryResult::QueryResult(const QueryResult& other) = default; 213 QueryResult::QueryResult(const QueryResult& other) = default;
182 214
183 QueryResult::~QueryResult() = default; 215 QueryResult::~QueryResult() = default;
184 216
217 CupsWrapper::CupsWrapper()
218 : cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false) {
219 DETACH_FROM_SEQUENCE(sequence_checker_);
220 }
221
222 CupsWrapper::~CupsWrapper() = default;
223
224 void CupsWrapper::QueryCups(const std::vector<std::string>& printer_ids,
225 QueryResult* result) {
226 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
227 base::ThreadRestrictions::AssertIOAllowed();
228
229 result->success = cups_connection_.GetJobs(printer_ids, &result->queues);
230 }
231
232 void CupsWrapper::CancelJobImpl(const std::string& printer_id,
233 const int job_id) {
234 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
235 base::ThreadRestrictions::AssertIOAllowed();
236
237 std::unique_ptr<::printing::CupsPrinter> printer =
238 cups_connection_.GetPrinter(printer_id);
239 if (!printer) {
240 LOG(WARNING) << "Printer not found: " << printer_id;
241 return;
242 }
243
244 if (!printer->CancelJob(job_id)) {
245 // This is not expected to fail but log it if it does.
246 LOG(WARNING) << "Cancelling job failed. Job may be stuck in queue.";
247 }
248 }
249
185 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile) 250 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
186 : CupsPrintJobManager(profile), 251 : CupsPrintJobManager(profile),
187 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false), 252 query_runner_(base::CreateSequencedTaskRunnerWithTraits(
253 base::TaskTraits(base::TaskPriority::BACKGROUND,
254 base::MayBlock(),
255 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN))),
256 cups_wrapper_(new CupsWrapper(),
257 base::OnTaskRunnerDeleter(query_runner_)),
188 weak_ptr_factory_(this) { 258 weak_ptr_factory_(this) {
189 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, 259 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
190 content::NotificationService::AllSources()); 260 content::NotificationService::AllSources());
191 } 261 }
192 262
193 CupsPrintJobManagerImpl::~CupsPrintJobManagerImpl() {} 263 CupsPrintJobManagerImpl::~CupsPrintJobManagerImpl() {}
194 264
195 // Must be run from the UI thread. 265 // Must be run from the UI thread.
196 void CupsPrintJobManagerImpl::CancelPrintJob(CupsPrintJob* job) { 266 void CupsPrintJobManagerImpl::CancelPrintJob(CupsPrintJob* job) {
197 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 267 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
198 268
199 // Copy job_id and printer_id. |job| is about to be freed. 269 // Copy job_id and printer_id. |job| is about to be freed.
200 const int job_id = job->job_id(); 270 const int job_id = job->job_id();
201 const std::string printer_id = job->printer().id(); 271 const std::string printer_id = job->printer().id();
202 272
203 // Stop montioring jobs after we cancel them. The user no longer cares. 273 // Stop montioring jobs after we cancel them. The user no longer cares.
204 jobs_.erase(job->GetUniqueId()); 274 jobs_.erase(job->GetUniqueId());
205 275
206 // Be sure to copy out all relevant fields. |job| may be destroyed after we 276 query_runner_->PostTask(
207 // exit this scope.
208 content::BrowserThread::GetBlockingPool()->PostTask(
209 FROM_HERE, 277 FROM_HERE,
210 base::Bind(&CupsPrintJobManagerImpl::CancelJobImpl, 278 base::Bind(&CupsWrapper::CancelJobImpl,
211 weak_ptr_factory_.GetWeakPtr(), printer_id, job_id)); 279 base::Unretained(cups_wrapper_.get()), printer_id, job_id));
212 } 280 }
213 281
214 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) { 282 bool CupsPrintJobManagerImpl::SuspendPrintJob(CupsPrintJob* job) {
215 NOTREACHED() << "Pause printer is not implemented"; 283 NOTREACHED() << "Pause printer is not implemented";
216 return false; 284 return false;
217 } 285 }
218 286
219 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) { 287 bool CupsPrintJobManagerImpl::ResumePrintJob(CupsPrintJob* job) {
220 NOTREACHED() << "Resume printer is not implemented"; 288 NOTREACHED() << "Resume printer is not implemented";
221 return false; 289 return false;
(...skipping 15 matching lines...) Expand all
237 CreatePrintJob(base::UTF16ToUTF8(document->settings().device_name()), 305 CreatePrintJob(base::UTF16ToUTF8(document->settings().device_name()),
238 base::UTF16ToUTF8(document->settings().title()), 306 base::UTF16ToUTF8(document->settings().title()),
239 job_details->job_id(), document->page_count()); 307 job_details->job_id(), document->page_count());
240 } 308 }
241 } 309 }
242 310
243 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, 311 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name,
244 const std::string& title, 312 const std::string& title,
245 int job_id, 313 int job_id,
246 int total_page_number) { 314 int total_page_number) {
315 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
316
247 auto printer = 317 auto printer =
248 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter( 318 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
249 printer_name); 319 printer_name);
250 if (!printer) { 320 if (!printer) {
251 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " 321 LOG(WARNING) << "Printer was removed while job was in progress. It cannot "
252 "be tracked"; 322 "be tracked";
253 return false; 323 return false;
254 } 324 }
255 325
256 // Records the number of jobs we're currently tracking when a new job is 326 // Records the number of jobs we're currently tracking when a new job is
(...skipping 17 matching lines...) Expand all
274 ScheduleQuery(base::TimeDelta()); 344 ScheduleQuery(base::TimeDelta());
275 345
276 return true; 346 return true;
277 } 347 }
278 348
279 void CupsPrintJobManagerImpl::ScheduleQuery() { 349 void CupsPrintJobManagerImpl::ScheduleQuery() {
280 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate)); 350 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate));
281 } 351 }
282 352
283 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) { 353 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
354 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
355
284 if (!in_query_) { 356 if (!in_query_) {
285 in_query_ = true; 357 in_query_ = true;
286 358
287 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( 359 content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
288 FROM_HERE, 360 ->PostDelayedTask(FROM_HERE,
gab 2017/06/29 17:12:20 BrowserThread::PostDelayedTask(BrowserThread::UI,
gab 2017/06/29 17:12:20 BrowserThread::PostDelayedTask(BrowserThread::UI,
skau 2017/07/05 22:14:32 Done.
289 base::Bind(&CupsPrintJobManagerImpl::PostQuery, 361 base::Bind(&CupsPrintJobManagerImpl::PostQuery,
290 weak_ptr_factory_.GetWeakPtr()), 362 weak_ptr_factory_.GetWeakPtr()),
291 delay); 363 delay);
292 } 364 }
293 } 365 }
294 366
295 void CupsPrintJobManagerImpl::PostQuery() { 367 void CupsPrintJobManagerImpl::PostQuery() {
368 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
369
296 // The set of active printers is expected to be small. 370 // The set of active printers is expected to be small.
297 std::set<std::string> printer_ids; 371 std::set<std::string> printer_ids;
298 for (const auto& entry : jobs_) { 372 for (const auto& entry : jobs_) {
299 printer_ids.insert(entry.second->printer().id()); 373 printer_ids.insert(entry.second->printer().id());
300 } 374 }
301 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()}; 375 std::vector<std::string> ids{printer_ids.begin(), printer_ids.end()};
302 376
303 content::BrowserThread::PostTaskAndReplyWithResult( 377 auto result = base::MakeUnique<QueryResult>();
304 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, 378 QueryResult* result_ptr = result.get();
305 base::Bind(&QueryCups, &cups_connection_, ids), 379 // Runs a query on query_runner_ which will rejoin this sequnece on
gab 2017/06/29 17:12:20 |query_runner_|
skau 2017/07/05 22:14:32 Done.
380 // completion.
381 query_runner_->PostTaskAndReply(
382 FROM_HERE,
383 base::Bind(&CupsWrapper::QueryCups, base::Unretained(cups_wrapper_.get()),
384 ids, result_ptr),
306 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, 385 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs,
307 weak_ptr_factory_.GetWeakPtr())); 386 weak_ptr_factory_.GetWeakPtr(), base::Passed(&result)));
308 }
309
310 bool CupsPrintJobManagerImpl::UpdatePrintJob(
311 const ::printing::PrinterStatus& printer_status,
312 const ::printing::CupsJob& job,
313 CupsPrintJob* print_job) {
314 DCHECK_EQ(job.id, print_job->job_id());
315
316 State old_state = print_job->state();
317
318 bool pages_updated = false;
319 switch (job.state) {
320 case ::printing::CupsJob::PROCESSING:
321 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
322 if (EnforceTimeout(job, print_job)) {
323 LOG(WARNING) << "Connecting to printer timed out";
324 print_job->set_expired(true);
325 }
326 } else {
327 pages_updated = UpdateCurrentPage(job, print_job);
328 }
329 break;
330 case ::printing::CupsJob::COMPLETED:
331 DCHECK_GE(job.current_pages, print_job->total_page_number());
332 print_job->set_state(State::STATE_DOCUMENT_DONE);
333 break;
334 case ::printing::CupsJob::ABORTED:
335 case ::printing::CupsJob::CANCELED:
336 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
337 // fall through
338 default:
339 print_job->set_state(ConvertState(job.state));
340 break;
341 }
342
343 return print_job->state() != old_state || pages_updated;
344 } 387 }
345 388
346 // Use job information to update local job states. Previously completed jobs 389 // Use job information to update local job states. Previously completed jobs
347 // could be in |jobs| but those are ignored as we will not emit updates for them 390 // could be in |jobs| but those are ignored as we will not emit updates for
348 // after they are completed. 391 // them after they are completed.
349 void CupsPrintJobManagerImpl::UpdateJobs(const QueryResult& result) { 392 void CupsPrintJobManagerImpl::UpdateJobs(std::unique_ptr<QueryResult> result) {
350 const std::vector<::printing::QueueStatus>& queues = result.queues; 393 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
394
395 const std::vector<::printing::QueueStatus>& queues = result->queues;
351 396
352 // Query has completed. Allow more queries. 397 // Query has completed. Allow more queries.
353 in_query_ = false; 398 in_query_ = false;
354 399
355 // If the query failed, either retry or purge. 400 // If the query failed, either retry or purge.
356 if (!result.success) { 401 if (!result->success) {
357 retry_count_++; 402 retry_count_++;
358 LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry (" 403 LOG(WARNING) << "Failed to query CUPS for queue status. Schedule retry ("
359 << retry_count_ << ")"; 404 << retry_count_ << ")";
360 if (retry_count_ > kRetryMax) { 405 if (retry_count_ > kRetryMax) {
361 LOG(ERROR) << "CUPS is unreachable. Giving up on all jobs."; 406 LOG(ERROR) << "CUPS is unreachable. Giving up on all jobs.";
362 PurgeJobs(); 407 PurgeJobs();
363 } else { 408 } else {
364 // Schedule another query with a larger delay. 409 // Schedule another query with a larger delay.
365 DCHECK_GE(1, retry_count_); 410 DCHECK_GE(1, retry_count_);
366 ScheduleQuery( 411 ScheduleQuery(
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 active_jobs.push_back(key); 445 active_jobs.push_back(key);
401 } 446 }
402 } 447 }
403 } 448 }
404 449
405 // Keep polling until all jobs complete or error. 450 // Keep polling until all jobs complete or error.
406 if (!active_jobs.empty()) { 451 if (!active_jobs.empty()) {
407 // During normal operations, we poll at the default rate. 452 // During normal operations, we poll at the default rate.
408 ScheduleQuery(); 453 ScheduleQuery();
409 } else if (!jobs_.empty()) { 454 } else if (!jobs_.empty()) {
410 // We're tracking jobs that we didn't receive an update for. Something bad 455 // We're tracking jobs that we didn't receive an update for. Something
411 // has happened. 456 // bad has happened.
412 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; 457 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
413 PurgeJobs(); 458 PurgeJobs();
414 } 459 }
415 } 460 }
416 461
417 void CupsPrintJobManagerImpl::PurgeJobs() { 462 void CupsPrintJobManagerImpl::PurgeJobs() {
463 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
464
418 for (const auto& entry : jobs_) { 465 for (const auto& entry : jobs_) {
419 // Declare all lost jobs errors. 466 // Declare all lost jobs errors.
420 RecordJobResult(LOST); 467 RecordJobResult(LOST);
421 CupsPrintJob* job = entry.second.get(); 468 CupsPrintJob* job = entry.second.get();
422 job->set_state(CupsPrintJob::State::STATE_ERROR); 469 job->set_state(CupsPrintJob::State::STATE_ERROR);
423 NotifyJobStateUpdate(job); 470 NotifyJobStateUpdate(job);
424 } 471 }
425 472
426 jobs_.clear(); 473 jobs_.clear();
427 } 474 }
428 475
429 void CupsPrintJobManagerImpl::CancelJobImpl(const std::string& printer_id, 476 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
430 const int job_id) { 477 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
431 std::unique_ptr<::printing::CupsPrinter> printer =
432 cups_connection_.GetPrinter(printer_id);
433 if (!printer) {
434 LOG(WARNING) << "Printer not found: " << printer_id;
435 return;
436 }
437 478
438 if (!printer->CancelJob(job_id)) {
439 // This is not expected to fail but log it if it does.
440 LOG(WARNING) << "Cancelling job failed. Job may be stuck in queue.";
441 }
442 }
443
444 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
445 switch (job->state()) { 479 switch (job->state()) {
446 case State::STATE_NONE: 480 case State::STATE_NONE:
447 // State does not require notification. 481 // State does not require notification.
448 break; 482 break;
449 case State::STATE_WAITING: 483 case State::STATE_WAITING:
450 NotifyJobUpdated(job); 484 NotifyJobUpdated(job);
451 break; 485 break;
452 case State::STATE_STARTED: 486 case State::STATE_STARTED:
453 NotifyJobStarted(job); 487 NotifyJobStarted(job);
454 break; 488 break;
(...skipping 17 matching lines...) Expand all
472 break; 506 break;
473 } 507 }
474 } 508 }
475 509
476 // static 510 // static
477 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 511 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
478 return new CupsPrintJobManagerImpl(profile); 512 return new CupsPrintJobManagerImpl(profile);
479 } 513 }
480 514
481 } // namespace chromeos 515 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/printing/cups_print_job_manager_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698