blob: 313225df59060d09c967dd4cf239bc78eb43db8f [file] [log] [blame]
// Copyright 2014 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/extension_install_checker.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/chrome_requirements_checker.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
namespace extensions {
ExtensionInstallChecker::ExtensionInstallChecker(Profile* profile)
: profile_(profile),
blacklist_state_(NOT_BLACKLISTED),
policy_allows_load_(true),
current_sequence_number_(0),
running_checks_(0),
fail_fast_(false),
weak_ptr_factory_(this) {
}
ExtensionInstallChecker::~ExtensionInstallChecker() {
}
void ExtensionInstallChecker::Start(int enabled_checks,
bool fail_fast,
const Callback& callback) {
// Profile is null in tests.
if (profile_) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!extension_.get()) {
NOTREACHED();
return;
}
}
if (is_running() || !enabled_checks || callback.is_null()) {
NOTREACHED();
return;
}
running_checks_ = enabled_checks;
fail_fast_ = fail_fast;
callback_ = callback;
ResetResults();
// Execute the management policy check first as it is synchronous.
if (enabled_checks & CHECK_MANAGEMENT_POLICY) {
CheckManagementPolicy();
if (!is_running())
return;
}
if (enabled_checks & CHECK_REQUIREMENTS) {
CheckRequirements();
if (!is_running())
return;
}
if (enabled_checks & CHECK_BLACKLIST)
CheckBlacklistState();
}
void ExtensionInstallChecker::CheckManagementPolicy() {
DCHECK(extension_.get());
base::string16 error;
bool allow = ExtensionSystem::Get(profile_)->management_policy()->UserMayLoad(
extension_.get(), &error);
OnManagementPolicyCheckDone(allow, base::UTF16ToUTF8(error));
}
void ExtensionInstallChecker::OnManagementPolicyCheckDone(
bool allows_load,
const std::string& error) {
policy_allows_load_ = allows_load;
policy_error_ = error;
DCHECK(policy_allows_load_ || !policy_error_.empty());
running_checks_ &= ~CHECK_MANAGEMENT_POLICY;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::CheckRequirements() {
DCHECK(extension_.get());
if (!requirements_checker_.get())
requirements_checker_.reset(new ChromeRequirementsChecker());
requirements_checker_->Check(
extension_,
base::Bind(&ExtensionInstallChecker::OnRequirementsCheckDone,
weak_ptr_factory_.GetWeakPtr(),
current_sequence_number_));
}
void ExtensionInstallChecker::OnRequirementsCheckDone(
int sequence_number,
const std::vector<std::string>& errors) {
// Some pending results may arrive after fail fast.
if (sequence_number != current_sequence_number_)
return;
requirement_errors_ = errors;
running_checks_ &= ~CHECK_REQUIREMENTS;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::CheckBlacklistState() {
DCHECK(extension_.get());
extensions::Blacklist* blacklist = Blacklist::Get(profile_);
blacklist->IsBlacklisted(
extension_->id(),
base::Bind(&ExtensionInstallChecker::OnBlacklistStateCheckDone,
weak_ptr_factory_.GetWeakPtr(),
current_sequence_number_));
}
void ExtensionInstallChecker::OnBlacklistStateCheckDone(int sequence_number,
BlacklistState state) {
// Some pending results may arrive after fail fast.
if (sequence_number != current_sequence_number_)
return;
blacklist_state_ = state;
running_checks_ &= ~CHECK_BLACKLIST;
MaybeInvokeCallback();
}
void ExtensionInstallChecker::ResetResults() {
requirement_errors_.clear();
blacklist_state_ = NOT_BLACKLISTED;
policy_allows_load_ = true;
policy_error_.clear();
}
void ExtensionInstallChecker::MaybeInvokeCallback() {
if (callback_.is_null())
return;
// Set bits for failed checks.
int failed_mask = 0;
if (blacklist_state_ == BLACKLISTED_MALWARE)
failed_mask |= CHECK_BLACKLIST;
if (!requirement_errors_.empty())
failed_mask |= CHECK_REQUIREMENTS;
if (!policy_allows_load_)
failed_mask |= CHECK_MANAGEMENT_POLICY;
// Invoke callback if all checks are complete or there was at least one
// failure and |fail_fast_| is true.
if (!is_running() || (failed_mask && fail_fast_)) {
// If we are failing fast, discard any pending results.
weak_ptr_factory_.InvalidateWeakPtrs();
running_checks_ = 0;
++current_sequence_number_;
Callback callback_copy = callback_;
callback_.Reset();
// This instance may be owned by the callback recipient and deleted here,
// so reset |callback_| first and invoke a copy of the callback.
callback_copy.Run(failed_mask);
}
}
} // namespace extensions