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 27 namespace extensions { 28 29 using core_api::system_storage::StorageUnitInfo; 30 using content::BrowserThread; 31 using storage_monitor::StorageMonitor; 32 33 namespace system_display = core_api::system_display; 34 namespace system_storage = core_api::system_storage; 35 36 namespace { 37 38 bool IsDisplayChangedEvent(const std::string& event_name) { 39 return event_name == system_display::OnDisplayChanged::kEventName; 40 } 41 42 bool 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. 49 class 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 90 static base::LazyInstance<SystemInfoEventRouter>::Leaky 91 g_system_info_event_router = LAZY_INSTANCE_INITIALIZER; 92 93 // static 94 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() { 95 return g_system_info_event_router.Pointer(); 96 } 97 98 SystemInfoEventRouter::SystemInfoEventRouter() 99 : has_storage_monitor_observer_(false) { 100 } 101 102 SystemInfoEventRouter::~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 110 void 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 132 void 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 161 void 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 170 void 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 181 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) { 182 OnDisplayChanged(); 183 } 184 185 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) { 186 OnDisplayChanged(); 187 } 188 189 void SystemInfoEventRouter::OnDisplayMetricsChanged(const gfx::Display& display, 190 uint32_t metrics) { 191 OnDisplayChanged(); 192 } 193 194 void SystemInfoEventRouter::OnDisplayChanged() { 195 scoped_ptr<base::ListValue> args(new base::ListValue()); 196 DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass()); 197 } 198 199 void SystemInfoEventRouter::DispatchEvent(const std::string& event_name, 200 scoped_ptr<base::ListValue> args) { 201 ExtensionsBrowserClient::Get()->BroadcastEventToRenderers(event_name, 202 args.Pass()); 203 } 204 205 void AddEventListener(const std::string& event_name) { 206 SystemInfoEventRouter::GetInstance()->AddEventListener(event_name); 207 } 208 209 void RemoveEventListener(const std::string& event_name) { 210 SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name); 211 } 212 213 } // namespace 214 215 static base::LazyInstance<BrowserContextKeyedAPIFactory<SystemInfoAPI> > 216 g_factory = LAZY_INSTANCE_INITIALIZER; 217 218 // static 219 BrowserContextKeyedAPIFactory<SystemInfoAPI>* 220 SystemInfoAPI::GetFactoryInstance() { 221 return g_factory.Pointer(); 222 } 223 224 SystemInfoAPI::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 232 SystemInfoAPI::~SystemInfoAPI() { 233 } 234 235 void SystemInfoAPI::Shutdown() { 236 EventRouter::Get(browser_context_)->UnregisterObserver(this); 237 } 238 239 void 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 248 void 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