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