[go: nahoru, domu]

blob: 8fd05a85db6440fe883ed522db910f3d265955c8 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/extensions/install_limiter.h"
#include <string>
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/ash/extensions/install_limiter_factory.h"
#include "extensions/browser/extensions_browser_client.h"
namespace {
int64_t GetFileSize(const base::FilePath& file) {
// Get file size. In case of error, sets 0 as file size to let the installer
// run and fail.
int64_t size;
return base::GetFileSize(file, &size) ? size : 0;
}
} // namespace
namespace extensions {
////////////////////////////////////////////////////////////////////////////////
// InstallLimiter::DeferredInstall
InstallLimiter::DeferredInstall::DeferredInstall(
const scoped_refptr<CrxInstaller>& installer,
const CRXFileInfo& file_info)
: installer(installer), file_info(file_info) {}
InstallLimiter::DeferredInstall::DeferredInstall(const DeferredInstall& other) =
default;
InstallLimiter::DeferredInstall::~DeferredInstall() = default;
////////////////////////////////////////////////////////////////////////////////
// InstallLimiter
// static
InstallLimiter* InstallLimiter::Get(Profile* profile) {
return InstallLimiterFactory::GetForProfile(profile);
}
// static
bool InstallLimiter::ShouldDeferInstall(int64_t app_size,
const std::string& app_id) {
constexpr int64_t kBigAppSizeThreshold = 1048576; // 1MB in bytes
return app_size > kBigAppSizeThreshold &&
!ExtensionsBrowserClient::Get()->IsScreensaverInDemoMode(app_id);
}
InstallLimiter::InstallLimiter() : disabled_for_test_(false) {}
InstallLimiter::~InstallLimiter() = default;
void InstallLimiter::DisableForTest() {
disabled_for_test_ = true;
}
void InstallLimiter::Add(const scoped_refptr<CrxInstaller>& installer,
const CRXFileInfo& file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// No deferred installs when disabled for test.
if (disabled_for_test_) {
installer->InstallCrxFile(file_info);
return;
}
num_installs_waiting_for_file_size_++;
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&GetFileSize, file_info.path),
base::BindOnce(&InstallLimiter::AddWithSize,
weak_ptr_factory_.GetWeakPtr(), installer, file_info));
}
void InstallLimiter::OnAllExternalProvidersReady() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
all_external_providers_ready_ = true;
if (AllInstallsQueuedWithFileSize()) {
// Stop wait timer and let install notification drive deferred installs.
wait_timer_.Stop();
CheckAndRunDeferrredInstalls();
}
}
void InstallLimiter::AddWithSize(const scoped_refptr<CrxInstaller>& installer,
const CRXFileInfo& file_info,
int64_t size) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
num_installs_waiting_for_file_size_--;
if (!ShouldDeferInstall(size, installer->expected_id()) ||
AllInstallsQueuedWithFileSize()) {
RunInstall(installer, file_info);
// Stop wait timer and let install notification drive deferred installs.
wait_timer_.Stop();
return;
}
deferred_installs_.push(DeferredInstall(installer, file_info));
// When there are no running installs, wait a bit before running deferred
// installs to allow small app install to take precedence, especially when a
// big app is the first one in the list.
if (num_running_installs_ == 0 && !wait_timer_.IsRunning()) {
const int kMaxWaitTimeInMs = 5000; // 5 seconds.
wait_timer_.Start(FROM_HERE, base::Milliseconds(kMaxWaitTimeInMs), this,
&InstallLimiter::CheckAndRunDeferrredInstalls);
}
}
void InstallLimiter::CheckAndRunDeferrredInstalls() {
if (deferred_installs_.empty() || num_running_installs_ > 0)
return;
const DeferredInstall& deferred = deferred_installs_.front();
RunInstall(deferred.installer, deferred.file_info);
deferred_installs_.pop();
}
void InstallLimiter::RunInstall(const scoped_refptr<CrxInstaller>& installer,
const CRXFileInfo& file_info) {
installer->AddInstallerCallback(base::BindOnce(
&InstallLimiter::OnInstallerDone, weak_ptr_factory_.GetWeakPtr()));
installer->InstallCrxFile(file_info);
num_running_installs_++;
}
void InstallLimiter::OnInstallerDone(
const std::optional<CrxInstallError>& error) {
CHECK(num_running_installs_ > 0);
num_running_installs_--;
CheckAndRunDeferrredInstalls();
}
bool InstallLimiter::AllInstallsQueuedWithFileSize() const {
return all_external_providers_ready_ &&
num_installs_waiting_for_file_size_ == 0;
}
} // namespace extensions