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

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

Issue 8417012: Refactor loading out of ExtensionService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: components Created 9 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/installed_loader.h"
6
7 #include "base/file_path.h"
8 #include "base/metrics/histogram.h"
9 #include "base/stringprintf.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/extensions/extension_prefs.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_file_util.h"
17 #include "chrome/common/extensions/extension_l10n_util.h"
18 #include "chrome/common/pref_names.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/browser/user_metrics.h"
21
22 namespace errors = extension_manifest_errors;
23
24 namespace {
25
26 // The following enumeration is used in histograms matching
27 // Extensions.ManifestReload* . Values may be added, as long as existing
28 // values are not changed.
29 enum ManifestReloadReason {
30 NOT_NEEDED = 0, // Reload not needed.
31 UNPACKED_DIR, // Unpacked directory.
32 NEEDS_RELOCALIZATION, // The locale has changed since we read this extension.
33 NUM_MANIFEST_RELOAD_REASONS
34 };
35
36 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
37 // Always reload manifests of unpacked extensions, because they can change
38 // on disk independent of the manifest in our prefs.
39 if (info.extension_location == Extension::LOAD)
40 return UNPACKED_DIR;
41
42 // Reload the manifest if it needs to be relocalized.
43 if (extension_l10n_util::ShouldRelocalizeManifest(info))
44 return NEEDS_RELOCALIZATION;
45
46 return NOT_NEEDED;
47 }
48
49 } // namespace
50
51 namespace extensions {
52
53 InstalledLoader::InstalledLoader(ExtensionService* extension_service)
54 : extension_service_(extension_service),
55 extension_prefs_(extension_service->extension_prefs()) {
56 }
57
58 InstalledLoader::~InstalledLoader() {
59 }
60
61 void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
62 std::string error;
63 scoped_refptr<const Extension> extension(NULL);
64 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
65 error = errors::kDisabledByPolicy;
66 } else if (info.extension_manifest.get()) {
67 extension = Extension::Create(
68 info.extension_path,
69 info.extension_location,
70 *info.extension_manifest,
71 GetCreationFlags(&info),
72 &error);
73 } else {
74 error = errors::kManifestUnreadable;
75 }
76
77 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
78 // updating the 'key' field in their manifest).
79 if (extension &&
80 extension->location() != Extension::LOAD &&
81 info.extension_id != extension->id()) {
82 error = errors::kCannotChangeExtensionID;
83 extension = NULL;
84 UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
85 }
86
87 if (!extension) {
88 extension_service_->
89 ReportExtensionLoadError(info.extension_path, error, false);
90 return;
91 }
92
93 if (write_to_prefs)
94 extension_prefs_->UpdateManifest(extension);
95
96 extension_service_->AddExtension(extension);
97 }
98
99 void InstalledLoader::LoadAllExtensions() {
100 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101
102 base::TimeTicks start_time = base::TimeTicks::Now();
103
104 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
105 extension_prefs_->GetInstalledExtensionsInfo());
106
107 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
108 bool should_write_prefs = false;
109
110 for (size_t i = 0; i < extensions_info->size(); ++i) {
111 ExtensionInfo* info = extensions_info->at(i).get();
112
113 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
114 ++reload_reason_counts[reload_reason];
115 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
116 reload_reason, 100);
117
118 if (reload_reason != NOT_NEEDED) {
119 // Reloading an extension reads files from disk. We do this on the
120 // UI thread because reloads should be very rare, and the complexity
121 // added by delaying the time when the extensions service knows about
122 // all extensions is significant. See crbug.com/37548 for details.
123 // |allow_io| disables tests that file operations run on the file
124 // thread.
125 base::ThreadRestrictions::ScopedAllowIO allow_io;
126
127 std::string error;
128 scoped_refptr<const Extension> extension(
129 extension_file_util::LoadExtension(
130 info->extension_path,
131 info->extension_location,
132 GetCreationFlags(info),
133 &error));
134
135 if (extension.get()) {
136 extensions_info->at(i)->extension_manifest.reset(
137 static_cast<DictionaryValue*>(
138 extension->manifest_value()->DeepCopy()));
139 should_write_prefs = true;
140 }
141 }
142 }
143
144 for (size_t i = 0; i < extensions_info->size(); ++i) {
145 Load(*extensions_info->at(i), should_write_prefs);
146 }
147
148 extension_service_->OnLoadedInstalledExtensions();
149
150 // The histograms Extensions.ManifestReload* allow us to validate
151 // the assumption that reloading manifest is a rare event.
152 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
153 reload_reason_counts[NOT_NEEDED]);
154 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
155 reload_reason_counts[UNPACKED_DIR]);
156 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
157 reload_reason_counts[NEEDS_RELOCALIZATION]);
158
159 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
160 extension_service_->extensions()->size());
161 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
162 extension_service_->disabled_extensions()->size());
163
164 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
165 base::TimeTicks::Now() - start_time);
166
167 int app_user_count = 0;
168 int app_external_count = 0;
169 int hosted_app_count = 0;
170 int packaged_app_count = 0;
171 int user_script_count = 0;
172 int extension_user_count = 0;
173 int extension_external_count = 0;
174 int theme_count = 0;
175 int page_action_count = 0;
176 int browser_action_count = 0;
177 const ExtensionList* extensions = extension_service_->extensions();
178 ExtensionList::const_iterator ex;
179 for (ex = extensions->begin(); ex != extensions->end(); ++ex) {
180 Extension::Location location = (*ex)->location();
181 Extension::Type type = (*ex)->GetType();
182 if ((*ex)->is_app()) {
183 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
184 location, 100);
185 } else if (type == Extension::TYPE_EXTENSION) {
186 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
187 location, 100);
188 }
189
190 // Don't count component extensions, since they are only extensions as an
191 // implementation detail.
192 if (location == Extension::COMPONENT)
193 continue;
194
195 // Don't count unpacked extensions, since they're a developer-specific
196 // feature.
197 if (location == Extension::LOAD)
198 continue;
199
200 // Using an enumeration shows us the total installed ratio across all users.
201 // Using the totals per user at each startup tells us the distribution of
202 // usage for each user (e.g. 40% of users have at least one app installed).
203 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
204 switch (type) {
205 case Extension::TYPE_THEME:
206 ++theme_count;
207 break;
208 case Extension::TYPE_USER_SCRIPT:
209 ++user_script_count;
210 break;
211 case Extension::TYPE_HOSTED_APP:
212 ++hosted_app_count;
213 if (Extension::IsExternalLocation(location)) {
214 ++app_external_count;
215 } else {
216 ++app_user_count;
217 }
218 break;
219 case Extension::TYPE_PACKAGED_APP:
220 ++packaged_app_count;
221 if (Extension::IsExternalLocation(location)) {
222 ++app_external_count;
223 } else {
224 ++app_user_count;
225 }
226 break;
227 case Extension::TYPE_EXTENSION:
228 default:
229 if (Extension::IsExternalLocation(location)) {
230 ++extension_external_count;
231 } else {
232 ++extension_user_count;
233 }
234 break;
235 }
236 if ((*ex)->page_action() != NULL)
237 ++page_action_count;
238 if ((*ex)->browser_action() != NULL)
239 ++browser_action_count;
240
241 extension_service_->RecordPermissionMessagesHistogram(
242 ex->get(), "Extensions.Permissions_Load");
243 }
244 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
245 app_user_count + app_external_count);
246 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
247 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
248 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
249 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
250 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
251 extension_user_count + extension_external_count);
252 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
253 extension_user_count);
254 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
255 extension_external_count);
256 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
257 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
258 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
259 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
260 browser_action_count);
261 }
262
263 int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
264 int flags = Extension::NO_FLAGS;
265 if (info->extension_location != Extension::LOAD)
266 flags |= Extension::REQUIRE_KEY;
267 if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
268 flags |= Extension::STRICT_ERROR_CHECKS;
269 if (extension_prefs_->AllowFileAccess(info->extension_id))
270 flags |= Extension::ALLOW_FILE_ACCESS;
271 if (extension_prefs_->IsFromWebStore(info->extension_id))
272 flags |= Extension::FROM_WEBSTORE;
273 if (extension_prefs_->IsFromBookmark(info->extension_id))
274 flags |= Extension::FROM_BOOKMARK;
275 return flags;
276 }
277
278 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698