Remove NotificationService usage from UsbService.
This changes UsbService to be a LazyInstance that destroys
itself along with the FILE thread message loop, rather than
observing NOTIFICATION_APP_TERMINATING.
This has two benefits: It kills one more consumer of
NotificationService, and it removes the only external
Chrome dependency from //chrome/browser/usb.
BUG=361000
[email protected]
Review URL: https://codereview.chromium.org/234813007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263556 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/usb/usb_service.cc b/chrome/browser/usb/usb_service.cc
index 221ccbb..5916457 100644
--- a/chrome/browser/usb/usb_service.cc
+++ b/chrome/browser/usb/usb_service.cc
@@ -7,110 +7,49 @@
#include <set>
#include <vector>
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
+#include "base/lazy_instance.h"
#include "base/stl_util.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/usb/usb_context.h"
#include "chrome/browser/usb/usb_device.h"
-#include "chrome/browser/usb/usb_device_handle.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
#include "third_party/libusb/src/libusb/libusb.h"
-namespace content {
-
-class NotificationDetails;
-class NotificationSource;
-
-} // namespace content
-
-using content::BrowserThread;
-using std::vector;
-
namespace {
-// This is the one and only instance of UsbService. The reason not to use
-// Singleton is: 1. Singleton focuses on solving race conditions and at-exit
-// deletion, none of them are needed here, and 2. Singleton does not provide
-// a way to clear the pointer after the instance being destroyed.
-UsbService* g_usb_service_instance = NULL;
-bool g_usb_service_instance_destroyed = false;
-
-class ExitObserver : public content::NotificationObserver {
- public:
- ExitObserver() {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&content::NotificationRegistrar::Add,
- base::Unretained(®istrar_), this,
- chrome::NOTIFICATION_APP_TERMINATING,
- content::NotificationService::AllSources()));
- }
-
- private:
- // content::NotificationObserver
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE {
- if (type == chrome::NOTIFICATION_APP_TERMINATING) {
- BrowserThread::DeleteSoon(BrowserThread::FILE,
- FROM_HERE,
- g_usb_service_instance);
- delete this;
- }
- }
- content::NotificationRegistrar registrar_;
-};
+base::LazyInstance<scoped_ptr<UsbService> >::Leaky g_usb_service_instance =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace
-UsbService::UsbService(PlatformUsbContext context)
- : context_(new UsbContext(context)),
- next_unique_id_(0) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-}
-
-UsbService::~UsbService() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Prevents creating a new UsbService.
- g_usb_service_instance_destroyed = true;
- g_usb_service_instance = NULL;
-
- for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
- it->second->OnDisconnect();
- }
-}
-
+// static
UsbService* UsbService::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (g_usb_service_instance_destroyed)
- return NULL;
-
- if (!g_usb_service_instance) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+ UsbService* instance = g_usb_service_instance.Get().get();
+ if (!instance) {
PlatformUsbContext context = NULL;
if (libusb_init(&context) != LIBUSB_SUCCESS)
return NULL;
if (!context)
return NULL;
- g_usb_service_instance = new UsbService(context);
-
- // Will be deleted upon NOTIFICATION_APP_TERMINATING.
- new ExitObserver();
+ instance = new UsbService(context);
+ g_usb_service_instance.Get().reset(instance);
}
+ return instance;
+}
- return g_usb_service_instance;
+scoped_refptr<UsbDevice> UsbService::GetDeviceById(uint32 unique_id) {
+ DCHECK(CalledOnValidThread());
+ RefreshDevices();
+ for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if (it->second->unique_id() == unique_id)
+ return it->second;
+ }
+ return NULL;
}
void UsbService::GetDevices(std::vector<scoped_refptr<UsbDevice> >* devices) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(CalledOnValidThread());
STLClearObject(devices);
RefreshDevices();
@@ -119,25 +58,32 @@
}
}
-scoped_refptr<UsbDevice> UsbService::GetDeviceById(uint32 unique_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- RefreshDevices();
+void UsbService::WillDestroyCurrentMessageLoop() {
+ DCHECK(CalledOnValidThread());
+ g_usb_service_instance.Get().reset(NULL);
+}
+UsbService::UsbService(PlatformUsbContext context)
+ : context_(new UsbContext(context)), next_unique_id_(0) {
+ base::MessageLoop::current()->AddDestructionObserver(this);
+}
+
+UsbService::~UsbService() {
+ base::MessageLoop::current()->RemoveDestructionObserver(this);
for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
- if (it->second->unique_id() == unique_id) return it->second;
+ it->second->OnDisconnect();
}
- return NULL;
}
void UsbService::RefreshDevices() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(CalledOnValidThread());
libusb_device** platform_devices = NULL;
const ssize_t device_count =
libusb_get_device_list(context_->context(), &platform_devices);
std::set<UsbDevice*> connected_devices;
- vector<PlatformUsbDevice> disconnected_devices;
+ std::vector<PlatformUsbDevice> disconnected_devices;
// Populates new devices.
for (ssize_t i = 0; i < device_count; ++i) {