Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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/extensions/chrome_runtime_api_delegate.h" | |
| 6 | |
| 7 #include "base/message_loop/message_loop.h" | |
| 8 #include "base/metrics/histogram.h" | |
| 9 #include "base/time/time.h" | |
| 10 #include "chrome/browser/chrome_notification_types.h" | |
| 11 #include "chrome/browser/extensions/extension_service.h" | |
| 12 #include "chrome/browser/extensions/extension_warning_service.h" | |
| 13 #include "chrome/browser/extensions/extension_warning_set.h" | |
| 14 #include "chrome/browser/extensions/updater/extension_updater.h" | |
| 15 #include "chrome/browser/omaha_query_params/omaha_query_params.h" | |
| 16 #include "chrome/browser/profiles/profile.h" | |
| 17 #include "chrome/browser/ui/browser_finder.h" | |
| 18 #include "chrome/browser/ui/browser_navigator.h" | |
| 19 #include "chrome/browser/ui/browser_window.h" | |
| 20 #include "content/public/browser/notification_service.h" | |
| 21 #include "extensions/browser/extension_system.h" | |
| 22 | |
| 23 #if defined(OS_CHROMEOS) | |
| 24 #include "chrome/browser/chromeos/login/user_manager.h" | |
| 25 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 26 #include "chromeos/dbus/power_manager_client.h" | |
| 27 #endif | |
| 28 | |
| 29 using extensions::Extension; | |
| 30 using extensions::ExtensionSystem; | |
| 31 using extensions::ExtensionUpdater; | |
| 32 using extensions::RuntimeAPI; | |
| 33 | |
| 34 using extensions::core_api::runtime::GetPlatformInfo::Results::PlatformInfo; | |
| 35 | |
| 36 namespace { | |
| 37 | |
| 38 const char kUpdatesDisabledError[] = "Autoupdate is not enabled."; | |
| 39 | |
| 40 const char kUpdateThrottled[] = "throttled"; | |
| 41 const char kUpdateNotFound[] = "no_update"; | |
| 42 const char kUpdateFound[] = "update_available"; | |
| 43 | |
| 44 // If an extension reloads itself within this many miliseconds of reloading | |
| 45 // itself, the reload is considered suspiciously fast. | |
| 46 const int kFastReloadTime = 10000; | |
| 47 | |
| 48 // After this many suspiciously fast consecutive reloads, an extension will get | |
| 49 // disabled. | |
| 50 const int kFastReloadCount = 5; | |
| 51 | |
| 52 } // namespace | |
| 53 | |
| 54 ChromeRuntimeAPIDelegate::ChromeRuntimeAPIDelegate( | |
| 55 content::BrowserContext* context) | |
| 56 : browser_context_(context), registered_for_updates_(false) { | |
| 57 registrar_.Add(this, | |
| 58 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, | |
| 59 content::NotificationService::AllSources()); | |
| 60 } | |
| 61 | |
| 62 ChromeRuntimeAPIDelegate::~ChromeRuntimeAPIDelegate() { | |
| 63 } | |
| 64 | |
| 65 void ChromeRuntimeAPIDelegate::RegisterUpdateObserver( | |
|
not at google - send to devlin
2014/05/05 19:26:15
why is this called "RegisterUpdateObserver" while
Ken Rockot(use gerrit already)
2014/05/05 21:08:07
I don't have a good answer. Changed.
| |
| 66 extensions::UpdateObserver* observer) { | |
| 67 registered_for_updates_ = true; | |
| 68 ExtensionSystem::Get(browser_context_) | |
| 69 ->extension_service() | |
| 70 ->AddUpdateObserver(observer); | |
| 71 } | |
| 72 | |
| 73 void ChromeRuntimeAPIDelegate::UnregisterUpdateObserver( | |
| 74 extensions::UpdateObserver* observer) { | |
| 75 if (registered_for_updates_) { | |
| 76 ExtensionSystem::Get(browser_context_) | |
| 77 ->extension_service() | |
| 78 ->RemoveUpdateObserver(observer); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 base::Version ChromeRuntimeAPIDelegate::GetOldExtensionVersion( | |
| 83 const Extension* extension) { | |
| 84 // Get the previous version to check if this is an upgrade. | |
| 85 ExtensionService* service = | |
| 86 ExtensionSystem::Get(browser_context_)->extension_service(); | |
| 87 const Extension* old = service->GetExtensionById(extension->id(), true); | |
| 88 if (old) | |
| 89 return *old->version(); | |
| 90 return base::Version(); | |
| 91 } | |
| 92 | |
| 93 void ChromeRuntimeAPIDelegate::MaybeReloadExtension( | |
| 94 const std::string& extension_id) { | |
| 95 std::pair<base::TimeTicks, int>& reload_info = | |
| 96 last_reload_time_[extension_id]; | |
| 97 base::TimeTicks now = base::TimeTicks::Now(); | |
| 98 if (reload_info.first.is_null() || | |
| 99 (now - reload_info.first).InMilliseconds() > kFastReloadTime) { | |
| 100 reload_info.second = 0; | |
| 101 } else { | |
| 102 reload_info.second++; | |
| 103 } | |
| 104 if (!reload_info.first.is_null()) { | |
| 105 UMA_HISTOGRAM_LONG_TIMES("Extensions.RuntimeReloadTime", | |
| 106 now - reload_info.first); | |
| 107 } | |
| 108 UMA_HISTOGRAM_COUNTS_100("Extensions.RuntimeReloadFastCount", | |
| 109 reload_info.second); | |
| 110 reload_info.first = now; | |
| 111 | |
| 112 ExtensionService* service = | |
| 113 ExtensionSystem::Get(browser_context_)->extension_service(); | |
| 114 if (reload_info.second >= kFastReloadCount) { | |
| 115 // Unloading an extension clears all warnings, so first terminate the | |
| 116 // extension, and then add the warning. Since this is called from an | |
| 117 // extension function unloading the extension has to be done | |
| 118 // asynchronously. Fortunately PostTask guarentees FIFO order so just | |
| 119 // post both tasks. | |
| 120 base::MessageLoop::current()->PostTask( | |
| 121 FROM_HERE, | |
| 122 base::Bind(&ExtensionService::TerminateExtension, | |
| 123 service->AsWeakPtr(), | |
| 124 extension_id)); | |
| 125 extensions::ExtensionWarningSet warnings; | |
| 126 warnings.insert( | |
| 127 extensions::ExtensionWarning::CreateReloadTooFrequentWarning( | |
| 128 extension_id)); | |
| 129 base::MessageLoop::current()->PostTask( | |
| 130 FROM_HERE, | |
| 131 base::Bind(&extensions::ExtensionWarningService::NotifyWarningsOnUI, | |
| 132 browser_context_, | |
| 133 warnings)); | |
| 134 } else { | |
| 135 // We can't call ReloadExtension directly, since when this method finishes | |
| 136 // it tries to decrease the reference count for the extension, which fails | |
| 137 // if the extension has already been reloaded; so instead we post a task. | |
| 138 base::MessageLoop::current()->PostTask( | |
| 139 FROM_HERE, | |
| 140 base::Bind(&ExtensionService::ReloadExtension, | |
| 141 service->AsWeakPtr(), | |
| 142 extension_id)); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 bool ChromeRuntimeAPIDelegate::RequestUpdateCheck( | |
| 147 const std::string& extension_id, | |
| 148 const RuntimeAPI::UpdateCheckCallback& callback) { | |
| 149 ExtensionSystem* system = ExtensionSystem::Get(browser_context_); | |
| 150 ExtensionService* service = system->extension_service(); | |
| 151 ExtensionUpdater* updater = service->updater(); | |
| 152 if (!updater) { | |
| 153 return false; | |
| 154 } | |
| 155 if (!updater->CheckExtensionSoon( | |
| 156 extension_id, | |
| 157 base::Bind(&ChromeRuntimeAPIDelegate::UpdateCheckComplete, | |
| 158 base::Unretained(this), | |
| 159 extension_id))) { | |
| 160 base::MessageLoop::current()->PostTask( | |
| 161 FROM_HERE, | |
| 162 base::Bind(callback, | |
| 163 RuntimeAPI::UpdateCheckResult(true, kUpdateThrottled, ""))); | |
| 164 } else { | |
| 165 UpdateCallbackList& callbacks = pending_update_checks_[extension_id]; | |
| 166 callbacks.push_back(callback); | |
| 167 } | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 void ChromeRuntimeAPIDelegate::HandleUninstall(const std::string& extension_id, | |
| 172 const GURL& uninstall_url) { | |
| 173 Profile* profile = Profile::FromBrowserContext(browser_context_); | |
| 174 Browser* browser = | |
| 175 chrome::FindLastActiveWithProfile(profile, chrome::GetActiveDesktop()); | |
| 176 if (!browser) | |
| 177 browser = | |
| 178 new Browser(Browser::CreateParams(profile, chrome::GetActiveDesktop())); | |
| 179 | |
| 180 chrome::NavigateParams params( | |
| 181 browser, uninstall_url, content::PAGE_TRANSITION_CLIENT_REDIRECT); | |
| 182 params.disposition = NEW_FOREGROUND_TAB; | |
| 183 params.user_gesture = false; | |
| 184 chrome::Navigate(¶ms); | |
| 185 } | |
| 186 | |
| 187 bool ChromeRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { | |
| 188 const char* os = chrome::OmahaQueryParams::GetOS(); | |
| 189 if (strcmp(os, "mac") == 0) { | |
| 190 info->os = PlatformInfo::OS_MAC_; | |
| 191 } else if (strcmp(os, "win") == 0) { | |
| 192 info->os = PlatformInfo::OS_WIN_; | |
| 193 } else if (strcmp(os, "android") == 0) { | |
| 194 info->os = PlatformInfo::OS_ANDROID_; | |
| 195 } else if (strcmp(os, "cros") == 0) { | |
| 196 info->os = PlatformInfo::OS_CROS_; | |
| 197 } else if (strcmp(os, "linux") == 0) { | |
| 198 info->os = PlatformInfo::OS_LINUX_; | |
| 199 } else if (strcmp(os, "openbsd") == 0) { | |
| 200 info->os = PlatformInfo::OS_OPENBSD_; | |
| 201 } else { | |
| 202 NOTREACHED(); | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 const char* arch = chrome::OmahaQueryParams::GetArch(); | |
| 207 if (strcmp(arch, "arm") == 0) { | |
| 208 info->arch = PlatformInfo::ARCH_ARM; | |
| 209 } else if (strcmp(arch, "x86") == 0) { | |
| 210 info->arch = PlatformInfo::ARCH_X86_32; | |
| 211 } else if (strcmp(arch, "x64") == 0) { | |
| 212 info->arch = PlatformInfo::ARCH_X86_64; | |
| 213 } else { | |
| 214 NOTREACHED(); | |
| 215 return false; | |
| 216 } | |
| 217 | |
| 218 const char* nacl_arch = chrome::OmahaQueryParams::GetNaclArch(); | |
| 219 if (strcmp(nacl_arch, "arm") == 0) { | |
| 220 info->nacl_arch = PlatformInfo::NACL_ARCH_ARM; | |
| 221 } else if (strcmp(nacl_arch, "x86-32") == 0) { | |
| 222 info->nacl_arch = PlatformInfo::NACL_ARCH_X86_32; | |
| 223 } else if (strcmp(nacl_arch, "x86-64") == 0) { | |
| 224 info->nacl_arch = PlatformInfo::NACL_ARCH_X86_64; | |
| 225 } else { | |
| 226 NOTREACHED(); | |
| 227 return false; | |
| 228 } | |
| 229 | |
| 230 return true; | |
| 231 } | |
| 232 | |
| 233 bool ChromeRuntimeAPIDelegate::RequestRestart(std::string* error_message) { | |
| 234 #if defined(OS_CHROMEOS) | |
| 235 if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) { | |
| 236 chromeos::DBusThreadManager::Get() | |
| 237 ->GetPowerManagerClient() | |
| 238 ->RequestRestart(); | |
| 239 return true; | |
| 240 } | |
| 241 #endif | |
| 242 *error_message = "Function available only for ChromeOS kiosk mode."; | |
| 243 return false; | |
| 244 } | |
| 245 | |
| 246 void ChromeRuntimeAPIDelegate::Observe( | |
| 247 int type, | |
| 248 const content::NotificationSource& source, | |
| 249 const content::NotificationDetails& details) { | |
| 250 DCHECK(type == chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND); | |
| 251 typedef const std::pair<std::string, Version> UpdateDetails; | |
| 252 const std::string& id = content::Details<UpdateDetails>(details)->first; | |
| 253 const Version& version = content::Details<UpdateDetails>(details)->second; | |
| 254 CallUpdateCallbacks( | |
| 255 id, | |
| 256 RuntimeAPI::UpdateCheckResult(true, kUpdateFound, version.GetString())); | |
| 257 } | |
| 258 | |
| 259 void ChromeRuntimeAPIDelegate::UpdateCheckComplete( | |
| 260 const std::string& extension_id) { | |
| 261 ExtensionSystem* system = ExtensionSystem::Get(browser_context_); | |
| 262 ExtensionService* service = system->extension_service(); | |
| 263 const Extension* update = service->GetPendingExtensionUpdate(extension_id); | |
| 264 if (update) { | |
| 265 CallUpdateCallbacks(extension_id, | |
| 266 RuntimeAPI::UpdateCheckResult( | |
| 267 true, kUpdateFound, update->VersionString())); | |
| 268 } else { | |
| 269 CallUpdateCallbacks( | |
| 270 extension_id, RuntimeAPI::UpdateCheckResult(true, kUpdateNotFound, "")); | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 void ChromeRuntimeAPIDelegate::CallUpdateCallbacks( | |
| 275 const std::string& extension_id, | |
| 276 const RuntimeAPI::UpdateCheckResult& result) { | |
| 277 UpdateCallbackList callbacks = pending_update_checks_[extension_id]; | |
| 278 pending_update_checks_.erase(extension_id); | |
| 279 for (UpdateCallbackList::const_iterator iter = callbacks.begin(); | |
| 280 iter != callbacks.end(); | |
| 281 ++iter) { | |
| 282 const RuntimeAPI::UpdateCheckCallback& callback = *iter; | |
| 283 callback.Run(result); | |
| 284 } | |
| 285 } | |
| OLD | NEW |