GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_service.cc
blobc7b4cb2b174067ecea4c0391c952603960db68e1
1 // Copyright 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.
5 #include "chrome/browser/apps/ephemeral_app_service.h"
7 #include "base/command_line.h"
8 #include "chrome/browser/apps/ephemeral_app_service_factory.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/data_deleter.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/browser/extension_util.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_set.h"
25 using extensions::Extension;
26 using extensions::ExtensionInfo;
27 using extensions::ExtensionPrefs;
28 using extensions::ExtensionSet;
29 using extensions::ExtensionSystem;
30 using extensions::InstalledExtensionInfo;
32 namespace {
34 // The number of seconds after startup before performing garbage collection
35 // of ephemeral apps.
36 const int kGarbageCollectAppsStartupDelay = 60;
38 // The number of seconds after an ephemeral app has been installed before
39 // performing garbage collection.
40 const int kGarbageCollectAppsInstallDelay = 15;
42 // When the number of ephemeral apps reaches this count, trigger garbage
43 // collection to trim off the least-recently used apps in excess of
44 // kMaxEphemeralAppsCount.
45 const int kGarbageCollectAppsTriggerCount = 35;
47 // The number of seconds after startup before performing garbage collection
48 // of the data of evicted ephemeral apps.
49 const int kGarbageCollectDataStartupDelay = 120;
51 } // namespace
53 const int EphemeralAppService::kAppInactiveThreshold = 10;
54 const int EphemeralAppService::kAppKeepThreshold = 1;
55 const int EphemeralAppService::kMaxEphemeralAppsCount = 30;
56 const int EphemeralAppService::kDataInactiveThreshold = 90;
58 // static
59 EphemeralAppService* EphemeralAppService::Get(Profile* profile) {
60 return EphemeralAppServiceFactory::GetForProfile(profile);
63 EphemeralAppService::EphemeralAppService(Profile* profile)
64 : profile_(profile),
65 extension_registry_observer_(this),
66 ephemeral_app_count_(-1) {
67 if (!CommandLine::ForCurrentProcess()->HasSwitch(
68 switches::kEnableEphemeralApps))
69 return;
71 extension_registry_observer_.Add(
72 extensions::ExtensionRegistry::Get(profile_));
73 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
74 content::Source<Profile>(profile_));
75 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
76 content::Source<Profile>(profile_));
79 EphemeralAppService::~EphemeralAppService() {
82 void EphemeralAppService::Observe(
83 int type,
84 const content::NotificationSource& source,
85 const content::NotificationDetails& details) {
86 switch (type) {
87 case chrome::NOTIFICATION_EXTENSIONS_READY: {
88 Init();
89 break;
91 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
92 // Ideally we need to know when the extension system is shutting down.
93 garbage_collect_apps_timer_.Stop();
94 break;
96 default:
97 NOTREACHED();
101 void EphemeralAppService::OnExtensionWillBeInstalled(
102 content::BrowserContext* browser_context,
103 const extensions::Extension* extension,
104 bool is_update,
105 bool from_ephemeral,
106 const std::string& old_name) {
107 if (from_ephemeral) {
108 // An ephemeral app was just promoted to a regular installed app.
109 --ephemeral_app_count_;
110 DCHECK_GE(ephemeral_app_count_, 0);
111 } else if (!is_update &&
112 extensions::util::IsEphemeralApp(extension->id(), profile_)) {
113 ++ephemeral_app_count_;
114 if (ephemeral_app_count_ >= kGarbageCollectAppsTriggerCount) {
115 TriggerGarbageCollect(
116 base::TimeDelta::FromSeconds(kGarbageCollectAppsInstallDelay));
121 void EphemeralAppService::OnExtensionUninstalled(
122 content::BrowserContext* browser_context,
123 const extensions::Extension* extension) {
124 if (extensions::util::IsEphemeralApp(extension->id(), profile_)) {
125 --ephemeral_app_count_;
126 DCHECK_GE(ephemeral_app_count_, 0);
130 void EphemeralAppService::Init() {
131 InitEphemeralAppCount();
132 TriggerGarbageCollect(
133 base::TimeDelta::FromSeconds(kGarbageCollectAppsStartupDelay));
135 garbage_collect_data_timer_.Start(
136 FROM_HERE,
137 base::TimeDelta::FromSeconds(kGarbageCollectDataStartupDelay),
138 this,
139 &EphemeralAppService::GarbageCollectData);
142 void EphemeralAppService::InitEphemeralAppCount() {
143 scoped_ptr<ExtensionSet> extensions =
144 extensions::ExtensionRegistry::Get(profile_)
145 ->GenerateInstalledExtensionsSet();
146 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
147 DCHECK(prefs);
149 ephemeral_app_count_ = 0;
150 for (ExtensionSet::const_iterator it = extensions->begin();
151 it != extensions->end(); ++it) {
152 const Extension* extension = *it;
153 if (prefs->IsEphemeralApp(extension->id()))
154 ++ephemeral_app_count_;
158 void EphemeralAppService::TriggerGarbageCollect(const base::TimeDelta& delay) {
159 if (!garbage_collect_apps_timer_.IsRunning()) {
160 garbage_collect_apps_timer_.Start(
161 FROM_HERE,
162 delay,
163 this,
164 &EphemeralAppService::GarbageCollectApps);
168 void EphemeralAppService::GarbageCollectApps() {
169 scoped_ptr<ExtensionSet> extensions =
170 extensions::ExtensionRegistry::Get(profile_)
171 ->GenerateInstalledExtensionsSet();
172 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
173 DCHECK(prefs);
175 int app_count = 0;
176 LaunchTimeAppMap app_launch_times;
177 std::set<std::string> remove_app_ids;
179 // Populate a list of ephemeral apps, ordered by their last launch time.
180 for (ExtensionSet::const_iterator it = extensions->begin();
181 it != extensions->end(); ++it) {
182 const Extension* extension = *it;
183 if (!prefs->IsEphemeralApp(extension->id()))
184 continue;
186 ++app_count;
188 // Do not remove ephemeral apps that are running.
189 if (!extensions::util::IsExtensionIdle(extension->id(), profile_))
190 continue;
192 base::Time last_launch_time = prefs->GetLastLaunchTime(extension->id());
194 // If the last launch time is invalid, this may be because it was just
195 // installed. So use the install time. If this is also null for some reason,
196 // the app will be removed.
197 if (last_launch_time.is_null())
198 last_launch_time = prefs->GetInstallTime(extension->id());
200 app_launch_times.insert(std::make_pair(last_launch_time, extension->id()));
203 ExtensionService* service =
204 ExtensionSystem::Get(profile_)->extension_service();
205 DCHECK(service);
206 // Execute the replacement policies and remove apps marked for deletion.
207 if (!app_launch_times.empty()) {
208 GetAppsToRemove(app_count, app_launch_times, &remove_app_ids);
209 for (std::set<std::string>::const_iterator id = remove_app_ids.begin();
210 id != remove_app_ids.end(); ++id) {
211 if (service->UninstallExtension(*id, false, NULL))
212 --app_count;
216 ephemeral_app_count_ = app_count;
219 // static
220 void EphemeralAppService::GetAppsToRemove(
221 int app_count,
222 const LaunchTimeAppMap& app_launch_times,
223 std::set<std::string>* remove_app_ids) {
224 base::Time time_now = base::Time::Now();
225 const base::Time inactive_threshold =
226 time_now - base::TimeDelta::FromDays(kAppInactiveThreshold);
227 const base::Time keep_threshold =
228 time_now - base::TimeDelta::FromDays(kAppKeepThreshold);
230 // Visit the apps in order of least recently to most recently launched.
231 for (LaunchTimeAppMap::const_iterator it = app_launch_times.begin();
232 it != app_launch_times.end(); ++it) {
233 // Cannot remove apps that have been launched recently. So break when we
234 // reach the new apps.
235 if (it->first > keep_threshold)
236 break;
238 // Remove ephemeral apps that have been inactive for a while or if the cache
239 // is larger than the desired size.
240 if (it->first < inactive_threshold || app_count > kMaxEphemeralAppsCount) {
241 remove_app_ids->insert(it->second);
242 --app_count;
243 } else {
244 break;
249 void EphemeralAppService::GarbageCollectData() {
250 ExtensionService* service =
251 ExtensionSystem::Get(profile_)->extension_service();
252 DCHECK(service);
253 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
254 DCHECK(prefs);
255 scoped_ptr<ExtensionPrefs::ExtensionsInfo> evicted_apps_info(
256 prefs->GetEvictedEphemeralAppsInfo());
258 base::Time time_now = base::Time::Now();
259 const base::Time inactive_threshold =
260 time_now - base::TimeDelta::FromDays(kDataInactiveThreshold);
262 for (size_t i = 0; i < evicted_apps_info->size(); ++i) {
263 ExtensionInfo* info = evicted_apps_info->at(i).get();
264 base::Time last_launch_time = prefs->GetLastLaunchTime(info->extension_id);
265 if (last_launch_time > inactive_threshold)
266 continue;
268 // Sanity check to ensure the app is not currently installed.
269 if (service->GetInstalledExtension(info->extension_id)) {
270 NOTREACHED();
271 continue;
274 // Ensure the app is not waiting to be installed.
275 scoped_ptr<ExtensionInfo> delayed_install(
276 prefs->GetDelayedInstallInfo(info->extension_id));
277 if (delayed_install.get())
278 continue;
280 if (info->extension_manifest.get()) {
281 std::string error;
282 scoped_refptr<const Extension> extension(Extension::Create(
283 info->extension_path,
284 info->extension_location,
285 *info->extension_manifest,
286 prefs->GetCreationFlags(info->extension_id),
287 info->extension_id,
288 &error));
290 if (extension.get())
291 extensions::DataDeleter::StartDeleting(profile_, extension.get());
294 prefs->RemoveEvictedEphemeralApp(info->extension_id);