• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/extensions/install_limiter.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "chrome/browser/chromeos/extensions/install_limiter_factory.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "extensions/browser/notification_types.h"
17 
18 using content::BrowserThread;
19 
20 namespace {
21 
GetFileSizeOnBlockingPool(const base::FilePath & file)22 int64 GetFileSizeOnBlockingPool(const base::FilePath& file) {
23   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
24 
25   // Get file size. In case of error, sets 0 as file size to let the installer
26   // run and fail.
27   int64 size;
28   return base::GetFileSize(file, &size) ? size : 0;
29 }
30 
31 }  // namespace
32 
33 namespace extensions {
34 
35 ////////////////////////////////////////////////////////////////////////////////
36 // InstallLimiter::DeferredInstall
37 
DeferredInstall(const scoped_refptr<CrxInstaller> & installer,const base::FilePath & path)38 InstallLimiter::DeferredInstall::DeferredInstall(
39     const scoped_refptr<CrxInstaller>& installer,
40     const base::FilePath& path)
41     : installer(installer),
42       path(path) {
43 }
44 
~DeferredInstall()45 InstallLimiter::DeferredInstall::~DeferredInstall() {
46 }
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 // InstallLimiter
50 
Get(Profile * profile)51 InstallLimiter* InstallLimiter::Get(Profile* profile) {
52   return InstallLimiterFactory::GetForProfile(profile);
53 }
54 
InstallLimiter()55 InstallLimiter::InstallLimiter() : disabled_for_test_(false) {
56 }
57 
~InstallLimiter()58 InstallLimiter::~InstallLimiter() {
59 }
60 
DisableForTest()61 void InstallLimiter::DisableForTest() {
62   disabled_for_test_ = true;
63 }
64 
Add(const scoped_refptr<CrxInstaller> & installer,const base::FilePath & path)65 void InstallLimiter::Add(const scoped_refptr<CrxInstaller>& installer,
66                          const base::FilePath& path) {
67   // No deferred installs when disabled for test.
68   if (disabled_for_test_) {
69     installer->InstallCrx(path);
70     return;
71   }
72 
73   base::PostTaskAndReplyWithResult(
74       BrowserThread::GetBlockingPool(),
75       FROM_HERE,
76       base::Bind(&GetFileSizeOnBlockingPool, path),
77       base::Bind(&InstallLimiter::AddWithSize, AsWeakPtr(), installer, path));
78 }
79 
AddWithSize(const scoped_refptr<CrxInstaller> & installer,const base::FilePath & path,int64 size)80 void InstallLimiter::AddWithSize(
81     const scoped_refptr<CrxInstaller>& installer,
82     const base::FilePath& path,
83     int64 size) {
84   const int64 kBigAppSizeThreshold = 1048576;  // 1MB
85 
86   if (size <= kBigAppSizeThreshold) {
87     RunInstall(installer, path);
88 
89     // Stop wait timer and let install notification drive deferred installs.
90     wait_timer_.Stop();
91     return;
92   }
93 
94   deferred_installs_.push(DeferredInstall(installer, path));
95 
96   // When there are no running installs, wait a bit before running deferred
97   // installs to allow small app install to take precedence, especially when a
98   // big app is the first one in the list.
99   if (running_installers_.empty() && !wait_timer_.IsRunning()) {
100     const int kMaxWaitTimeInMs = 5000;  // 5 seconds.
101     wait_timer_.Start(
102         FROM_HERE,
103         base::TimeDelta::FromMilliseconds(kMaxWaitTimeInMs),
104         this, &InstallLimiter::CheckAndRunDeferrredInstalls);
105   }
106 }
107 
CheckAndRunDeferrredInstalls()108 void InstallLimiter::CheckAndRunDeferrredInstalls() {
109   if (deferred_installs_.empty() || !running_installers_.empty())
110     return;
111 
112   const DeferredInstall& deferred = deferred_installs_.front();
113   RunInstall(deferred.installer, deferred.path);
114   deferred_installs_.pop();
115 }
116 
RunInstall(const scoped_refptr<CrxInstaller> & installer,const base::FilePath & path)117 void InstallLimiter::RunInstall(const scoped_refptr<CrxInstaller>& installer,
118                                 const base::FilePath& path) {
119   registrar_.Add(this,
120                  extensions::NOTIFICATION_CRX_INSTALLER_DONE,
121                  content::Source<CrxInstaller>(installer.get()));
122 
123   installer->InstallCrx(path);
124   running_installers_.insert(installer);
125 }
126 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)127 void InstallLimiter::Observe(int type,
128                              const content::NotificationSource& source,
129                              const content::NotificationDetails& details) {
130   DCHECK_EQ(extensions::NOTIFICATION_CRX_INSTALLER_DONE, type);
131 
132   registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
133 
134   const scoped_refptr<CrxInstaller> installer =
135       content::Source<extensions::CrxInstaller>(source).ptr();
136   running_installers_.erase(installer);
137   CheckAndRunDeferrredInstalls();
138 }
139 
140 }  // namespace extensions
141