• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
IsDisplayChangedEvent(const std::string & event_name)43 bool IsDisplayChangedEvent(const std::string& event_name) {
44   return event_name == system_display::OnDisplayChanged::kEventName;
45 }
46 #endif
47 
IsSystemStorageEvent(const std::string & event_name)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
GetInstance()100 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
101   return g_system_info_event_router.Pointer();
102 }
103 
SystemInfoEventRouter()104 SystemInfoEventRouter::SystemInfoEventRouter()
105     : has_storage_monitor_observer_(false) {
106 }
107 
~SystemInfoEventRouter()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 
AddEventListener(const std::string & event_name)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 
RemoveEventListener(const std::string & event_name)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 
OnRemovableStorageAttached(const storage_monitor::StorageInfo & info)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 
OnRemovableStorageDetached(const storage_monitor::StorageInfo & info)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 
OnDisplayAdded(const gfx::Display & new_display)186 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) {
187   OnDisplayChanged();
188 }
189 
OnDisplayRemoved(const gfx::Display & old_display)190 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) {
191   OnDisplayChanged();
192 }
193 
OnDisplayMetricsChanged(const gfx::Display & display,uint32_t metrics)194 void SystemInfoEventRouter::OnDisplayMetricsChanged(const gfx::Display& display,
195                                                     uint32_t metrics) {
196   OnDisplayChanged();
197 }
198 
OnDisplayChanged()199 void SystemInfoEventRouter::OnDisplayChanged() {
200   scoped_ptr<base::ListValue> args(new base::ListValue());
201   DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
202 }
203 
DispatchEvent(const std::string & event_name,scoped_ptr<base::ListValue> args)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 
AddEventListener(const std::string & event_name)210 void AddEventListener(const std::string& event_name) {
211   SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
212 }
213 
RemoveEventListener(const std::string & event_name)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>*
GetFactoryInstance()225 SystemInfoAPI::GetFactoryInstance() {
226   return g_factory.Pointer();
227 }
228 
SystemInfoAPI(content::BrowserContext * context)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 
~SystemInfoAPI()237 SystemInfoAPI::~SystemInfoAPI() {
238 }
239 
Shutdown()240 void SystemInfoAPI::Shutdown() {
241   EventRouter::Get(browser_context_)->UnregisterObserver(this);
242 }
243 
OnListenerAdded(const EventListenerInfo & details)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 
OnListenerRemoved(const EventListenerInfo & details)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