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