error_console.cc revision ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16
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/error_console/error_console.h"
6
7#include <list>
8
9#include "base/lazy_instance.h"
10#include "base/stl_util.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/extensions/extension_system.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/common/extensions/extension.h"
15#include "content/public/browser/notification_details.h"
16#include "content/public/browser/notification_service.h"
17#include "content/public/browser/notification_source.h"
18#include "extensions/common/constants.h"
19
20namespace extensions {
21
22namespace {
23
24const size_t kMaxErrorsPerExtension = 100;
25
26// Iterate through an error list and remove and delete all errors which were
27// from an incognito context.
28void DeleteIncognitoErrorsFromList(ErrorConsole::ErrorList* list) {
29  ErrorConsole::ErrorList::iterator iter = list->begin();
30  while (iter != list->end()) {
31    if ((*iter)->from_incognito()) {
32      delete *iter;
33      iter = list->erase(iter);
34    } else {
35      ++iter;
36    }
37  }
38}
39
40base::LazyInstance<ErrorConsole::ErrorList> g_empty_error_list =
41    LAZY_INSTANCE_INITIALIZER;
42
43}  // namespace
44
45void ErrorConsole::Observer::OnErrorConsoleDestroyed() {
46}
47
48ErrorConsole::ErrorConsole(Profile* profile) : profile_(profile) {
49  registrar_.Add(this,
50                 chrome::NOTIFICATION_PROFILE_DESTROYED,
51                 content::NotificationService::AllBrowserContextsAndSources());
52  registrar_.Add(this,
53                 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
54                 content::Source<Profile>(profile_));
55}
56
57ErrorConsole::~ErrorConsole() {
58  FOR_EACH_OBSERVER(Observer, observers_, OnErrorConsoleDestroyed());
59  RemoveAllErrors();
60}
61
62// static
63ErrorConsole* ErrorConsole::Get(Profile* profile) {
64  return ExtensionSystem::Get(profile)->error_console();
65}
66
67void ErrorConsole::ReportError(scoped_ptr<const ExtensionError> scoped_error) {
68  DCHECK(thread_checker_.CalledOnValidThread());
69
70  const ExtensionError* error = scoped_error.release();
71  // If there are too many errors for an extension already, limit ourselves to
72  // the most recent ones.
73  ErrorList* error_list = &errors_[error->extension_id()];
74  if (error_list->size() >= kMaxErrorsPerExtension) {
75    delete error_list->front();
76    error_list->pop_front();
77  }
78  error_list->push_back(error);
79
80  FOR_EACH_OBSERVER(Observer, observers_, OnErrorAdded(error));
81}
82
83const ErrorConsole::ErrorList& ErrorConsole::GetErrorsForExtension(
84    const std::string& extension_id) const {
85  ErrorMap::const_iterator iter = errors_.find(extension_id);
86  if (iter != errors_.end())
87    return iter->second;
88  return g_empty_error_list.Get();
89}
90
91void ErrorConsole::AddObserver(Observer* observer) {
92  DCHECK(thread_checker_.CalledOnValidThread());
93  observers_.AddObserver(observer);
94}
95
96void ErrorConsole::RemoveObserver(Observer* observer) {
97  DCHECK(thread_checker_.CalledOnValidThread());
98  observers_.RemoveObserver(observer);
99}
100
101void ErrorConsole::RemoveIncognitoErrors() {
102  for (ErrorMap::iterator iter = errors_.begin();
103       iter != errors_.end(); ++iter) {
104    DeleteIncognitoErrorsFromList(&(iter->second));
105  }
106}
107
108void ErrorConsole::RemoveErrorsForExtension(const std::string& extension_id) {
109  ErrorMap::iterator iter = errors_.find(extension_id);
110  if (iter != errors_.end()) {
111    STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
112    errors_.erase(iter);
113  }
114}
115
116void ErrorConsole::RemoveAllErrors() {
117  for (ErrorMap::iterator iter = errors_.begin(); iter != errors_.end(); ++iter)
118    STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
119  errors_.clear();
120}
121
122void ErrorConsole::Observe(int type,
123                           const content::NotificationSource& source,
124                           const content::NotificationDetails& details) {
125  switch (type) {
126    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
127      Profile* profile = content::Source<Profile>(source).ptr();
128      // If incognito profile which we are associated with is destroyed, also
129      // destroy all incognito errors.
130      if (profile->IsOffTheRecord() && profile_->IsSameProfile(profile))
131        RemoveIncognitoErrors();
132      break;
133    }
134    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
135      // No need to check the profile here, since we registered to only receive
136      // notifications from our own.
137      RemoveErrorsForExtension(
138          content::Details<Extension>(details).ptr()->id());
139      break;
140    default:
141      NOTREACHED();
142  }
143}
144
145}  // namespace extensions
146