Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / error_console / error_console.cc
blob7156622f7e9fc2feffa356828127f7e796eb237d
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.
5 #include "chrome/browser/extensions/error_console/error_console.h"
7 #include <list>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/lazy_instance.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/extension_system.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/pref_names.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_source.h"
24 #include "extensions/common/constants.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_set.h"
27 #include "extensions/common/feature_switch.h"
29 namespace extensions {
31 namespace {
33 const size_t kMaxErrorsPerExtension = 100;
35 // Iterate through an error list and remove and delete all errors which were
36 // from an incognito context.
37 void DeleteIncognitoErrorsFromList(ErrorConsole::ErrorList* list) {
38 ErrorConsole::ErrorList::iterator iter = list->begin();
39 while (iter != list->end()) {
40 if ((*iter)->from_incognito()) {
41 delete *iter;
42 iter = list->erase(iter);
43 } else {
44 ++iter;
49 // Iterate through an error list and remove and delete all errors of a given
50 // |type|.
51 void DeleteErrorsOfTypeFromList(ErrorConsole::ErrorList* list,
52 ExtensionError::Type type) {
53 ErrorConsole::ErrorList::iterator iter = list->begin();
54 while (iter != list->end()) {
55 if ((*iter)->type() == type) {
56 delete *iter;
57 iter = list->erase(iter);
58 } else {
59 ++iter;
64 base::LazyInstance<ErrorConsole::ErrorList> g_empty_error_list =
65 LAZY_INSTANCE_INITIALIZER;
67 } // namespace
69 void ErrorConsole::Observer::OnErrorConsoleDestroyed() {
72 ErrorConsole::ErrorConsole(Profile* profile,
73 ExtensionService* extension_service)
74 : enabled_(false), profile_(profile) {
75 // TODO(rdevlin.cronin): Remove once crbug.com/159265 is fixed.
76 #if !defined(ENABLE_EXTENSIONS)
77 return;
78 #endif
80 // If we don't have the necessary FeatureSwitch enabled, then return
81 // immediately. Since we never register for any notifications, this ensures
82 // the ErrorConsole will never be enabled.
83 if (!FeatureSwitch::error_console()->IsEnabled())
84 return;
86 pref_registrar_.Init(profile_->GetPrefs());
87 pref_registrar_.Add(prefs::kExtensionsUIDeveloperMode,
88 base::Bind(&ErrorConsole::OnPrefChanged,
89 base::Unretained(this)));
91 if (profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode))
92 Enable(extension_service);
95 ErrorConsole::~ErrorConsole() {
96 FOR_EACH_OBSERVER(Observer, observers_, OnErrorConsoleDestroyed());
97 RemoveAllErrors();
100 // static
101 ErrorConsole* ErrorConsole::Get(Profile* profile) {
102 return ExtensionSystem::Get(profile)->error_console();
105 void ErrorConsole::ReportError(scoped_ptr<ExtensionError> error) {
106 DCHECK(thread_checker_.CalledOnValidThread());
108 if (!enabled_ || !Extension::IdIsValid(error->extension_id()))
109 return;
111 ErrorList* extension_errors = &errors_[error->extension_id()];
113 // First, check if it's a duplicate.
114 for (ErrorList::iterator iter = extension_errors->begin();
115 iter != extension_errors->end(); ++iter) {
116 // If we find a duplicate error, remove the old error and add the new one,
117 // incrementing the occurrence count of the error. We use the new error
118 // for runtime errors, so we can link to the latest context, inspectable
119 // view, etc.
120 if (error->IsEqual(*iter)) {
121 error->set_occurrences((*iter)->occurrences() + 1);
122 delete *iter;
123 extension_errors->erase(iter);
124 break;
128 // If there are too many errors for an extension already, limit ourselves to
129 // the most recent ones.
130 if (extension_errors->size() >= kMaxErrorsPerExtension) {
131 delete extension_errors->front();
132 extension_errors->pop_front();
135 extension_errors->push_back(error.release());
137 FOR_EACH_OBSERVER(
138 Observer, observers_, OnErrorAdded(extension_errors->back()));
141 const ErrorConsole::ErrorList& ErrorConsole::GetErrorsForExtension(
142 const std::string& extension_id) const {
143 ErrorMap::const_iterator iter = errors_.find(extension_id);
144 if (iter != errors_.end())
145 return iter->second;
146 return g_empty_error_list.Get();
149 void ErrorConsole::AddObserver(Observer* observer) {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 observers_.AddObserver(observer);
154 void ErrorConsole::RemoveObserver(Observer* observer) {
155 DCHECK(thread_checker_.CalledOnValidThread());
156 observers_.RemoveObserver(observer);
159 void ErrorConsole::OnPrefChanged() {
160 bool developer_mode =
161 profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
163 if (developer_mode && !enabled_)
164 Enable(ExtensionSystem::Get(profile_)->extension_service());
165 else if (!developer_mode && enabled_)
166 Disable();
169 void ErrorConsole::Enable(ExtensionService* extension_service) {
170 enabled_ = true;
172 notification_registrar_.Add(
173 this,
174 chrome::NOTIFICATION_PROFILE_DESTROYED,
175 content::NotificationService::AllBrowserContextsAndSources());
176 notification_registrar_.Add(
177 this,
178 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
179 content::Source<Profile>(profile_));
180 notification_registrar_.Add(
181 this,
182 chrome::NOTIFICATION_EXTENSION_INSTALLED,
183 content::Source<Profile>(profile_));
185 if (extension_service) {
186 // Get manifest errors for extensions already installed.
187 const ExtensionSet* extensions = extension_service->extensions();
188 for (ExtensionSet::const_iterator iter = extensions->begin();
189 iter != extensions->end(); ++iter) {
190 AddManifestErrorsForExtension(iter->get());
195 void ErrorConsole::Disable() {
196 notification_registrar_.RemoveAll();
197 RemoveAllErrors();
198 enabled_ = false;
201 void ErrorConsole::AddManifestErrorsForExtension(const Extension* extension) {
202 const std::vector<InstallWarning>& warnings =
203 extension->install_warnings();
204 for (std::vector<InstallWarning>::const_iterator iter = warnings.begin();
205 iter != warnings.end(); ++iter) {
206 ReportError(scoped_ptr<ExtensionError>(new ManifestError(
207 extension->id(),
208 base::UTF8ToUTF16(iter->message),
209 base::UTF8ToUTF16(iter->key),
210 base::UTF8ToUTF16(iter->specific))));
214 void ErrorConsole::RemoveIncognitoErrors() {
215 for (ErrorMap::iterator iter = errors_.begin();
216 iter != errors_.end(); ++iter) {
217 DeleteIncognitoErrorsFromList(&(iter->second));
221 void ErrorConsole::RemoveErrorsForExtension(const std::string& extension_id) {
222 ErrorMap::iterator iter = errors_.find(extension_id);
223 if (iter != errors_.end()) {
224 STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
225 errors_.erase(iter);
229 void ErrorConsole::RemoveAllErrors() {
230 for (ErrorMap::iterator iter = errors_.begin(); iter != errors_.end(); ++iter)
231 STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
232 errors_.clear();
235 void ErrorConsole::Observe(int type,
236 const content::NotificationSource& source,
237 const content::NotificationDetails& details) {
238 switch (type) {
239 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
240 Profile* profile = content::Source<Profile>(source).ptr();
241 // If incognito profile which we are associated with is destroyed, also
242 // destroy all incognito errors.
243 if (profile->IsOffTheRecord() && profile_->IsSameProfile(profile))
244 RemoveIncognitoErrors();
245 break;
247 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
248 // No need to check the profile here, since we registered to only receive
249 // notifications from our own.
250 RemoveErrorsForExtension(
251 content::Details<Extension>(details).ptr()->id());
252 break;
253 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
254 const InstalledExtensionInfo* info =
255 content::Details<InstalledExtensionInfo>(details).ptr();
257 // We don't want to have manifest errors from previous installs. We want
258 // to keep runtime errors, though, because extensions are reloaded on a
259 // refresh of chrome:extensions, and we don't want to wipe our history
260 // whenever that happens.
261 ErrorMap::iterator iter = errors_.find(info->extension->id());
262 if (iter != errors_.end()) {
263 DeleteErrorsOfTypeFromList(&(iter->second),
264 ExtensionError::MANIFEST_ERROR);
267 AddManifestErrorsForExtension(info->extension);
268 break;
270 default:
271 NOTREACHED();
275 } // namespace extensions