12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/install_limiter.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/install_limiter_factory.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_details.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_source.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)int64 GetFileSizeOnBlockingPool(const base::FilePath& file) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get file size. In case of error, sets 0 as file size to let the installer
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // run and fail.
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int64 size;
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return base::GetFileSize(file, &size) ? size : 0;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// InstallLimiter::DeferredInstall
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallLimiter::DeferredInstall::DeferredInstall(
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<CrxInstaller>& installer,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : installer(installer),
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path(path) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallLimiter::DeferredInstall::~DeferredInstall() {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// InstallLimiter
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallLimiter* InstallLimiter::Get(Profile* profile) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return InstallLimiterFactory::GetForProfile(profile);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallLimiter::InstallLimiter() : disabled_for_test_(false) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InstallLimiter::~InstallLimiter() {
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::DisableForTest() {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  disabled_for_test_ = true;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::Add(const scoped_refptr<CrxInstaller>& installer,
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         const base::FilePath& path) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // No deferred installs when disabled for test.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (disabled_for_test_) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    installer->InstallCrx(path);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::PostTaskAndReplyWithResult(
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BrowserThread::GetBlockingPool(),
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&GetFileSizeOnBlockingPool, path),
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&InstallLimiter::AddWithSize, AsWeakPtr(), installer, path));
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::AddWithSize(
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<CrxInstaller>& installer,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path,
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int64 size) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int64 kBigAppSizeThreshold = 1048576;  // 1MB
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (size <= kBigAppSizeThreshold) {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunInstall(installer, path);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Stop wait timer and let install notification drive deferred installs.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    wait_timer_.Stop();
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deferred_installs_.push(DeferredInstall(installer, path));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When there are no running installs, wait a bit before running deferred
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // installs to allow small app install to take precedence, especially when a
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // big app is the first one in the list.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (running_installers_.empty() && !wait_timer_.IsRunning()) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int kMaxWaitTimeInMs = 5000;  // 5 seconds.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    wait_timer_.Start(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(kMaxWaitTimeInMs),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this, &InstallLimiter::CheckAndRunDeferrredInstalls);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::CheckAndRunDeferrredInstalls() {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (deferred_installs_.empty() || !running_installers_.empty())
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const DeferredInstall& deferred = deferred_installs_.front();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunInstall(deferred.installer, deferred.path);
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deferred_installs_.pop();
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::RunInstall(const scoped_refptr<CrxInstaller>& installer,
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                const base::FilePath& path) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this,
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<CrxInstaller>(installer.get()));
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  installer->InstallCrx(path);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  running_installers_.insert(installer);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InstallLimiter::Observe(int type,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const content::NotificationSource& source,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const content::NotificationDetails& details) {
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(extensions::NOTIFICATION_CRX_INSTALLER_DONE, type);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const scoped_refptr<CrxInstaller> installer =
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      content::Source<extensions::CrxInstaller>(source).ptr();
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  running_installers_.erase(installer);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckAndRunDeferrredInstalls();
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
141