blob: cff063cd3adc45272e927bd7140317f31fcc40c1 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/error_console/error_console.h"
#include <list>
#include "base/lazy_instance.h"
#include "base/stl_util.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "extensions/common/constants.h"
namespace extensions {
namespace {
const size_t kMaxErrorsPerExtension = 100;
// Iterate through an error list and remove and delete all errors which were
// from an incognito context.
void DeleteIncognitoErrorsFromList(ErrorConsole::ErrorList* list) {
ErrorConsole::ErrorList::iterator iter = list->begin();
while (iter != list->end()) {
if ((*iter)->from_incognito()) {
delete *iter;
iter = list->erase(iter);
} else {
++iter;
}
}
}
base::LazyInstance<ErrorConsole::ErrorList> g_empty_error_list =
LAZY_INSTANCE_INITIALIZER;
} // namespace
void ErrorConsole::Observer::OnErrorConsoleDestroyed() {
}
ErrorConsole::ErrorConsole(Profile* profile) : profile_(profile) {
registrar_.Add(this,
chrome::NOTIFICATION_PROFILE_DESTROYED,
content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(this,
chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
content::Source<Profile>(profile_));
}
ErrorConsole::~ErrorConsole() {
FOR_EACH_OBSERVER(Observer, observers_, OnErrorConsoleDestroyed());
RemoveAllErrors();
}
// static
ErrorConsole* ErrorConsole::Get(Profile* profile) {
return ExtensionSystem::Get(profile)->error_console();
}
void ErrorConsole::ReportError(scoped_ptr<const ExtensionError> scoped_error) {
DCHECK(thread_checker_.CalledOnValidThread());
const ExtensionError* error = scoped_error.release();
// If there are too many errors for an extension already, limit ourselves to
// the most recent ones.
ErrorList* error_list = &errors_[error->extension_id()];
if (error_list->size() >= kMaxErrorsPerExtension) {
delete error_list->front();
error_list->pop_front();
}
error_list->push_back(error);
FOR_EACH_OBSERVER(Observer, observers_, OnErrorAdded(error));
}
const ErrorConsole::ErrorList& ErrorConsole::GetErrorsForExtension(
const std::string& extension_id) const {
ErrorMap::const_iterator iter = errors_.find(extension_id);
if (iter != errors_.end())
return iter->second;
return g_empty_error_list.Get();
}
void ErrorConsole::AddObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.AddObserver(observer);
}
void ErrorConsole::RemoveObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.RemoveObserver(observer);
}
void ErrorConsole::RemoveIncognitoErrors() {
for (ErrorMap::iterator iter = errors_.begin();
iter != errors_.end(); ++iter) {
DeleteIncognitoErrorsFromList(&(iter->second));
}
}
void ErrorConsole::RemoveErrorsForExtension(const std::string& extension_id) {
ErrorMap::iterator iter = errors_.find(extension_id);
if (iter != errors_.end()) {
STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
errors_.erase(iter);
}
}
void ErrorConsole::RemoveAllErrors() {
for (ErrorMap::iterator iter = errors_.begin(); iter != errors_.end(); ++iter)
STLDeleteContainerPointers(iter->second.begin(), iter->second.end());
errors_.clear();
}
void ErrorConsole::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_DESTROYED: {
Profile* profile = content::Source<Profile>(source).ptr();
// If incognito profile which we are associated with is destroyed, also
// destroy all incognito errors.
if (profile->IsOffTheRecord() && profile_->IsSameProfile(profile))
RemoveIncognitoErrors();
break;
}
case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
// No need to check the profile here, since we registered to only receive
// notifications from our own.
RemoveErrorsForExtension(
content::Details<Extension>(details).ptr()->id());
break;
default:
NOTREACHED();
}
}
} // namespace extensions