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

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

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

Powered by Google App Engine
This is Rietveld 408576698