Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <stdint.h> | 5 #include <stdint.h> |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/observer_list_threadsafe.h" | |
| 15 #include "base/scoped_observer.h" | 16 #include "base/scoped_observer.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/synchronization/lock.h" | |
| 19 #include "base/threading/sequenced_task_runner_handle.h" | |
| 17 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 18 #include "chrome/browser/chromeos/printer_detector/printer_detector.h" | 21 #include "chrome/browser/chromeos/printer_detector/printer_detector.h" |
| 19 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" | 22 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" |
| 20 #include "chrome/browser/chromeos/printing/printer_configurer.h" | 23 #include "chrome/browser/chromeos/printing/printer_configurer.h" |
| 21 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" | 24 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" |
| 22 #include "chrome/browser/chromeos/printing/usb_printer_util.h" | 25 #include "chrome/browser/chromeos/printing/usb_printer_util.h" |
| 23 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 26 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 24 #include "chromeos/dbus/dbus_thread_manager.h" | 27 #include "chromeos/dbus/dbus_thread_manager.h" |
| 25 #include "chromeos/dbus/debug_daemon_client.h" | 28 #include "chromeos/dbus/debug_daemon_client.h" |
| 26 #include "chromeos/printing/ppd_provider.h" | 29 #include "chromeos/printing/ppd_provider.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 return base::UTF16ToUTF8(device.manufacturer_string()) + " " + | 68 return base::UTF16ToUTF8(device.manufacturer_string()) + " " + |
| 66 base::UTF16ToUTF8(device.product_string()); | 69 base::UTF16ToUTF8(device.product_string()); |
| 67 } | 70 } |
| 68 | 71 |
| 69 // The PrinterDetector that drives the flow for setting up a USB printer to use | 72 // The PrinterDetector that drives the flow for setting up a USB printer to use |
| 70 // CUPS backend. | 73 // CUPS backend. |
| 71 class CupsPrinterDetectorImpl : public PrinterDetector, | 74 class CupsPrinterDetectorImpl : public PrinterDetector, |
| 72 public device::UsbService::Observer { | 75 public device::UsbService::Observer { |
| 73 public: | 76 public: |
| 74 explicit CupsPrinterDetectorImpl(Profile* profile) | 77 explicit CupsPrinterDetectorImpl(Profile* profile) |
| 75 : profile_(profile), observer_(this), weak_ptr_factory_(this) { | 78 : profile_(profile), |
| 79 usb_observer_(this), | |
| 80 observer_list_( | |
| 81 new base::ObserverListThreadSafe<PrinterDetector::Observer>), | |
| 82 weak_ptr_factory_(this) { | |
| 76 device::UsbService* usb_service = | 83 device::UsbService* usb_service = |
| 77 device::DeviceClient::Get()->GetUsbService(); | 84 device::DeviceClient::Get()->GetUsbService(); |
| 78 if (usb_service) { | 85 if (usb_service) { |
| 79 observer_.Add(usb_service); | 86 usb_observer_.Add(usb_service); |
| 80 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices, | 87 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices, |
| 81 weak_ptr_factory_.GetWeakPtr())); | 88 weak_ptr_factory_.GetWeakPtr())); |
| 82 } | 89 } |
| 83 } | 90 } |
| 84 ~CupsPrinterDetectorImpl() override = default; | 91 ~CupsPrinterDetectorImpl() override = default; |
| 85 | 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 auto ret = GetPrintersLocked(); | |
| 107 return ret; | |
| 108 } | |
| 109 | |
| 86 private: | 110 private: |
| 111 std::vector<Printer> GetPrintersLocked() { | |
| 112 pp_lock_.AssertAcquired(); | |
| 113 std::vector<Printer> printers; | |
| 114 printers.reserve(present_printers_.size()); | |
| 115 for (const auto& entry : present_printers_) { | |
| 116 printers.push_back(*entry.second); | |
| 117 } | |
| 118 return printers; | |
| 119 } | |
| 120 | |
| 87 // Callback for initial enumeration of usb devices. | 121 // Callback for initial enumeration of usb devices. |
| 88 void OnGetDevices( | 122 void OnGetDevices( |
| 89 const std::vector<scoped_refptr<device::UsbDevice>>& devices) { | 123 const std::vector<scoped_refptr<device::UsbDevice>>& devices) { |
| 90 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 124 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 91 for (const auto& device : devices) { | 125 for (const auto& device : devices) { |
| 92 MaybeSetUpDevice(device, false); | 126 MaybeSetUpDevice(device, false); |
| 93 } | 127 } |
| 94 } | 128 } |
| 95 | 129 |
| 96 // UsbService::observer override. | 130 // UsbService::observer override. |
| 97 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { | 131 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { |
| 98 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 132 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 99 MaybeSetUpDevice(device, true); | 133 MaybeSetUpDevice(device, true); |
| 100 } | 134 } |
| 101 | 135 |
| 102 // UsbService::observer override. | 136 // UsbService::observer override. |
| 103 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override { | 137 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override { |
| 104 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 105 if (!UsbDeviceIsPrinter(*device)) { | 139 if (!UsbDeviceIsPrinter(*device)) { |
| 106 return; | 140 return; |
| 107 } | 141 } |
| 108 known_printers_.erase(device->guid()); | |
| 109 // TODO(justincarlson): Update failed printers. | |
| 110 } | |
| 111 | 142 |
| 112 // Returns the existing printer using this URI, if one exists, or | 143 base::AutoLock auto_lock(pp_lock_); |
| 113 // null otherwise. | 144 if (base::ContainsKey(present_printers_, device->guid())) { |
| 114 std::unique_ptr<Printer> FindExistingPrinter(const std::string& uri) { | 145 present_printers_.erase(device->guid()); |
| 115 // TODO(justincarlson): add a GetPrinterByURI to PrintersManager. | 146 observer_list_->Notify( |
| 116 // https://crbug.com/700602 | 147 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged, |
|
skau
2017/03/31 17:50:11
Add a note to this method that calling GetPrinters
Carlson
2017/03/31 18:20:06
Done. (I really, really wish we had lock annotati
| |
| 117 auto existing_printers = | 148 GetPrintersLocked()); |
| 118 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinters(); | 149 } else { |
| 119 for (std::unique_ptr<Printer>& printer : existing_printers) { | 150 // If the device has been removed but it's not in present_printers_, it |
| 120 if (printer->uri() == uri) { | 151 // must still be in the setup flow. |
| 121 // Found a match, so use the existing configuration. | 152 deferred_printer_removals_.insert(device->guid()); |
| 122 return std::move(printer); | |
| 123 } | |
| 124 } | 153 } |
| 125 return nullptr; | |
| 126 } | 154 } |
| 127 | 155 |
| 128 // If this device is a printer and we haven't already tried to set it up, | 156 // If this device is a printer and we haven't already tried to set it up, |
| 129 // starts the process of setting the printer up. |hotplugged| | 157 // starts the process of setting the printer up. |hotplugged| |
| 130 // should be true if this was plugged in during the session. | 158 // should be true if this was plugged in during the session. |
| 131 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device, | 159 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device, |
| 132 bool hotplugged) { | 160 bool hotplugged) { |
| 133 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 161 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 134 | 162 |
| 135 if (!UsbDeviceIsPrinter(*device) || | 163 if (!UsbDeviceIsPrinter(*device)) { |
| 136 base::ContainsKey(known_printers_, device->guid())) { | |
| 137 return; | 164 return; |
| 138 } | 165 } |
| 139 known_printers_.insert(device->guid()); | |
| 140 | 166 |
| 167 // If we got this far, we want to try to auto-configure this printer. | |
| 141 auto data = base::MakeUnique<SetUpPrinterData>(); | 168 auto data = base::MakeUnique<SetUpPrinterData>(); |
| 142 data->configurer = PrinterConfigurer::Create(profile_); | 169 data->configurer = PrinterConfigurer::Create(profile_); |
| 143 data->device = device; | 170 data->device = device; |
| 144 data->hotplugged = hotplugged; | 171 data->hotplugged = hotplugged; |
| 145 | 172 |
| 146 data->printer = FindExistingPrinter(UsbPrinterUri(*device)); | 173 data->printer = UsbDeviceToPrinter(*device); |
| 147 if (data->printer != nullptr) { | 174 if (data->printer == nullptr) { |
| 175 // We've failed to understand this printer device, an error will already | |
| 176 // have been logged, so just bail. | |
| 177 return; | |
| 178 } | |
| 179 | |
| 180 // If the user already has a configuration for this device, substitute that | |
| 181 // one for the one we generated automatically and skip the parts where we | |
| 182 // try to automagically figure out the driver. | |
| 183 auto existing_printer_configuration = | |
| 184 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinter( | |
| 185 data->printer->id()); | |
| 186 if (existing_printer_configuration != nullptr) { | |
| 148 data->is_new = false; | 187 data->is_new = false; |
| 188 data->printer = std::move(existing_printer_configuration); | |
| 149 OnPrinterResolved(std::move(data)); | 189 OnPrinterResolved(std::move(data)); |
| 150 return; | 190 return; |
| 151 } | 191 } |
| 152 | 192 |
| 153 // It's not a device we have configured previously. | 193 // It's not a device we have configured previously. |
| 154 // | 194 // |
| 155 // TODO(justincarlson): Add a notification that we are attempting to set up | 195 // TODO(justincarlson): Add a notification that we are attempting to set up |
| 156 // this printer at this point. | 196 // this printer at this point. |
| 157 data->is_new = true; | 197 data->is_new = true; |
| 158 data->printer = UsbDeviceToPrinter(*device); | |
| 159 if (data->printer == nullptr) { | |
| 160 return; | |
| 161 } | |
| 162 | 198 |
| 163 // Look for an exact match based on USB ids. | 199 // Look for an exact match based on USB ids. |
| 164 scoped_refptr<PpdProvider> ppd_provider = | 200 scoped_refptr<PpdProvider> ppd_provider = |
| 165 printing::CreateProvider(profile_); | 201 printing::CreateProvider(profile_); |
| 166 ppd_provider->ResolveUsbIds( | 202 ppd_provider->ResolveUsbIds( |
| 167 device->vendor_id(), device->product_id(), | 203 device->vendor_id(), device->product_id(), |
| 168 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone, | 204 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone, |
| 169 weak_ptr_factory_.GetWeakPtr(), ppd_provider, | 205 weak_ptr_factory_.GetWeakPtr(), ppd_provider, |
| 170 base::Passed(std::move(data)))); | 206 base::Passed(std::move(data)))); |
| 171 } | 207 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 } | 243 } |
| 208 | 244 |
| 209 // Called with the result of asking to have a printer configured for CUPS. If | 245 // Called with the result of asking to have a printer configured for CUPS. If |
| 210 // |printer_to_register| is non-null and we successfully configured, then the | 246 // |printer_to_register| is non-null and we successfully configured, then the |
| 211 // printer is registered with the printers manager. | 247 // printer is registered with the printers manager. |
| 212 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data, | 248 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data, |
| 213 PrinterSetupResult result) { | 249 PrinterSetupResult result) { |
| 214 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 250 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 215 if (result == PrinterSetupResult::SUCCESS) { | 251 if (result == PrinterSetupResult::SUCCESS) { |
| 216 if (data->is_new) { | 252 if (data->is_new) { |
| 253 // We aren't done with data->printer yet, so we have to copy it instead | |
| 254 // of moving it. | |
| 255 auto printer_copy = base::MakeUnique<Printer>(); | |
| 256 *printer_copy = *data->printer; | |
| 217 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter( | 257 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter( |
| 218 std::move(data->printer)); | 258 std::move(printer_copy)); |
| 219 } | 259 } |
| 220 // TODO(justincarlson): If the device was hotplugged, pop a timed | 260 // TODO(justincarlson): If the device was hotplugged, pop a timed |
| 221 // notification that says the printer is now available for printing. | 261 // notification that says the printer is now available for printing. |
| 222 } | 262 } |
| 223 // TODO(justincarlson): If this doesn't succeed, Pop a notification that | 263 // TODO(justincarlson): If this doesn't succeed, pop a notification that |
| 224 // tells the user automatic setup failed and offers to open the CUPS printer | 264 // tells the user automatic setup failed and offers to open the CUPS printer |
| 225 // configuration settings. | 265 // configuration settings. |
| 226 // | 266 |
| 227 // TODO(justincarlson): If this doesn't succeed, Update the list of printers | 267 if (base::ContainsKey(deferred_printer_removals_, data->device->guid())) { |
| 228 // that failed to set up. | 268 // The device was removed before we finished the flow, so just don't add |
| 269 // it to present_printers_; | |
| 270 deferred_printer_removals_.erase(data->device->guid()); | |
| 271 } else { | |
| 272 base::AutoLock auto_lock(pp_lock_); | |
| 273 present_printers_.emplace(data->device->guid(), std::move(data->printer)); | |
| 274 observer_list_->Notify( | |
| 275 FROM_HERE, &PrinterDetector::Observer::OnAvailableUsbPrintersChanged, | |
| 276 GetPrintersLocked()); | |
| 277 } | |
| 229 } | 278 } |
| 230 | 279 |
| 231 void SetNotificationUIManagerForTesting( | 280 void SetNotificationUIManagerForTesting( |
| 232 NotificationUIManager* manager) override { | 281 NotificationUIManager* manager) override { |
| 233 LOG(FATAL) << "Not implemented for CUPS"; | 282 LOG(FATAL) << "Not implemented for CUPS"; |
| 234 } | 283 } |
| 235 | 284 |
| 236 // USB GUIDs of printers we've already dealt with. There's an inherent race | 285 // Map from USB GUID to Printer that we have detected as being currently |
| 237 // between initially querying all usb devices and receiving a notification | 286 // plugged in and have finished processing. Note present_printers_ may be |
| 238 // about a new device, so this set lets us guarantee that we handle a given | 287 // accessed from multiple threads, so is protected by pp_lock_. |
| 239 // printer exactly once. | 288 std::map<std::string, std::unique_ptr<Printer>> present_printers_; |
| 240 std::set<std::string> known_printers_; | 289 base::Lock pp_lock_; |
| 290 | |
| 291 // If the usb device is removed before we've finished processing it, we'll | |
| 292 // defer the cleanup until the setup flow finishes. This is the set of | |
| 293 // guids which have been removed before the flow finished. | |
| 294 std::set<std::string> deferred_printer_removals_; | |
| 241 | 295 |
| 242 Profile* profile_; | 296 Profile* profile_; |
| 243 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; | 297 ScopedObserver<device::UsbService, device::UsbService::Observer> |
| 298 usb_observer_; | |
| 299 scoped_refptr<base::ObserverListThreadSafe<PrinterDetector::Observer>> | |
| 300 observer_list_; | |
| 244 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; | 301 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; |
| 245 }; | 302 }; |
| 246 | 303 |
| 247 } // namespace | 304 } // namespace |
| 248 | 305 |
| 249 // static | 306 // static |
| 250 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { | 307 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { |
| 251 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); | 308 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); |
| 252 } | 309 } |
| 253 | 310 |
| 254 } // namespace chromeos | 311 } // namespace chromeos |
| OLD | NEW |