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