OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/apps/ephemeral_app_service.h" | 5 #include "chrome/browser/apps/ephemeral_app_service.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "chrome/browser/apps/ephemeral_app_service_factory.h" | 8 #include "chrome/browser/apps/ephemeral_app_service_factory.h" |
9 #include "chrome/browser/chrome_notification_types.h" | 9 #include "chrome/browser/chrome_notification_types.h" |
10 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
11 #include "chrome/browser/extensions/extension_util.h" | 11 #include "chrome/browser/extensions/extension_util.h" |
12 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
13 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
14 #include "content/public/browser/notification_service.h" | 14 #include "content/public/browser/notification_service.h" |
15 #include "content/public/browser/notification_source.h" | 15 #include "content/public/browser/notification_source.h" |
16 #include "content/public/browser/notification_types.h" | 16 #include "content/public/browser/notification_types.h" |
17 #include "extensions/browser/extension_prefs.h" | 17 #include "extensions/browser/extension_prefs.h" |
18 #include "extensions/browser/extension_registry.h" | 18 #include "extensions/browser/extension_registry.h" |
19 #include "extensions/browser/extension_system.h" | 19 #include "extensions/browser/extension_system.h" |
20 #include "extensions/browser/extension_util.h" | 20 #include "extensions/browser/extension_util.h" |
21 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
22 #include "extensions/common/extension_set.h" | 22 #include "extensions/common/extension_set.h" |
23 | 23 |
24 using extensions::Extension; | 24 using extensions::Extension; |
25 using extensions::ExtensionPrefs; | 25 using extensions::ExtensionPrefs; |
| 26 using extensions::ExtensionRegistry; |
26 using extensions::ExtensionSet; | 27 using extensions::ExtensionSet; |
27 using extensions::ExtensionSystem; | 28 using extensions::ExtensionSystem; |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 // The number of seconds after startup before performing garbage collection | 32 // The number of seconds after startup before performing garbage collection |
32 // of ephemeral apps. | 33 // of ephemeral apps. |
33 const int kGarbageCollectAppsStartupDelay = 60; | 34 const int kGarbageCollectAppsStartupDelay = 60; |
34 | 35 |
35 // The number of seconds after an ephemeral app has been installed before | 36 // The number of seconds after an ephemeral app has been installed before |
(...skipping 17 matching lines...) Expand all Loading... |
53 } | 54 } |
54 | 55 |
55 EphemeralAppService::EphemeralAppService(Profile* profile) | 56 EphemeralAppService::EphemeralAppService(Profile* profile) |
56 : profile_(profile), | 57 : profile_(profile), |
57 extension_registry_observer_(this), | 58 extension_registry_observer_(this), |
58 ephemeral_app_count_(-1) { | 59 ephemeral_app_count_(-1) { |
59 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 60 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
60 switches::kEnableEphemeralApps)) | 61 switches::kEnableEphemeralApps)) |
61 return; | 62 return; |
62 | 63 |
63 extension_registry_observer_.Add( | 64 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); |
64 extensions::ExtensionRegistry::Get(profile_)); | |
65 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 65 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
66 content::Source<Profile>(profile_)); | 66 content::Source<Profile>(profile_)); |
67 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 67 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
68 content::Source<Profile>(profile_)); | 68 content::Source<Profile>(profile_)); |
69 } | 69 } |
70 | 70 |
71 EphemeralAppService::~EphemeralAppService() { | 71 EphemeralAppService::~EphemeralAppService() { |
72 } | 72 } |
73 | 73 |
| 74 void EphemeralAppService::ClearCachedApps() { |
| 75 // Cancel any pending garbage collects. |
| 76 garbage_collect_apps_timer_.Stop(); |
| 77 |
| 78 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| 79 DCHECK(registry); |
| 80 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); |
| 81 DCHECK(prefs); |
| 82 ExtensionService* service = |
| 83 ExtensionSystem::Get(profile_)->extension_service(); |
| 84 DCHECK(service); |
| 85 |
| 86 scoped_ptr<ExtensionSet> extensions = |
| 87 registry->GenerateInstalledExtensionsSet(); |
| 88 |
| 89 for (ExtensionSet::const_iterator it = extensions->begin(); |
| 90 it != extensions->end(); |
| 91 ++it) { |
| 92 std::string extension_id = (*it)->id(); |
| 93 if (!prefs->IsEphemeralApp(extension_id)) |
| 94 continue; |
| 95 |
| 96 // Do not remove apps that are running. |
| 97 if (!extensions::util::IsExtensionIdle(extension_id, profile_)) |
| 98 continue; |
| 99 |
| 100 DCHECK(registry->GetExtensionById(extension_id, |
| 101 ExtensionRegistry::EVERYTHING)); |
| 102 service->UninstallExtension( |
| 103 extension_id, |
| 104 ExtensionService::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION, |
| 105 NULL); |
| 106 } |
| 107 } |
| 108 |
74 void EphemeralAppService::Observe( | 109 void EphemeralAppService::Observe( |
75 int type, | 110 int type, |
76 const content::NotificationSource& source, | 111 const content::NotificationSource& source, |
77 const content::NotificationDetails& details) { | 112 const content::NotificationDetails& details) { |
78 switch (type) { | 113 switch (type) { |
79 case chrome::NOTIFICATION_EXTENSIONS_READY: { | 114 case chrome::NOTIFICATION_EXTENSIONS_READY: { |
80 Init(); | 115 Init(); |
81 break; | 116 break; |
82 } | 117 } |
83 case chrome::NOTIFICATION_PROFILE_DESTROYED: { | 118 case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 } | 155 } |
121 | 156 |
122 void EphemeralAppService::Init() { | 157 void EphemeralAppService::Init() { |
123 InitEphemeralAppCount(); | 158 InitEphemeralAppCount(); |
124 TriggerGarbageCollect( | 159 TriggerGarbageCollect( |
125 base::TimeDelta::FromSeconds(kGarbageCollectAppsStartupDelay)); | 160 base::TimeDelta::FromSeconds(kGarbageCollectAppsStartupDelay)); |
126 } | 161 } |
127 | 162 |
128 void EphemeralAppService::InitEphemeralAppCount() { | 163 void EphemeralAppService::InitEphemeralAppCount() { |
129 scoped_ptr<ExtensionSet> extensions = | 164 scoped_ptr<ExtensionSet> extensions = |
130 extensions::ExtensionRegistry::Get(profile_) | 165 ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet(); |
131 ->GenerateInstalledExtensionsSet(); | |
132 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); | 166 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); |
133 DCHECK(prefs); | 167 DCHECK(prefs); |
134 | 168 |
135 ephemeral_app_count_ = 0; | 169 ephemeral_app_count_ = 0; |
136 for (ExtensionSet::const_iterator it = extensions->begin(); | 170 for (ExtensionSet::const_iterator it = extensions->begin(); |
137 it != extensions->end(); ++it) { | 171 it != extensions->end(); ++it) { |
138 const Extension* extension = *it; | 172 const Extension* extension = *it; |
139 if (prefs->IsEphemeralApp(extension->id())) | 173 if (prefs->IsEphemeralApp(extension->id())) |
140 ++ephemeral_app_count_; | 174 ++ephemeral_app_count_; |
141 } | 175 } |
142 } | 176 } |
143 | 177 |
144 void EphemeralAppService::TriggerGarbageCollect(const base::TimeDelta& delay) { | 178 void EphemeralAppService::TriggerGarbageCollect(const base::TimeDelta& delay) { |
145 if (!garbage_collect_apps_timer_.IsRunning()) { | 179 if (!garbage_collect_apps_timer_.IsRunning()) { |
146 garbage_collect_apps_timer_.Start( | 180 garbage_collect_apps_timer_.Start( |
147 FROM_HERE, | 181 FROM_HERE, |
148 delay, | 182 delay, |
149 this, | 183 this, |
150 &EphemeralAppService::GarbageCollectApps); | 184 &EphemeralAppService::GarbageCollectApps); |
151 } | 185 } |
152 } | 186 } |
153 | 187 |
154 void EphemeralAppService::GarbageCollectApps() { | 188 void EphemeralAppService::GarbageCollectApps() { |
155 scoped_ptr<ExtensionSet> extensions = | 189 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
156 extensions::ExtensionRegistry::Get(profile_) | 190 DCHECK(registry); |
157 ->GenerateInstalledExtensionsSet(); | |
158 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); | 191 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); |
159 DCHECK(prefs); | 192 DCHECK(prefs); |
160 | 193 |
| 194 scoped_ptr<ExtensionSet> extensions = |
| 195 registry->GenerateInstalledExtensionsSet(); |
| 196 |
161 int app_count = 0; | 197 int app_count = 0; |
162 LaunchTimeAppMap app_launch_times; | 198 LaunchTimeAppMap app_launch_times; |
163 std::set<std::string> remove_app_ids; | 199 std::set<std::string> remove_app_ids; |
164 | 200 |
165 // Populate a list of ephemeral apps, ordered by their last launch time. | 201 // Populate a list of ephemeral apps, ordered by their last launch time. |
166 for (ExtensionSet::const_iterator it = extensions->begin(); | 202 for (ExtensionSet::const_iterator it = extensions->begin(); |
167 it != extensions->end(); ++it) { | 203 it != extensions->end(); ++it) { |
168 const Extension* extension = *it; | 204 const Extension* extension = *it; |
169 if (!prefs->IsEphemeralApp(extension->id())) | 205 if (!prefs->IsEphemeralApp(extension->id())) |
170 continue; | 206 continue; |
(...skipping 11 matching lines...) Expand all Loading... |
182 // the app will be removed. | 218 // the app will be removed. |
183 if (last_launch_time.is_null()) | 219 if (last_launch_time.is_null()) |
184 last_launch_time = prefs->GetInstallTime(extension->id()); | 220 last_launch_time = prefs->GetInstallTime(extension->id()); |
185 | 221 |
186 app_launch_times.insert(std::make_pair(last_launch_time, extension->id())); | 222 app_launch_times.insert(std::make_pair(last_launch_time, extension->id())); |
187 } | 223 } |
188 | 224 |
189 ExtensionService* service = | 225 ExtensionService* service = |
190 ExtensionSystem::Get(profile_)->extension_service(); | 226 ExtensionSystem::Get(profile_)->extension_service(); |
191 DCHECK(service); | 227 DCHECK(service); |
192 // Execute the replacement policies and remove apps marked for deletion. | 228 // Execute the eviction policies and remove apps marked for deletion. |
193 if (!app_launch_times.empty()) { | 229 if (!app_launch_times.empty()) { |
194 GetAppsToRemove(app_count, app_launch_times, &remove_app_ids); | 230 GetAppsToRemove(app_count, app_launch_times, &remove_app_ids); |
| 231 |
195 for (std::set<std::string>::const_iterator id = remove_app_ids.begin(); | 232 for (std::set<std::string>::const_iterator id = remove_app_ids.begin(); |
196 id != remove_app_ids.end(); ++id) { | 233 id != remove_app_ids.end(); ++id) { |
197 if (service->UninstallExtension( | 234 // Protect against cascading uninstalls. |
198 *id, | 235 if (!registry->GetExtensionById(*id, ExtensionRegistry::EVERYTHING)) |
199 ExtensionService::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION, | 236 continue; |
200 NULL)) { | 237 |
201 --app_count; | 238 service->UninstallExtension( |
202 } | 239 *id, |
| 240 ExtensionService::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION, |
| 241 NULL); |
203 } | 242 } |
204 } | 243 } |
205 | |
206 ephemeral_app_count_ = app_count; | |
207 } | 244 } |
208 | 245 |
209 // static | 246 // static |
210 void EphemeralAppService::GetAppsToRemove( | 247 void EphemeralAppService::GetAppsToRemove( |
211 int app_count, | 248 int app_count, |
212 const LaunchTimeAppMap& app_launch_times, | 249 const LaunchTimeAppMap& app_launch_times, |
213 std::set<std::string>* remove_app_ids) { | 250 std::set<std::string>* remove_app_ids) { |
214 base::Time time_now = base::Time::Now(); | 251 base::Time time_now = base::Time::Now(); |
215 const base::Time inactive_threshold = | 252 const base::Time inactive_threshold = |
216 time_now - base::TimeDelta::FromDays(kAppInactiveThreshold); | 253 time_now - base::TimeDelta::FromDays(kAppInactiveThreshold); |
(...skipping 11 matching lines...) Expand all Loading... |
228 // Remove ephemeral apps that have been inactive for a while or if the cache | 265 // Remove ephemeral apps that have been inactive for a while or if the cache |
229 // is larger than the desired size. | 266 // is larger than the desired size. |
230 if (it->first < inactive_threshold || app_count > kMaxEphemeralAppsCount) { | 267 if (it->first < inactive_threshold || app_count > kMaxEphemeralAppsCount) { |
231 remove_app_ids->insert(it->second); | 268 remove_app_ids->insert(it->second); |
232 --app_count; | 269 --app_count; |
233 } else { | 270 } else { |
234 break; | 271 break; |
235 } | 272 } |
236 } | 273 } |
237 } | 274 } |
OLD | NEW |