OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_settings_frontend.h" | 5 #include "chrome/browser/extensions/extension_settings_frontend.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
| 9 #include "chrome/browser/extensions/extension_event_names.h" |
| 10 #include "chrome/browser/extensions/extension_event_router.h" |
| 11 #include "chrome/browser/extensions/extension_service.h" |
9 #include "chrome/browser/extensions/extension_settings_backend.h" | 12 #include "chrome/browser/extensions/extension_settings_backend.h" |
| 13 #include "chrome/browser/profiles/profile.h" |
10 #include "content/browser/browser_thread.h" | 14 #include "content/browser/browser_thread.h" |
11 | 15 |
12 ExtensionSettingsFrontend::ExtensionSettingsFrontend( | 16 // Observer which sends events to a target profile iff the profile isn't the |
13 const FilePath& base_path) | 17 // originating profile for the event. |
14 : core_(new ExtensionSettingsFrontend::Core()) { | 18 class ExtensionSettingsFrontend::DefaultObserver |
| 19 : public ExtensionSettingsObserver { |
| 20 public: |
| 21 explicit DefaultObserver(Profile* target_profile) |
| 22 : target_profile_(target_profile) {} |
| 23 |
| 24 virtual ~DefaultObserver() {} |
| 25 |
| 26 virtual void OnSettingsChanged( |
| 27 Profile* origin_profile, |
| 28 const std::string& extension_id, |
| 29 const std::string& event_json) OVERRIDE { |
| 30 if (origin_profile != target_profile_) { |
| 31 target_profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
| 32 extension_id, |
| 33 extension_event_names::kOnSettingsChanged, |
| 34 event_json, |
| 35 target_profile_, |
| 36 GURL()); |
| 37 } |
| 38 } |
| 39 |
| 40 private: |
| 41 Profile* target_profile_; |
| 42 }; |
| 43 |
| 44 // Ref-counted container for the ExtensionSettingsBackend object. |
| 45 class ExtensionSettingsFrontend::Core |
| 46 : public base::RefCountedThreadSafe<Core> { |
| 47 public: |
| 48 // Constructed on UI thread. |
| 49 explicit Core( |
| 50 const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >& |
| 51 observers) : observers_(observers), backend_(NULL) { |
| 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 53 } |
| 54 |
| 55 // Does any FILE thread specific initialization, such as construction of |
| 56 // |backend_|. Must be called before any call to |
| 57 // RunWithBackendOnFileThread(). |
| 58 void InitOnFileThread(const FilePath& base_path) { |
| 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 60 DCHECK(!backend_); |
| 61 backend_ = new ExtensionSettingsBackend(base_path, observers_); |
| 62 } |
| 63 |
| 64 // Runs |callback| with the extension backend. |
| 65 void RunWithBackendOnFileThread(const BackendCallback& callback) { |
| 66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 67 DCHECK(backend_); |
| 68 callback.Run(backend_); |
| 69 } |
| 70 |
| 71 private: |
| 72 virtual ~Core() { |
| 73 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
| 74 delete backend_; |
| 75 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 76 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); |
| 77 } else { |
| 78 NOTREACHED(); |
| 79 } |
| 80 } |
| 81 |
| 82 friend class base::RefCountedThreadSafe<Core>; |
| 83 |
| 84 // Observers to settings changes (thread safe). |
| 85 scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> > |
| 86 observers_; |
| 87 |
| 88 // Lives on the FILE thread. |
| 89 ExtensionSettingsBackend* backend_; |
| 90 |
| 91 DISALLOW_COPY_AND_ASSIGN(Core); |
| 92 }; |
| 93 |
| 94 ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile) |
| 95 : observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()), |
| 96 core_(new ExtensionSettingsFrontend::Core(observers_.get())) { |
15 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 98 |
| 99 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| 100 NotificationService::AllBrowserContextsAndSources()); |
| 101 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 102 NotificationService::AllBrowserContextsAndSources()); |
| 103 OnProfileCreated(profile); |
| 104 |
16 BrowserThread::PostTask( | 105 BrowserThread::PostTask( |
17 BrowserThread::FILE, | 106 BrowserThread::FILE, |
18 FROM_HERE, | 107 FROM_HERE, |
19 base::Bind( | 108 base::Bind( |
20 &ExtensionSettingsFrontend::Core::InitOnFileThread, | 109 &ExtensionSettingsFrontend::Core::InitOnFileThread, |
21 core_.get(), | 110 core_.get(), |
22 base_path)); | 111 profile->GetPath().AppendASCII( |
| 112 ExtensionService::kSettingsDirectoryName))); |
| 113 } |
| 114 |
| 115 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { |
| 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
23 } | 117 } |
24 | 118 |
25 void ExtensionSettingsFrontend::RunWithBackend( | 119 void ExtensionSettingsFrontend::RunWithBackend( |
26 const BackendCallback& callback) { | 120 const BackendCallback& callback) { |
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
28 BrowserThread::PostTask( | 122 BrowserThread::PostTask( |
29 BrowserThread::FILE, | 123 BrowserThread::FILE, |
30 FROM_HERE, | 124 FROM_HERE, |
31 base::Bind( | 125 base::Bind( |
32 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread, | 126 &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread, |
33 core_.get(), | 127 core_.get(), |
34 callback)); | 128 callback)); |
35 } | 129 } |
36 | 130 |
37 ExtensionSettingsFrontend::~ExtensionSettingsFrontend() { | 131 void ExtensionSettingsFrontend::AddObserver( |
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 132 ExtensionSettingsObserver* observer) { |
| 133 observers_->AddObserver(observer); |
39 } | 134 } |
40 | 135 |
41 ExtensionSettingsFrontend::Core::Core() : backend_(NULL) { | 136 void ExtensionSettingsFrontend::RemoveObserver( |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 137 ExtensionSettingsObserver* observer) { |
| 138 observers_->RemoveObserver(observer); |
43 } | 139 } |
44 | 140 |
45 void ExtensionSettingsFrontend::Core::InitOnFileThread( | 141 void ExtensionSettingsFrontend::Observe( |
46 const FilePath& base_path) { | 142 int type, |
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 143 const NotificationSource& source, |
48 DCHECK(!backend_); | 144 const NotificationDetails& details) { |
49 backend_ = new ExtensionSettingsBackend(base_path); | 145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 146 switch (type) { |
| 147 case chrome::NOTIFICATION_PROFILE_CREATED: |
| 148 OnProfileCreated(Source<Profile>(source).ptr()); |
| 149 break; |
| 150 case chrome::NOTIFICATION_PROFILE_DESTROYED: |
| 151 OnProfileDestroyed(Source<Profile>(source).ptr()); |
| 152 break; |
| 153 default: |
| 154 NOTREACHED(); |
| 155 } |
50 } | 156 } |
51 | 157 |
52 void ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread( | 158 void ExtensionSettingsFrontend::OnProfileCreated(Profile* new_profile) { |
53 const BackendCallback& callback) { | 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 160 DCHECK(profile_observers_.find(new_profile) == profile_observers_.end()); |
55 DCHECK(backend_); | 161 linked_ptr<DefaultObserver> new_observer(new DefaultObserver(new_profile)); |
56 callback.Run(backend_); | 162 profile_observers_[new_profile] = new_observer; |
| 163 AddObserver(new_observer.get()); |
57 } | 164 } |
58 | 165 |
59 ExtensionSettingsFrontend::Core::~Core() { | 166 void ExtensionSettingsFrontend::OnProfileDestroyed(Profile* old_profile) { |
60 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
61 delete backend_; | 168 linked_ptr<DefaultObserver> old_observer = profile_observers_[old_profile]; |
62 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 169 DCHECK(old_observer.get()); |
63 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); | 170 profile_observers_.erase(old_profile); |
64 } else { | 171 RemoveObserver(old_observer.get()); |
65 NOTREACHED(); | |
66 } | |
67 } | 172 } |
OLD | NEW |