Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(614)

Side by Side Diff: chrome/browser/extensions/extension_service.cc

Issue 1495403002: Observe adding external extensions via windows registry. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sync @tott Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 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/extensions/extension_service.h" 5 #include "chrome/browser/extensions/extension_service.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <iterator> 10 #include <iterator>
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 #include "content/public/browser/notification_service.h" 67 #include "content/public/browser/notification_service.h"
68 #include "content/public/browser/render_process_host.h" 68 #include "content/public/browser/render_process_host.h"
69 #include "content/public/browser/storage_partition.h" 69 #include "content/public/browser/storage_partition.h"
70 #include "extensions/browser/app_sorting.h" 70 #include "extensions/browser/app_sorting.h"
71 #include "extensions/browser/event_router.h" 71 #include "extensions/browser/event_router.h"
72 #include "extensions/browser/extension_host.h" 72 #include "extensions/browser/extension_host.h"
73 #include "extensions/browser/extension_prefs.h" 73 #include "extensions/browser/extension_prefs.h"
74 #include "extensions/browser/extension_registry.h" 74 #include "extensions/browser/extension_registry.h"
75 #include "extensions/browser/extension_system.h" 75 #include "extensions/browser/extension_system.h"
76 #include "extensions/browser/extensions_browser_client.h" 76 #include "extensions/browser/extensions_browser_client.h"
77 #include "extensions/browser/external_install_info.h"
77 #include "extensions/browser/install_flag.h" 78 #include "extensions/browser/install_flag.h"
78 #include "extensions/browser/runtime_data.h" 79 #include "extensions/browser/runtime_data.h"
79 #include "extensions/browser/uninstall_reason.h" 80 #include "extensions/browser/uninstall_reason.h"
80 #include "extensions/browser/update_observer.h" 81 #include "extensions/browser/update_observer.h"
81 #include "extensions/browser/updater/extension_cache.h" 82 #include "extensions/browser/updater/extension_cache.h"
82 #include "extensions/browser/updater/extension_downloader.h" 83 #include "extensions/browser/updater/extension_downloader.h"
83 #include "extensions/common/extension_messages.h" 84 #include "extensions/common/extension_messages.h"
84 #include "extensions/common/extension_urls.h" 85 #include "extensions/common/extension_urls.h"
85 #include "extensions/common/feature_switch.h" 86 #include "extensions/common/feature_switch.h"
86 #include "extensions/common/file_util.h" 87 #include "extensions/common/file_util.h"
(...skipping 20 matching lines...) Expand all
107 using content::BrowserThread; 108 using content::BrowserThread;
108 using content::DevToolsAgentHost; 109 using content::DevToolsAgentHost;
109 using extensions::APIPermission; 110 using extensions::APIPermission;
110 using extensions::AppSorting; 111 using extensions::AppSorting;
111 using extensions::CrxInstaller; 112 using extensions::CrxInstaller;
112 using extensions::Extension; 113 using extensions::Extension;
113 using extensions::ExtensionIdSet; 114 using extensions::ExtensionIdSet;
114 using extensions::ExtensionInfo; 115 using extensions::ExtensionInfo;
115 using extensions::ExtensionRegistry; 116 using extensions::ExtensionRegistry;
116 using extensions::ExtensionSet; 117 using extensions::ExtensionSet;
118 using extensions::ExternalInstallInfoFile;
119 using extensions::ExternalInstallInfoUpdateUrl;
120 using extensions::ExternalProviderInterface;
117 using extensions::FeatureSwitch; 121 using extensions::FeatureSwitch;
118 using extensions::InstallVerifier; 122 using extensions::InstallVerifier;
119 using extensions::ManagementPolicy; 123 using extensions::ManagementPolicy;
120 using extensions::Manifest; 124 using extensions::Manifest;
121 using extensions::PermissionID; 125 using extensions::PermissionID;
122 using extensions::PermissionIDSet; 126 using extensions::PermissionIDSet;
123 using extensions::PermissionSet; 127 using extensions::PermissionSet;
124 using extensions::SharedModuleInfo; 128 using extensions::SharedModuleInfo;
125 using extensions::SharedModuleService; 129 using extensions::SharedModuleService;
126 using extensions::UnloadedExtensionInfo; 130 using extensions::UnloadedExtensionInfo;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 void ExtensionService::SetFileTaskRunnerForTesting( 171 void ExtensionService::SetFileTaskRunnerForTesting(
168 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { 172 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
169 file_task_runner_ = task_runner; 173 file_task_runner_ = task_runner;
170 } 174 }
171 175
172 void ExtensionService::ClearProvidersForTesting() { 176 void ExtensionService::ClearProvidersForTesting() {
173 external_extension_providers_.clear(); 177 external_extension_providers_.clear();
174 } 178 }
175 179
176 void ExtensionService::AddProviderForTesting( 180 void ExtensionService::AddProviderForTesting(
177 extensions::ExternalProviderInterface* test_provider) { 181 ExternalProviderInterface* test_provider) {
178 CHECK(test_provider); 182 CHECK(test_provider);
179 external_extension_providers_.push_back( 183 external_extension_providers_.push_back(
180 linked_ptr<extensions::ExternalProviderInterface>(test_provider)); 184 linked_ptr<ExternalProviderInterface>(test_provider));
181 } 185 }
182 186
183 void ExtensionService::BlacklistExtensionForTest( 187 void ExtensionService::BlacklistExtensionForTest(
184 const std::string& extension_id) { 188 const std::string& extension_id) {
185 ExtensionIdSet blacklisted; 189 ExtensionIdSet blacklisted;
186 ExtensionIdSet unchanged; 190 ExtensionIdSet unchanged;
187 blacklisted.insert(extension_id); 191 blacklisted.insert(extension_id);
188 UpdateBlacklistedExtensions(blacklisted, unchanged); 192 UpdateBlacklistedExtensions(blacklisted, unchanged);
189 } 193 }
190 194
191 bool ExtensionService::OnExternalExtensionUpdateUrlFound( 195 bool ExtensionService::OnExternalExtensionUpdateUrlFound(
192 const std::string& id, 196 const ExternalInstallInfoUpdateUrl& info,
193 const std::string& install_parameter, 197 bool is_initial_load) {
194 const GURL& update_url,
195 Manifest::Location location,
196 int creation_flags,
197 bool mark_acknowledged) {
198 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
199 CHECK(crx_file::id_util::IdIsValid(id)); 199 CHECK(crx_file::id_util::IdIsValid(info.extension_id));
200 200
201 if (Manifest::IsExternalLocation(location)) { 201 if (Manifest::IsExternalLocation(info.download_location)) {
202 // All extensions that are not user specific can be cached. 202 // All extensions that are not user specific can be cached.
203 extensions::ExtensionsBrowserClient::Get()->GetExtensionCache() 203 extensions::ExtensionsBrowserClient::Get()
204 ->AllowCaching(id); 204 ->GetExtensionCache()
205 ->AllowCaching(info.extension_id);
205 } 206 }
206 207
207 const Extension* extension = GetExtensionById(id, true); 208 const Extension* extension = GetExtensionById(info.extension_id, true);
208 if (extension) { 209 if (extension) {
209 // Already installed. Skip this install if the current location has 210 // Already installed. Skip this install if the current location has
210 // higher priority than |location|. 211 // higher priority than |info.download_location|.
211 Manifest::Location current = extension->location(); 212 Manifest::Location current = extension->location();
212 if (current == Manifest::GetHigherPriorityLocation(current, location)) 213 if (current ==
214 Manifest::GetHigherPriorityLocation(current, info.download_location)) {
213 return false; 215 return false;
216 }
214 // Otherwise, overwrite the current installation. 217 // Otherwise, overwrite the current installation.
215 } 218 }
216 219
217 // Add |id| to the set of pending extensions. If it can not be added, 220 // Add |info.extension_id| to the set of pending extensions. If it can not
218 // then there is already a pending record from a higher-priority install 221 // be added, then there is already a pending record from a higher-priority
219 // source. In this case, signal that this extension will not be 222 // install source. In this case, signal that this extension will not be
220 // installed by returning false. 223 // installed by returning false.
221 if (!pending_extension_manager()->AddFromExternalUpdateUrl( 224 if (!pending_extension_manager()->AddFromExternalUpdateUrl(
222 id, 225 info.extension_id, info.install_parameter, *info.update_url,
223 install_parameter, 226 info.download_location, info.creation_flags,
224 update_url, 227 info.mark_acknowledged)) {
225 location,
226 creation_flags,
227 mark_acknowledged)) {
228 return false; 228 return false;
229 } 229 }
230 230
231 update_once_all_providers_are_ready_ = true; 231 if (is_initial_load)
232 update_once_all_providers_are_ready_ = true;
232 return true; 233 return true;
233 } 234 }
234 235
236 void ExtensionService::OnExternalProviderUpdateComplete(
237 const ExternalProviderInterface* provider,
238 const ScopedVector<ExternalInstallInfoUpdateUrl>& update_url_extensions,
239 const ScopedVector<ExternalInstallInfoFile>& file_extensions,
240 const std::set<std::string>& removed_extensions) {
241 // Update pending_extension_manager() with the new extensions first.
242 for (const auto& extension : update_url_extensions)
243 OnExternalExtensionUpdateUrlFound(*extension, false);
244 for (const auto& extension : file_extensions)
245 OnExternalExtensionFileFound(*extension);
246
247 #if DCHECK_IS_ON()
248 for (const std::string& id : removed_extensions) {
249 for (const auto& extension : update_url_extensions)
250 DCHECK_NE(id, extension->extension_id);
251 for (const auto& extension : file_extensions)
252 DCHECK_NE(id, extension->extension_id);
253 }
254 #endif
255
256 // Then uninstall before running |updater_|.
257 for (const std::string& id : removed_extensions)
258 CheckExternalUninstall(id);
259
260 if (!update_url_extensions.empty() && updater_) {
261 // Empty params will cause pending extensions to be updated.
262 extensions::ExtensionUpdater::CheckParams empty_params;
263 updater_->CheckNow(empty_params);
264 }
265
266 error_controller_->ShowErrorIfNeeded();
267 external_install_manager_->UpdateExternalExtensionAlert();
268 }
269
235 // static 270 // static
236 // This function is used to uninstall an extension via sync. The LOG statements 271 // This function is used to uninstall an extension via sync. The LOG statements
237 // within this function are used to inform the user if the uninstall cannot be 272 // within this function are used to inform the user if the uninstall cannot be
238 // done. 273 // done.
239 bool ExtensionService::UninstallExtensionHelper( 274 bool ExtensionService::UninstallExtensionHelper(
240 ExtensionService* extensions_service, 275 ExtensionService* extensions_service,
241 const std::string& extension_id, 276 const std::string& extension_id,
242 extensions::UninstallReason reason) { 277 extensions::UninstallReason reason) {
243 // We can't call UninstallExtension with an invalid extension ID. 278 // We can't call UninstallExtension with an invalid extension ID.
244 if (!extensions_service->GetInstalledExtension(extension_id)) { 279 if (!extensions_service->GetInstalledExtension(extension_id)) {
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 return &pending_extension_manager_; 398 return &pending_extension_manager_;
364 } 399 }
365 400
366 ExtensionService::~ExtensionService() { 401 ExtensionService::~ExtensionService() {
367 // No need to unload extensions here because they are profile-scoped, and the 402 // No need to unload extensions here because they are profile-scoped, and the
368 // profile is in the process of being deleted. 403 // profile is in the process of being deleted.
369 404
370 extensions::ProviderCollection::const_iterator i; 405 extensions::ProviderCollection::const_iterator i;
371 for (i = external_extension_providers_.begin(); 406 for (i = external_extension_providers_.begin();
372 i != external_extension_providers_.end(); ++i) { 407 i != external_extension_providers_.end(); ++i) {
373 extensions::ExternalProviderInterface* provider = i->get(); 408 ExternalProviderInterface* provider = i->get();
374 provider->ServiceShutdown(); 409 provider->ServiceShutdown();
375 } 410 }
376 } 411 }
377 412
378 void ExtensionService::Shutdown() { 413 void ExtensionService::Shutdown() {
379 extensions::ExtensionManagementFactory::GetInstance() 414 extensions::ExtensionManagementFactory::GetInstance()
380 ->GetForBrowserContext(profile()) 415 ->GetForBrowserContext(profile())
381 ->RemoveObserver(this); 416 ->RemoveObserver(this);
382 } 417 }
383 418
(...skipping 883 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 // go through the front-end). Extensions that are registered in this 1302 // go through the front-end). Extensions that are registered in this
1268 // way are effectively considered 'pre-bundled', and so implicitly 1303 // way are effectively considered 'pre-bundled', and so implicitly
1269 // trusted. In general, if something has HKLM or filesystem access, 1304 // trusted. In general, if something has HKLM or filesystem access,
1270 // they could install an extension manually themselves anyway. 1305 // they could install an extension manually themselves anyway.
1271 1306
1272 // Ask each external extension provider to give us a call back for each 1307 // Ask each external extension provider to give us a call back for each
1273 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found. 1308 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
1274 extensions::ProviderCollection::const_iterator i; 1309 extensions::ProviderCollection::const_iterator i;
1275 for (i = external_extension_providers_.begin(); 1310 for (i = external_extension_providers_.begin();
1276 i != external_extension_providers_.end(); ++i) { 1311 i != external_extension_providers_.end(); ++i) {
1277 extensions::ExternalProviderInterface* provider = i->get(); 1312 ExternalProviderInterface* provider = i->get();
1278 provider->VisitRegisteredExtension(); 1313 provider->VisitRegisteredExtension();
1279 } 1314 }
1280 1315
1281 // Do any required work that we would have done after completion of all 1316 // Do any required work that we would have done after completion of all
1282 // providers. 1317 // providers.
1283 if (external_extension_providers_.empty()) 1318 if (external_extension_providers_.empty())
1284 OnAllExternalProvidersReady(); 1319 OnAllExternalProvidersReady();
1285 } 1320 }
1286 1321
1287 void ExtensionService::OnExternalProviderReady( 1322 void ExtensionService::OnExternalProviderReady(
1288 const extensions::ExternalProviderInterface* provider) { 1323 const ExternalProviderInterface* provider) {
1289 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1324 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1290 CHECK(provider->IsReady()); 1325 CHECK(provider->IsReady());
1291 1326
1292 // An external provider has finished loading. We only take action 1327 // An external provider has finished loading. We only take action
1293 // if all of them are finished. So we check them first. 1328 // if all of them are finished. So we check them first.
1294 if (AreAllExternalProvidersReady()) 1329 if (AreAllExternalProvidersReady())
1295 OnAllExternalProvidersReady(); 1330 OnAllExternalProvidersReady();
1296 } 1331 }
1297 1332
1298 bool ExtensionService::AreAllExternalProvidersReady() const { 1333 bool ExtensionService::AreAllExternalProvidersReady() const {
(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after
2001 content::Details<const Extension>(extension)); 2036 content::Details<const Extension>(extension));
2002 } 2037 }
2003 } 2038 }
2004 2039
2005 const Extension* ExtensionService::GetInstalledExtension( 2040 const Extension* ExtensionService::GetInstalledExtension(
2006 const std::string& id) const { 2041 const std::string& id) const {
2007 return registry_->GetExtensionById(id, ExtensionRegistry::EVERYTHING); 2042 return registry_->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
2008 } 2043 }
2009 2044
2010 bool ExtensionService::OnExternalExtensionFileFound( 2045 bool ExtensionService::OnExternalExtensionFileFound(
2011 const std::string& id, 2046 const ExternalInstallInfoFile& info) {
2012 const Version* version,
2013 const base::FilePath& path,
2014 Manifest::Location location,
2015 int creation_flags,
2016 bool mark_acknowledged,
2017 bool install_immediately) {
2018 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2047 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2019 CHECK(crx_file::id_util::IdIsValid(id)); 2048 CHECK(crx_file::id_util::IdIsValid(info.extension_id));
2020 if (extension_prefs_->IsExternalExtensionUninstalled(id)) 2049 if (extension_prefs_->IsExternalExtensionUninstalled(info.extension_id))
2021 return false; 2050 return false;
2022 2051
2023 // Before even bothering to unpack, check and see if we already have this 2052 // Before even bothering to unpack, check and see if we already have this
2024 // version. This is important because these extensions are going to get 2053 // version. This is important because these extensions are going to get
2025 // installed on every startup. 2054 // installed on every startup.
2026 const Extension* existing = GetExtensionById(id, true); 2055 const Extension* existing = GetExtensionById(info.extension_id, true);
2027 2056
2028 if (existing) { 2057 if (existing) {
2029 // The default apps will have the location set as INTERNAL. Since older 2058 // The default apps will have the location set as INTERNAL. Since older
2030 // default apps are installed as EXTERNAL, we override them. However, if the 2059 // default apps are installed as EXTERNAL, we override them. However, if the
2031 // app is already installed as internal, then do the version check. 2060 // app is already installed as internal, then do the version check.
2032 // TODO(grv) : Remove after Q1-2013. 2061 // TODO(grv) : Remove after Q1-2013.
2033 bool is_default_apps_migration = 2062 bool is_default_apps_migration =
2034 (location == Manifest::INTERNAL && 2063 (info.crx_location == Manifest::INTERNAL &&
2035 Manifest::IsExternalLocation(existing->location())); 2064 Manifest::IsExternalLocation(existing->location()));
2036 2065
2037 if (!is_default_apps_migration) { 2066 if (!is_default_apps_migration) {
2038 DCHECK(version); 2067 DCHECK(info.version.get());
2039 2068
2040 switch (existing->version()->CompareTo(*version)) { 2069 switch (existing->version()->CompareTo(*info.version)) {
2041 case -1: // existing version is older, we should upgrade 2070 case -1: // existing version is older, we should upgrade
2042 break; 2071 break;
2043 case 0: // existing version is same, do nothing 2072 case 0: // existing version is same, do nothing
2044 return false; 2073 return false;
2045 case 1: // existing version is newer, uh-oh 2074 case 1: // existing version is newer, uh-oh
2046 LOG(WARNING) << "Found external version of extension " << id 2075 LOG(WARNING) << "Found external version of extension "
2076 << info.extension_id
2047 << "that is older than current version. Current version " 2077 << "that is older than current version. Current version "
2048 << "is: " << existing->VersionString() << ". New " 2078 << "is: " << existing->VersionString() << ". New "
2049 << "version is: " << version->GetString() 2079 << "version is: " << info.version->GetString()
2050 << ". Keeping current version."; 2080 << ". Keeping current version.";
2051 return false; 2081 return false;
2052 } 2082 }
2053 } 2083 }
2054 } 2084 }
2055 2085
2056 // If the extension is already pending, don't start an install. 2086 // If the extension is already pending, don't start an install.
2057 if (!pending_extension_manager()->AddFromExternalFile( 2087 if (!pending_extension_manager()->AddFromExternalFile(
2058 id, location, *version, creation_flags, mark_acknowledged)) { 2088 info.extension_id, info.crx_location, *info.version,
2089 info.creation_flags, info.mark_acknowledged)) {
2059 return false; 2090 return false;
2060 } 2091 }
2061 2092
2062 // no client (silent install) 2093 // no client (silent install)
2063 scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(this)); 2094 scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(this));
2064 installer->set_install_source(location); 2095 installer->set_install_source(info.crx_location);
2065 installer->set_expected_id(id); 2096 installer->set_expected_id(info.extension_id);
2066 installer->set_expected_version(*version, 2097 installer->set_expected_version(*info.version,
2067 true /* fail_install_if_unexpected */); 2098 true /* fail_install_if_unexpected */);
2068 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE); 2099 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE);
2069 installer->set_install_immediately(install_immediately); 2100 installer->set_install_immediately(info.install_immediately);
2070 installer->set_creation_flags(creation_flags); 2101 installer->set_creation_flags(info.creation_flags);
2071 #if defined(OS_CHROMEOS) 2102 #if defined(OS_CHROMEOS)
2072 extensions::InstallLimiter::Get(profile_)->Add(installer, path); 2103 extensions::InstallLimiter::Get(profile_)->Add(installer, info.path);
2073 #else 2104 #else
2074 installer->InstallCrx(path); 2105 installer->InstallCrx(info.path);
2075 #endif 2106 #endif
2076 2107
2077 // Depending on the source, a new external extension might not need a user 2108 // Depending on the source, a new external extension might not need a user
2078 // notification on installation. For such extensions, mark them acknowledged 2109 // notification on installation. For such extensions, mark them acknowledged
2079 // now to suppress the notification. 2110 // now to suppress the notification.
2080 if (mark_acknowledged) 2111 if (info.mark_acknowledged)
2081 external_install_manager_->AcknowledgeExternalExtension(id); 2112 external_install_manager_->AcknowledgeExternalExtension(info.extension_id);
2082 2113
2083 return true; 2114 return true;
2084 } 2115 }
2085 2116
2086 void ExtensionService::DidCreateRenderViewForBackgroundPage( 2117 void ExtensionService::DidCreateRenderViewForBackgroundPage(
2087 extensions::ExtensionHost* host) { 2118 extensions::ExtensionHost* host) {
2088 OrphanedDevTools::iterator iter = 2119 OrphanedDevTools::iterator iter =
2089 orphaned_dev_tools_.find(host->extension_id()); 2120 orphaned_dev_tools_.find(host->extension_id());
2090 if (iter == orphaned_dev_tools_.end()) 2121 if (iter == orphaned_dev_tools_.end())
2091 return; 2122 return;
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after
2465 } 2496 }
2466 2497
2467 void ExtensionService::OnProfileDestructionStarted() { 2498 void ExtensionService::OnProfileDestructionStarted() {
2468 ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs(); 2499 ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs();
2469 for (ExtensionIdSet::iterator it = ids_to_unload.begin(); 2500 for (ExtensionIdSet::iterator it = ids_to_unload.begin();
2470 it != ids_to_unload.end(); 2501 it != ids_to_unload.end();
2471 ++it) { 2502 ++it) {
2472 UnloadExtension(*it, UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN); 2503 UnloadExtension(*it, UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN);
2473 } 2504 }
2474 } 2505 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_service.h ('k') | chrome/browser/extensions/extension_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698