| 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 |