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(&registrar_), 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) {