Home | History | Annotate | Download | only in system_info
      1 // Copyright 2013 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 "chrome/browser/extensions/api/system_info/system_info_api.h"
      6 
      7 #include <set>
      8 
      9 #include "base/bind.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/memory/singleton.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/browser_process.h"
     16 #include "chrome/browser/extensions/api/system_storage/storage_info_provider.h"
     17 #include "chrome/browser/extensions/event_router_forwarder.h"
     18 #include "chrome/common/extensions/api/system_display.h"
     19 #include "chrome/common/extensions/api/system_storage.h"
     20 #include "components/storage_monitor/removable_storage_observer.h"
     21 #include "components/storage_monitor/storage_info.h"
     22 #include "components/storage_monitor/storage_monitor.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "ui/gfx/display_observer.h"
     25 
     26 #if defined(OS_CHROMEOS)
     27 #include "ash/shell.h"
     28 #include "ui/gfx/screen.h"
     29 #endif
     30 
     31 namespace extensions {
     32 
     33 using api::system_storage::StorageUnitInfo;
     34 using content::BrowserThread;
     35 using storage_monitor::StorageMonitor;
     36 
     37 namespace system_display = api::system_display;
     38 namespace system_storage = api::system_storage;
     39 
     40 namespace {
     41 
     42 #if defined(OS_CHROMEOS)
     43 bool IsDisplayChangedEvent(const std::string& event_name) {
     44   return event_name == system_display::OnDisplayChanged::kEventName;
     45 }
     46 #endif
     47 
     48 bool IsSystemStorageEvent(const std::string& event_name) {
     49   return (event_name == system_storage::OnAttached::kEventName ||
     50           event_name == system_storage::OnDetached::kEventName);
     51 }
     52 
     53 // Event router for systemInfo API. It is a singleton instance shared by
     54 // multiple profiles.
     55 class SystemInfoEventRouter : public gfx::DisplayObserver,
     56                               public storage_monitor::RemovableStorageObserver {
     57  public:
     58   static SystemInfoEventRouter* GetInstance();
     59 
     60   SystemInfoEventRouter();
     61   virtual ~SystemInfoEventRouter();
     62 
     63   // Add/remove event listener for the |event_name| event.
     64   void AddEventListener(const std::string& event_name);
     65   void RemoveEventListener(const std::string& event_name);
     66 
     67  private:
     68   // gfx::DisplayObserver:
     69   virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
     70   virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
     71   virtual void OnDisplayMetricsChanged(const gfx::Display& display,
     72                                        uint32_t metrics) OVERRIDE;
     73 
     74   // RemovableStorageObserver implementation.
     75   virtual void OnRemovableStorageAttached(
     76       const storage_monitor::StorageInfo& info) OVERRIDE;
     77   virtual void OnRemovableStorageDetached(
     78       const storage_monitor::StorageInfo& info) OVERRIDE;
     79 
     80   // Called from any thread to dispatch the systemInfo event to all extension
     81   // processes cross multiple profiles.
     82   void DispatchEvent(const std::string& event_name,
     83                      scoped_ptr<base::ListValue> args);
     84 
     85   // Called to dispatch the systemInfo.display.onDisplayChanged event.
     86   void OnDisplayChanged();
     87 
     88   // Used to record the event names being watched.
     89   std::multiset<std::string> watching_event_set_;
     90 
     91   bool has_storage_monitor_observer_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter);
     94 };
     95 
     96 static base::LazyInstance<SystemInfoEventRouter>::Leaky
     97     g_system_info_event_router = LAZY_INSTANCE_INITIALIZER;
     98 
     99 // static
    100 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
    101   return g_system_info_event_router.Pointer();
    102 }
    103 
    104 SystemInfoEventRouter::SystemInfoEventRouter()
    105     : has_storage_monitor_observer_(false) {
    106 }
    107 
    108 SystemInfoEventRouter::~SystemInfoEventRouter() {
    109   if (has_storage_monitor_observer_) {
    110     StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
    111     if (storage_monitor)
    112       storage_monitor->RemoveObserver(this);
    113   }
    114 }
    115 
    116 void SystemInfoEventRouter::AddEventListener(const std::string& event_name) {
    117   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    118 
    119   watching_event_set_.insert(event_name);
    120   if (watching_event_set_.count(event_name) > 1)
    121     return;
    122 
    123   // For system.display event.
    124 #if defined(OS_CHROMEOS)
    125   if (IsDisplayChangedEvent(event_name))
    126     ash::Shell::GetScreen()->AddObserver(this);
    127 #endif
    128 
    129   if (IsSystemStorageEvent(event_name)) {
    130     if (!has_storage_monitor_observer_) {
    131       has_storage_monitor_observer_ = true;
    132       DCHECK(StorageMonitor::GetInstance()->IsInitialized());
    133       StorageMonitor::GetInstance()->AddObserver(this);
    134     }
    135   }
    136 }
    137 
    138 void SystemInfoEventRouter::RemoveEventListener(const std::string& event_name) {
    139   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    140 
    141   std::multiset<std::string>::iterator it =
    142       watching_event_set_.find(event_name);
    143   if (it != watching_event_set_.end()) {
    144     watching_event_set_.erase(it);
    145     if (watching_event_set_.count(event_name) > 0)
    146       return;
    147   }
    148 
    149 #if defined(OS_CHROMEOS)
    150   if (IsDisplayChangedEvent(event_name))
    151     ash::Shell::GetScreen()->RemoveObserver(this);
    152 #endif
    153 
    154   if (IsSystemStorageEvent(event_name)) {
    155     const std::string& other_event_name =
    156         (event_name == system_storage::OnDetached::kEventName) ?
    157             system_storage::OnAttached::kEventName :
    158             system_storage::OnDetached::kEventName;
    159     if (watching_event_set_.count(other_event_name) == 0) {
    160       StorageMonitor::GetInstance()->RemoveObserver(this);
    161       has_storage_monitor_observer_ = false;
    162     }
    163   }
    164 }
    165 
    166 void SystemInfoEventRouter::OnRemovableStorageAttached(
    167     const storage_monitor::StorageInfo& info) {
    168   StorageUnitInfo unit;
    169   systeminfo::BuildStorageUnitInfo(info, &unit);
    170   scoped_ptr<base::ListValue> args(new base::ListValue);
    171   args->Append(unit.ToValue().release());
    172   DispatchEvent(system_storage::OnAttached::kEventName, args.Pass());
    173 }
    174 
    175 void SystemInfoEventRouter::OnRemovableStorageDetached(
    176     const storage_monitor::StorageInfo& info) {
    177   scoped_ptr<base::ListValue> args(new base::ListValue);
    178   std::string transient_id =
    179       StorageMonitor::GetInstance()->GetTransientIdForDeviceId(
    180           info.device_id());
    181   args->AppendString(transient_id);
    182 
    183   DispatchEvent(system_storage::OnDetached::kEventName, args.Pass());
    184 }
    185 
    186 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) {
    187   OnDisplayChanged();
    188 }
    189 
    190 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) {
    191   OnDisplayChanged();
    192 }
    193 
    194 void SystemInfoEventRouter::OnDisplayMetricsChanged(const gfx::Display& display,
    195                                                     uint32_t metrics) {
    196   OnDisplayChanged();
    197 }
    198 
    199 void SystemInfoEventRouter::OnDisplayChanged() {
    200   scoped_ptr<base::ListValue> args(new base::ListValue());
    201   DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
    202 }
    203 
    204 void SystemInfoEventRouter::DispatchEvent(const std::string& event_name,
    205                                           scoped_ptr<base::ListValue> args) {
    206   g_browser_process->extension_event_router_forwarder()->
    207       BroadcastEventToRenderers(event_name, args.Pass(), GURL());
    208 }
    209 
    210 void AddEventListener(const std::string& event_name) {
    211   SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
    212 }
    213 
    214 void RemoveEventListener(const std::string& event_name) {
    215   SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name);
    216 }
    217 
    218 }  // namespace
    219 
    220 static base::LazyInstance<BrowserContextKeyedAPIFactory<SystemInfoAPI> >
    221     g_factory = LAZY_INSTANCE_INITIALIZER;
    222 
    223 // static
    224 BrowserContextKeyedAPIFactory<SystemInfoAPI>*
    225 SystemInfoAPI::GetFactoryInstance() {
    226   return g_factory.Pointer();
    227 }
    228 
    229 SystemInfoAPI::SystemInfoAPI(content::BrowserContext* context)
    230     : browser_context_(context) {
    231   EventRouter* router = EventRouter::Get(browser_context_);
    232   router->RegisterObserver(this, system_storage::OnAttached::kEventName);
    233   router->RegisterObserver(this, system_storage::OnDetached::kEventName);
    234   router->RegisterObserver(this, system_display::OnDisplayChanged::kEventName);
    235 }
    236 
    237 SystemInfoAPI::~SystemInfoAPI() {
    238 }
    239 
    240 void SystemInfoAPI::Shutdown() {
    241   EventRouter::Get(browser_context_)->UnregisterObserver(this);
    242 }
    243 
    244 void SystemInfoAPI::OnListenerAdded(const EventListenerInfo& details) {
    245   if (IsSystemStorageEvent(details.event_name)) {
    246     StorageMonitor::GetInstance()->EnsureInitialized(
    247         base::Bind(&AddEventListener, details.event_name));
    248   } else {
    249     AddEventListener(details.event_name);
    250   }
    251 }
    252 
    253 void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo& details) {
    254   if (IsSystemStorageEvent(details.event_name)) {
    255     StorageMonitor::GetInstance()->EnsureInitialized(
    256         base::Bind(&RemoveEventListener, details.event_name));
    257   } else {
    258     RemoveEventListener(details.event_name);
    259   }
    260 }
    261 
    262 }  // namespace extensions
    263