Extensions cleanup: Merge IsSyncableApp+Extension, ShouldSyncApp+Extension
[chromium-blink-merge.git] / chrome / browser / extensions / external_registry_loader_win.cc
bloba1c289315575b57ee67974c2152b2adfd11a9e1c
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/external_registry_loader_win.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "base/version.h"
18 #include "base/win/registry.h"
19 #include "chrome/browser/extensions/external_provider_impl.h"
20 #include "components/crx_file/id_util.h"
21 #include "content/public/browser/browser_thread.h"
23 using content::BrowserThread;
25 namespace {
27 // The Registry subkey that contains information about external extensions.
28 const base::char16 kRegistryExtensions[] =
29 L"Software\\Google\\Chrome\\Extensions";
31 // Registry value of the key that defines the installation parameter.
32 const base::char16 kRegistryExtensionInstallParam[] = L"install_parameter";
34 // Registry value of the key that defines the path to the .crx file.
35 const base::char16 kRegistryExtensionPath[] = L"path";
37 // Registry value of that key that defines the current version of the .crx file.
38 const base::char16 kRegistryExtensionVersion[] = L"version";
40 // Registry value of the key that defines an external update URL.
41 const base::char16 kRegistryExtensionUpdateUrl[] = L"update_url";
43 bool CanOpenFileForReading(const base::FilePath& path) {
44 base::ScopedFILE file_handle(base::OpenFile(path, "rb"));
45 return file_handle.get() != NULL;
48 std::string MakePrefName(const std::string& extension_id,
49 const std::string& pref_name) {
50 return base::StringPrintf("%s.%s", extension_id.c_str(), pref_name.c_str());
53 } // namespace
55 namespace extensions {
57 void ExternalRegistryLoader::StartLoading() {
58 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 BrowserThread::PostTask(
60 BrowserThread::FILE, FROM_HERE,
61 base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
64 void ExternalRegistryLoader::LoadOnFileThread() {
65 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 base::TimeTicks start_time = base::TimeTicks::Now();
67 scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
69 // A map of IDs, to weed out duplicates between HKCU and HKLM.
70 std::set<base::string16> keys;
71 base::win::RegistryKeyIterator iterator_machine_key(
72 HKEY_LOCAL_MACHINE,
73 kRegistryExtensions,
74 KEY_WOW64_32KEY);
75 for (; iterator_machine_key.Valid(); ++iterator_machine_key)
76 keys.insert(iterator_machine_key.Name());
77 base::win::RegistryKeyIterator iterator_user_key(
78 HKEY_CURRENT_USER, kRegistryExtensions);
79 for (; iterator_user_key.Valid(); ++iterator_user_key)
80 keys.insert(iterator_user_key.Name());
82 // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
83 // policy conventions. We only fall back to HKCU if the HKLM key cannot be
84 // opened, not if the data within the key is invalid, for example.
85 for (std::set<base::string16>::const_iterator it = keys.begin();
86 it != keys.end(); ++it) {
87 base::win::RegKey key;
88 base::string16 key_path = kRegistryExtensions;
89 key_path.append(L"\\");
90 key_path.append(*it);
91 if (key.Open(HKEY_LOCAL_MACHINE,
92 key_path.c_str(),
93 KEY_READ | KEY_WOW64_32KEY) != ERROR_SUCCESS &&
94 key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ) !=
95 ERROR_SUCCESS) {
96 LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
97 << key_path << ".";
98 continue;
101 std::string id = base::UTF16ToASCII(*it);
102 base::StringToLowerASCII(&id);
103 if (!crx_file::id_util::IdIsValid(id)) {
104 LOG(ERROR) << "Invalid id value " << id
105 << " for key " << key_path << ".";
106 continue;
109 base::string16 extension_dist_id;
110 if (key.ReadValue(kRegistryExtensionInstallParam, &extension_dist_id) ==
111 ERROR_SUCCESS) {
112 prefs->SetString(MakePrefName(id, ExternalProviderImpl::kInstallParam),
113 base::UTF16ToASCII(extension_dist_id));
116 // If there is an update URL present, copy it to prefs and ignore
117 // path and version keys for this entry.
118 base::string16 extension_update_url;
119 if (key.ReadValue(kRegistryExtensionUpdateUrl, &extension_update_url)
120 == ERROR_SUCCESS) {
121 prefs->SetString(
122 MakePrefName(id, ExternalProviderImpl::kExternalUpdateUrl),
123 base::UTF16ToASCII(extension_update_url));
124 continue;
127 base::string16 extension_path_str;
128 if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
129 != ERROR_SUCCESS) {
130 // TODO(erikkay): find a way to get this into about:extensions
131 LOG(ERROR) << "Missing value " << kRegistryExtensionPath
132 << " for key " << key_path << ".";
133 continue;
136 base::FilePath extension_path(extension_path_str);
137 if (!extension_path.IsAbsolute()) {
138 LOG(ERROR) << "File path " << extension_path_str
139 << " needs to be absolute in key "
140 << key_path;
141 continue;
144 if (!base::PathExists(extension_path)) {
145 LOG(ERROR) << "File " << extension_path_str
146 << " for key " << key_path
147 << " does not exist or is not readable.";
148 continue;
151 if (!CanOpenFileForReading(extension_path)) {
152 LOG(ERROR) << "File " << extension_path_str
153 << " for key " << key_path << " can not be read. "
154 << "Check that users who should have the extension "
155 << "installed have permission to read it.";
156 continue;
159 base::string16 extension_version;
160 if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
161 != ERROR_SUCCESS) {
162 // TODO(erikkay): find a way to get this into about:extensions
163 LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
164 << " for key " << key_path << ".";
165 continue;
168 Version version(base::UTF16ToASCII(extension_version));
169 if (!version.IsValid()) {
170 LOG(ERROR) << "Invalid version value " << extension_version
171 << " for key " << key_path << ".";
172 continue;
175 prefs->SetString(
176 MakePrefName(id, ExternalProviderImpl::kExternalVersion),
177 base::UTF16ToASCII(extension_version));
178 prefs->SetString(
179 MakePrefName(id, ExternalProviderImpl::kExternalCrx),
180 extension_path_str);
181 prefs->SetBoolean(
182 MakePrefName(id, ExternalProviderImpl::kMayBeUntrusted),
183 true);
186 prefs_.reset(prefs.release());
187 LOCAL_HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
188 base::TimeTicks::Now() - start_time);
189 BrowserThread::PostTask(
190 BrowserThread::UI, FROM_HERE,
191 base::Bind(&ExternalRegistryLoader::LoadFinished, this));
194 } // namespace extensions