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

Side by Side Diff: chrome/browser/chromeos/printer_detector/cups_printer_detector.cc

Issue 2945653002: Remove the legacy (extension-notifier) usb printer detector. Rename the remaining printerdetector … (Closed)
Patch Set: Remove the legacy (extension-notifier) usb printer detector. Rename the remaining printerdetector … Created 3 years, 6 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/observer_list_threadsafe.h"
16 #include "base/scoped_observer.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/lock.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chromeos/printer_detector/printer_detector.h"
22 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
23 #include "chrome/browser/chromeos/printing/printer_configurer.h"
24 #include "chrome/browser/chromeos/printing/printers_manager_factory.h"
25 #include "chrome/browser/chromeos/printing/usb_printer_util.h"
26 #include "chrome/browser/chromeos/profiles/profile_helper.h"
27 #include "chromeos/dbus/dbus_thread_manager.h"
28 #include "chromeos/dbus/debug_daemon_client.h"
29 #include "chromeos/printing/ppd_provider.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "device/base/device_client.h"
32 #include "device/usb/usb_device.h"
33 #include "device/usb/usb_device_filter.h"
34 #include "device/usb/usb_service.h"
35
36 namespace chromeos {
37 namespace {
38
39 using printing::PpdProvider;
40
41 // Aggregates the information needed for printer setup so it's easier to pass it
42 // around.
43 struct SetUpPrinterData {
44 // The configurer running the SetUpPrinter call.
45 std::unique_ptr<PrinterConfigurer> configurer;
46
47 // The printer being set up.
48 std::unique_ptr<Printer> printer;
49
50 // The usb device causing this setup flow.
51 scoped_refptr<device::UsbDevice> device;
52
53 // True if this printer is one that the user doesn't already have a
54 // configuration for.
55 bool is_new;
56
57 // True if this was a printer that was plugged in during the session, false if
58 // it was already plugged in when the session started.
59 bool hotplugged;
60 };
61
62 // Given a usb device, guesses the make and model for a driver lookup.
63 //
64 // TODO(justincarlson): Possibly go deeper and query the IEEE1284 fields
65 // for make and model if we determine those are more likely to contain
66 // what we want.
67 std::string GuessEffectiveMakeAndModel(const device::UsbDevice& device) {
68 return base::UTF16ToUTF8(device.manufacturer_string()) + " " +
69 base::UTF16ToUTF8(device.product_string());
70 }
71
72 // The PrinterDetector that drives the flow for setting up a USB printer to use
73 // CUPS backend.
74 class CupsPrinterDetectorImpl : public PrinterDetector,
75 public device::UsbService::Observer {
76 public:
77 explicit CupsPrinterDetectorImpl(Profile* profile)
78 : profile_(profile),
79 usb_observer_(this),
80 observer_list_(
81 new base::ObserverListThreadSafe<PrinterDetector::Observer>),
82 weak_ptr_factory_(this) {
83 device::UsbService* usb_service =
84 device::DeviceClient::Get()->GetUsbService();
85 if (usb_service) {
86 usb_observer_.Add(usb_service);
87 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices,
88 weak_ptr_factory_.GetWeakPtr()));
89 }
90 }
91 ~CupsPrinterDetectorImpl() override = default;
92
93 // PrinterDetector interface function.
94 void AddObserver(PrinterDetector::Observer* observer) override {
95 observer_list_->AddObserver(observer);
96 }
97
98 // PrinterDetector interface function.
99 void RemoveObserver(PrinterDetector::Observer* observer) override {
100 observer_list_->RemoveObserver(observer);
101 }
102
103 // PrinterDetector interface function.
104 std::vector<Printer> GetPrinters() override {
105 base::AutoLock auto_lock(pp_lock_);
106 return GetPrintersLocked();
107 }
108
109 private:
110 std::vector<Printer> GetPrintersLocked() {
111 pp_lock_.AssertAcquired();
112 std::vector<Printer> printers;
113 printers.reserve(present_printers_.size());
114 for (const auto& entry : present_printers_) {
115 printers.push_back(*entry.second);
116 }
117 return printers;
118 }
119
120 // Callback for initial enumeration of usb devices.
121 void OnGetDevices(
122 const std::vector<scoped_refptr<device::UsbDevice>>& devices) {
123 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
124 for (const auto& device : devices) {
125 MaybeSetUpDevice(device, false);
126 }
127 }
128
129 // UsbService::observer override.
130 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override {
131 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
132 MaybeSetUpDevice(device, true);
133 }
134
135 // UsbService::observer override.
136 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
138 if (!UsbDeviceIsPrinter(*device)) {
139 return;
140 }
141
142 base::AutoLock auto_lock(pp_lock_);
143 if (base::ContainsKey(present_printers_, device->guid())) {
144 present_printers_.erase(device->guid());
145 auto printers = GetPrintersLocked();
146 // We already have pp_lock_, so need to call the pre-locked version of
147 // GetPrinters to prevent deadlock.
148 observer_list_->Notify(
149 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged,
150 GetPrintersLocked());
151 } else {
152 // If the device has been removed but it's not in present_printers_, it
153 // must still be in the setup flow.
154 deferred_printer_removals_.insert(device->guid());
155 }
156 }
157
158 // If this device is a printer and we haven't already tried to set it up,
159 // starts the process of setting the printer up. |hotplugged|
160 // should be true if this was plugged in during the session.
161 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device,
162 bool hotplugged) {
163 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
164
165 if (!UsbDeviceIsPrinter(*device)) {
166 return;
167 }
168
169 // If we got this far, we want to try to auto-configure this printer.
170 auto data = base::MakeUnique<SetUpPrinterData>();
171 data->configurer = PrinterConfigurer::Create(profile_);
172 data->device = device;
173 data->hotplugged = hotplugged;
174
175 data->printer = UsbDeviceToPrinter(*device);
176 if (data->printer == nullptr) {
177 // We've failed to understand this printer device, an error will already
178 // have been logged, so just bail.
179 return;
180 }
181
182 // If the user already has a configuration for this device, substitute that
183 // one for the one we generated automatically and skip the parts where we
184 // try to automagically figure out the driver.
185 std::unique_ptr<Printer> existing_printer_configuration =
186 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter(
187 data->printer->id());
188 if (existing_printer_configuration != nullptr) {
189 data->is_new = false;
190 data->printer = std::move(existing_printer_configuration);
191 OnPrinterResolved(std::move(data));
192 return;
193 }
194
195 // It's not a device we have configured previously.
196 //
197 // TODO(justincarlson): Add a notification that we are attempting to set up
198 // this printer at this point.
199 data->is_new = true;
200
201 // Look for an exact match based on USB ids.
202 scoped_refptr<PpdProvider> ppd_provider =
203 printing::CreateProvider(profile_);
204 ppd_provider->ResolveUsbIds(
205 device->vendor_id(), device->product_id(),
206 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone,
207 weak_ptr_factory_.GetWeakPtr(), ppd_provider,
208 base::Passed(std::move(data))));
209 }
210
211 void OnPrinterResolved(std::unique_ptr<SetUpPrinterData> data) {
212 // |data| will be invalidated by the move below, so we have to latch it
213 // before the call.
214 SetUpPrinterData* data_ptr = data.get();
215 data_ptr->configurer->SetUpPrinter(
216 *(data_ptr->printer),
217 base::Bind(&CupsPrinterDetectorImpl::SetUpPrinterDone,
218 weak_ptr_factory_.GetWeakPtr(),
219 base::Passed(std::move(data))));
220 }
221
222 // Called when the query for a driver based on usb ids completes.
223 //
224 // Note |provider| is not used in this function, it's just passed along to
225 // keep it alive during the USB resolution.
226 void ResolveUsbIdsDone(scoped_refptr<PpdProvider> provider,
227 std::unique_ptr<SetUpPrinterData> data,
228 PpdProvider::CallbackResultCode result,
229 const std::string& effective_make_and_model) {
230 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
231 if (result == PpdProvider::SUCCESS) {
232 // Got something based on usb ids. Go with it.
233 data->printer->mutable_ppd_reference()->effective_make_and_model =
234 effective_make_and_model;
235 } else {
236 // Couldn't figure this printer out based on usb ids, fall back to
237 // guessing the make/model string from what the USB system reports.
238 //
239 // TODO(justincarlson): Consider adding a mechanism for aggregating data
240 // about which usb devices are in the wild but unsupported?
241 data->printer->mutable_ppd_reference()->effective_make_and_model =
242 GuessEffectiveMakeAndModel(*data->device);
243 }
244 OnPrinterResolved(std::move(data));
245 }
246
247 // Called with the result of asking to have a printer configured for CUPS. If
248 // |printer_to_register| is non-null and we successfully configured, then the
249 // printer is registered with the printers manager.
250 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data,
251 PrinterSetupResult result) {
252 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
253 if (result == PrinterSetupResult::kSuccess) {
254 if (data->is_new) {
255 // We aren't done with data->printer yet, so we have to copy it instead
256 // of moving it.
257 auto printer_copy = base::MakeUnique<Printer>(*data->printer);
258 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
259 std::move(printer_copy));
260 }
261 // TODO(justincarlson): If the device was hotplugged, pop a timed
262 // notification that says the printer is now available for printing.
263 }
264 // TODO(justincarlson): If this doesn't succeed, pop a notification that
265 // tells the user automatic setup failed and offers to open the CUPS printer
266 // configuration settings.
267
268 if (base::ContainsKey(deferred_printer_removals_, data->device->guid())) {
269 // The device was removed before we finished the flow, so just don't add
270 // it to present_printers_;
271 deferred_printer_removals_.erase(data->device->guid());
272 } else {
273 base::AutoLock auto_lock(pp_lock_);
274 present_printers_.emplace(data->device->guid(), std::move(data->printer));
275 observer_list_->Notify(
276 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged,
277 GetPrintersLocked());
278 }
279 }
280
281 void SetNotificationUIManagerForTesting(
282 NotificationUIManager* manager) override {
283 LOG(FATAL) << "Not implemented for CUPS";
284 }
285
286 // Map from USB GUID to Printer that we have detected as being currently
287 // plugged in and have finished processing. Note present_printers_ may be
288 // accessed from multiple threads, so is protected by pp_lock_.
289 std::map<std::string, std::unique_ptr<Printer>> present_printers_;
290 base::Lock pp_lock_;
291
292 // If the usb device is removed before we've finished processing it, we'll
293 // defer the cleanup until the setup flow finishes. This is the set of
294 // guids which have been removed before the flow finished.
295 std::set<std::string> deferred_printer_removals_;
296
297 Profile* profile_;
298 ScopedObserver<device::UsbService, device::UsbService::Observer>
299 usb_observer_;
300 scoped_refptr<base::ObserverListThreadSafe<PrinterDetector::Observer>>
301 observer_list_;
302 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_;
303 };
304
305 } // namespace
306
307 // Nop base class implementation of GetPrinters(). Because this is non-empty we
308 // have to define it out-of-line.
309 std::vector<Printer> PrinterDetector::GetPrinters() {
310 return std::vector<Printer>();
311 }
312
313 // static
314 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) {
315 return base::MakeUnique<CupsPrinterDetectorImpl>(profile);
316 }
317
318 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/BUILD.gn ('k') | chrome/browser/chromeos/printer_detector/legacy_printer_detector.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698