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 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_INSTALL_LIMITER_H_
6 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_INSTALL_LIMITER_H_
7 
8 #include <stdint.h>
9 
10 #include <set>
11 
12 #include "base/compiler_specific.h"
13 #include "base/containers/queue.h"
14 #include "base/files/file_path.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/timer/timer.h"
19 #include "chrome/browser/extensions/crx_installer.h"
20 #include "components/keyed_service/core/keyed_service.h"
21 #include "content/public/browser/notification_observer.h"
22 #include "content/public/browser/notification_registrar.h"
23 
24 namespace extensions {
25 
26 // TODO(hendrich, https://crbug.com/1046302)
27 // Add a test for the InstallLimiter, which checks that small extensions are
28 // installed before large extensions and that we don't have to wait the entire
29 // 5s when the OnAllExternalProvidersReady() signal was called.
30 
31 // InstallLimiter defers big app installs after all small app installs and then
32 // runs big app installs one by one. This improves first-time login experience.
33 // See http://crbug.com/166296
34 class InstallLimiter : public KeyedService,
35                        public content::NotificationObserver,
36                        public base::SupportsWeakPtr<InstallLimiter> {
37  public:
38   static InstallLimiter* Get(Profile* profile);
39 
40   // Install should be deferred if the size is larger than 1MB and the app is
41   // not the screensaver in demo mode (which requires instant installation to
42   // avoid visual delay).
43   static bool ShouldDeferInstall(int64_t app_size, const std::string& app_id);
44 
45   InstallLimiter();
46   ~InstallLimiter() override;
47 
48   void DisableForTest();
49 
50   void Add(const scoped_refptr<CrxInstaller>& installer,
51            const CRXFileInfo& file_info);
52 
53   // Triggers installation of deferred installations if all file sizes for
54   // added installations have been determined.
55   void OnAllExternalProvidersReady();
56 
57  private:
58   // DeferredInstall holds info to run a CrxInstaller later.
59   struct DeferredInstall {
60     DeferredInstall(const scoped_refptr<CrxInstaller>& installer,
61                     const CRXFileInfo& file_info);
62     DeferredInstall(const DeferredInstall& other);
63     ~DeferredInstall();
64 
65     const scoped_refptr<CrxInstaller> installer;
66     const CRXFileInfo file_info;
67   };
68 
69   using DeferredInstallList = base::queue<DeferredInstall>;
70   using CrxInstallerSet = std::set<scoped_refptr<CrxInstaller>>;
71 
72   // Adds install info with size. If |size| is greater than a certain threshold,
73   // it stores the install info into |deferred_installs_| to run it later.
74   // Otherwise, it just runs the installer.
75   void AddWithSize(const scoped_refptr<CrxInstaller>& installer,
76                    const CRXFileInfo& file_info,
77                    int64_t size);
78 
79   // Checks and runs deferred big app installs when appropriate.
80   void CheckAndRunDeferrredInstalls();
81 
82   // Starts install using passed-in info and observes |installer|'s done
83   // notification.
84   void RunInstall(const scoped_refptr<CrxInstaller>& installer,
85                   const CRXFileInfo& file_info);
86 
87   // content::NotificationObserver overrides:
88   void Observe(int type,
89                const content::NotificationSource& source,
90                const content::NotificationDetails& details) override;
91 
92   // Checks that OnAllExternalProvidersReady() has been called and all file
93   // sizes for added installations are determined. If this method returns true,
94   // we can directly continue installing all remaining extensions, since there
95   // will be no more added installations coming.
96   bool AllInstallsQueuedWithFileSize() const;
97 
98   content::NotificationRegistrar registrar_;
99 
100   DeferredInstallList deferred_installs_;
101   CrxInstallerSet running_installers_;
102 
103   // A timer to wait before running deferred big app install.
104   base::OneShotTimer wait_timer_;
105 
106   bool disabled_for_test_;
107 
108   bool all_external_providers_ready_ = false;
109   int num_installs_waiting_for_file_size_ = 0;
110 
111   DISALLOW_COPY_AND_ASSIGN(InstallLimiter);
112 };
113 
114 }  // namespace extensions
115 
116 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_INSTALL_LIMITER_H_
117