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