- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / external_registry_loader_win.cc
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.
4
5 #include "chrome/browser/extensions/external_registry_loader_win.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/memory/scoped_handle.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "base/version.h"
17 #include "base/win/registry.h"
18 #include "chrome/browser/extensions/external_provider_impl.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "content/public/browser/browser_thread.h"
21
22 using content::BrowserThread;
23
24 namespace {
25
26 // The Registry subkey that contains information about external extensions.
27 const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions";
28
29 // Registry value of of that key that defines the path to the .crx file.
30 const wchar_t kRegistryExtensionPath[] = L"path";
31
32 // Registry value of that key that defines the current version of the .crx file.
33 const wchar_t kRegistryExtensionVersion[] = L"version";
34
35 bool CanOpenFileForReading(const base::FilePath& path) {
36   ScopedStdioHandle file_handle(file_util::OpenFile(path, "rb"));
37   return file_handle.get() != NULL;
38 }
39
40 }  // namespace
41
42 namespace extensions {
43
44 void ExternalRegistryLoader::StartLoading() {
45   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
46   BrowserThread::PostTask(
47       BrowserThread::FILE, FROM_HERE,
48       base::Bind(&ExternalRegistryLoader::LoadOnFileThread, this));
49 }
50
51 void ExternalRegistryLoader::LoadOnFileThread() {
52   CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
53   base::TimeTicks start_time = base::TimeTicks::Now();
54   scoped_ptr<DictionaryValue> prefs(new DictionaryValue);
55
56   // A map of IDs, to weed out duplicates between HKCU and HKLM.
57   std::set<string16> keys;
58   base::win::RegistryKeyIterator iterator_machine_key(
59       HKEY_LOCAL_MACHINE, ASCIIToWide(kRegistryExtensions).c_str());
60   for (; iterator_machine_key.Valid(); ++iterator_machine_key)
61     keys.insert(iterator_machine_key.Name());
62   base::win::RegistryKeyIterator iterator_user_key(
63       HKEY_CURRENT_USER, ASCIIToWide(kRegistryExtensions).c_str());
64   for (; iterator_user_key.Valid(); ++iterator_user_key)
65     keys.insert(iterator_user_key.Name());
66
67   // Iterate over the keys found, first trying HKLM, then HKCU, as per Windows
68   // policy conventions. We only fall back to HKCU if the HKLM key cannot be
69   // opened, not if the data within the key is invalid, for example.
70   for (std::set<string16>::const_iterator it = keys.begin();
71        it != keys.end(); ++it) {
72     base::win::RegKey key;
73     string16 key_path = ASCIIToWide(kRegistryExtensions);
74     key_path.append(L"\\");
75     key_path.append(*it);
76     if (key.Open(HKEY_LOCAL_MACHINE,
77                  key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
78       if (key.Open(HKEY_CURRENT_USER,
79                    key_path.c_str(), KEY_READ) != ERROR_SUCCESS) {
80         LOG(ERROR) << "Unable to read registry key at path (HKLM & HKCU): "
81                    << key_path << ".";
82         continue;
83       }
84     }
85
86     string16 extension_path_str;
87     if (key.ReadValue(kRegistryExtensionPath, &extension_path_str)
88         != ERROR_SUCCESS) {
89       // TODO(erikkay): find a way to get this into about:extensions
90       LOG(ERROR) << "Missing value " << kRegistryExtensionPath
91                  << " for key " << key_path << ".";
92       continue;
93     }
94
95     base::FilePath extension_path(extension_path_str);
96     if (!extension_path.IsAbsolute()) {
97       LOG(ERROR) << "File path " << extension_path_str
98                  << " needs to be absolute in key "
99                  << key_path;
100       continue;
101     }
102
103     if (!base::PathExists(extension_path)) {
104       LOG(ERROR) << "File " << extension_path_str
105                  << " for key " << key_path
106                  << " does not exist or is not readable.";
107       continue;
108     }
109
110     if (!CanOpenFileForReading(extension_path)) {
111       LOG(ERROR) << "File " << extension_path_str
112                  << " for key " << key_path << " can not be read. "
113                  << "Check that users who should have the extension "
114                  << "installed have permission to read it.";
115       continue;
116     }
117
118     string16 extension_version;
119     if (key.ReadValue(kRegistryExtensionVersion, &extension_version)
120         != ERROR_SUCCESS) {
121       // TODO(erikkay): find a way to get this into about:extensions
122       LOG(ERROR) << "Missing value " << kRegistryExtensionVersion
123                  << " for key " << key_path << ".";
124       continue;
125     }
126
127     std::string id = WideToASCII(*it);
128     StringToLowerASCII(&id);
129     if (!Extension::IdIsValid(id)) {
130       LOG(ERROR) << "Invalid id value " << id
131                  << " for key " << key_path << ".";
132       continue;
133     }
134
135     Version version(WideToASCII(extension_version));
136     if (!version.IsValid()) {
137       LOG(ERROR) << "Invalid version value " << extension_version
138                  << " for key " << key_path << ".";
139       continue;
140     }
141
142     prefs->SetString(
143         id + "." + ExternalProviderImpl::kExternalVersion,
144         WideToASCII(extension_version));
145     prefs->SetString(
146         id + "." + ExternalProviderImpl::kExternalCrx,
147         extension_path_str);
148   }
149
150   prefs_.reset(prefs.release());
151   HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
152                   base::TimeTicks::Now() - start_time);
153   BrowserThread::PostTask(
154       BrowserThread::UI, FROM_HERE,
155       base::Bind(&ExternalRegistryLoader::LoadFinished, this));
156 }
157
158 }  // namespace extensions