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

Side by Side Diff: chrome/browser/component_updater/pnacl/pnacl_component_installer.cc

Issue 8348026: Add a component installer for Portable NaCl. Registration of installer is (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 years 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/component_updater/pnacl/pnacl_component_installer.h"
6
7 #include <string.h>
8
9 #include "base/base_paths.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_path.h"
13 #include "base/file_util.h"
14 #include "base/logging.h"
15 #include "base/path_service.h"
16 #include "base/values.h"
17 #include "base/version.h"
18 #include "build/build_config.h"
19 #include "chrome/browser/component_updater/component_updater_service.h"
20 #include "chrome/common/chrome_paths.h"
21 #include "content/public/browser/browser_thread.h"
22
23 using content::BrowserThread;
24
25 namespace {
26
27 // CRX hash. This corresponds to AppId: emkhcgigkicgidendmffimilfehocheg
28 const uint8 sha256_hash[] = {
29 0x4c, 0xa7, 0x26, 0x86, 0xa8, 0x26, 0x83, 0x4d, 0x3c, 0x55,
30 0x8c, 0x8b, 0x54, 0x7e, 0x27, 0x46, 0xa0, 0xf8, 0xd5, 0x0e, 0xea,
31 0x33, 0x46, 0x6e, 0xab, 0x6c, 0xde, 0xba, 0xc0, 0x91, 0xd4, 0x5e };
32
33 // One of the Pnacl component files, for checking that expected files exist.
34 // TODO(jvoung): perhaps replace this with a list of the expected files in the
35 // manifest.json. Use that to check that everything is unpacked.
36 // However, that would make startup detection even slower (need to check for
37 // more than one file!).
38 const FilePath::CharType kPnaclCompilerFileName[] =
39 FILE_PATH_LITERAL("llc");
40
41 // Name of the Pnacl component specified in the manifest.
42 const char kPnaclManifestName[] = "PNaCl";
43
44 // Name of the Pnacl architecture in the component manifest.
45 // NOTE: this is independent of the Omaha query parameter.
46 // TODO(jvoung): will this pre-processor define work with 64-bit Windows?
47 // NaCl's sel_ldr is 64-bit, but the browser process is 32-bit.
48 // Will the Omaha query do the right thing as well? If it doesn't, will
49 // we need two separate Omaha queries (ouch)?
50 const char kPnaclArch[] =
51 #if defined(ARCH_CPU_X86)
52 "x86-32";
53 #elif defined(ARCH_CPU_X86_64)
54 "x86-64";
55 #elif defined(ARCH_CPU_ARMEL)
56 "arm";
57 #else
58 #error "Unknown Architecture in Pnacl Component Installer."
59 #endif
60
61 // The Pnacl components are in a directory with this name.
62 const FilePath::CharType kPnaclBaseDirectory[] =
63 FILE_PATH_LITERAL("Pnacl");
64
65 // If we don't have Pnacl installed, this is the version we claim.
66 // TODO(jvoung): Is there a way to trick the configurator to ping the server
67 // earlier if there are components that are not yet installed (version 0.0.0.0),
68 // So that they will be available ASAP? Be careful not to hurt startup speed.
69 // Make kNullVersion part of ComponentUpdater in that case, to avoid skew?
70 const char kNullVersion[] = "0.0.0.0";
71
72 // The base directory on Windows looks like:
73 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\.
74 FilePath GetPnaclBaseDirectory() {
75 FilePath result;
76 PathService::Get(chrome::DIR_USER_DATA, &result);
77 return result.Append(kPnaclBaseDirectory);
78 }
79
80 // Pnacl components have the version encoded in the path itself
81 // so we need to enumerate the directories to find the full path.
82 // On success it returns something like:
83 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\0.1.2.3\.
84 //
85 // TODO(jvoung): Does it garbage collect old versions when a new version is
86 // installed? Do we need the architecture in the path too? That is for handling
87 // cases when you share a profile but switch between machine-types (or ignore
88 // that odd case?).
89 bool GetLatestPnaclDirectory(FilePath* result, Version* latest) {
90 *result = GetPnaclBaseDirectory();
91 bool found = false;
92 file_util::FileEnumerator
93 file_enumerator(*result, false, file_util::FileEnumerator::DIRECTORIES);
94 for (FilePath path = file_enumerator.Next(); !path.value().empty();
95 path = file_enumerator.Next()) {
96 Version version(path.BaseName().MaybeAsASCII());
97 if (!version.IsValid())
98 continue;
99 if (version.CompareTo(*latest) > 0) {
100 *latest = version;
101 *result = path;
102 found = true;
103 }
104 }
105 return found;
106 }
107
108 } // namespace
109
110 bool CheckPnaclComponentManifest(base::DictionaryValue* manifest,
111 Version* version_out) {
112 // Make sure we have the right manifest file.
113 std::string name;
114 manifest->GetStringASCII("name", &name);
115 if (name != kPnaclManifestName)
116 return false;
117
118 std::string proposed_version;
119 manifest->GetStringASCII("version", &proposed_version);
120 Version version(proposed_version.c_str());
121 if (!version.IsValid())
122 return false;
123
124 std::string arch;
125 manifest->GetStringASCII("x-pnacl-arch", &arch);
126 if (arch != kPnaclArch)
127 return false;
128
129 *version_out = version;
130 return true;
131 }
132
133 class PnaclComponentInstaller : public ComponentInstaller {
134 public:
135 explicit PnaclComponentInstaller(const Version& version);
136
137 virtual ~PnaclComponentInstaller() {}
138
139 virtual void OnUpdateError(int error) OVERRIDE;
140
141 virtual bool Install(base::DictionaryValue* manifest,
142 const FilePath& unpack_path) OVERRIDE;
143
144 private:
145 Version current_version_;
146 };
147
148 PnaclComponentInstaller::PnaclComponentInstaller(
149 const Version& version) : current_version_(version) {
150 DCHECK(version.IsValid());
151 }
152
153 void PnaclComponentInstaller::OnUpdateError(int error) {
154 NOTREACHED() << "Pnacl update error: " << error;
155 }
156
157 bool PnaclComponentInstaller::Install(base::DictionaryValue* manifest,
158 const FilePath& unpack_path) {
159 Version version;
160 if (!CheckPnaclComponentManifest(manifest, &version))
161 return false;
162 if (current_version_.CompareTo(version) > 0)
163 return false;
164
165 // Make sure that at least one of the compiler files exists.
166 if (!file_util::PathExists(unpack_path.Append(kPnaclCompilerFileName)))
167 return false;
168
169 // Passed the basic tests. Time to install it.
170 FilePath path =
171 GetPnaclBaseDirectory().AppendASCII(version.GetString());
172 if (file_util::PathExists(path))
173 return false;
174 if (!file_util::Move(unpack_path, path))
175 return false;
176
177 // Installation is done. Now tell the rest of chrome (just the path service
178 // for now). TODO(jvoung): we need notifications if someone surfed to a
179 // Pnacl webpage and Pnacl was just installed at this time. They should
180 // then be able to reload the page and retry (or something).
181 // See: http://code.google.com/p/chromium/issues/detail?id=107438
182 current_version_ = version;
183
184 PathService::Override(chrome::FILE_PNACL_COMPONENT, path);
185 return true;
186 }
187
188 namespace {
189
190 // Finally, do the registration with the right version number.
191 void FinishPnaclUpdateRegistration(ComponentUpdateService* cus,
192 const Version& version) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 CrxComponent pnacl;
195 pnacl.name = "pnacl";
196 pnacl.installer = new PnaclComponentInstaller(version);
197 pnacl.version = version;
198 pnacl.pk_hash.assign(sha256_hash, &sha256_hash[sizeof(sha256_hash)]);
199 if (cus->RegisterComponent(pnacl) != ComponentUpdateService::kOk) {
200 NOTREACHED() << "Pnacl component registration failed.";
201 }
202 }
203
204 // Check if there is an existing version on disk first to know when
205 // a hosted version is actually newer.
206 void StartPnaclUpdateRegistration(ComponentUpdateService* cus) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
208 FilePath path = GetPnaclBaseDirectory();
209 if (!file_util::PathExists(path)) {
210 if (!file_util::CreateDirectory(path)) {
211 NOTREACHED() << "Could not create Pnacl directory.";
212 return;
213 }
214 }
215
216 Version version(kNullVersion);
217 if (GetLatestPnaclDirectory(&path, &version)) {
218 // Check if one of the Pnacl files is really there.
219 FilePath compiler_path = path.Append(kPnaclCompilerFileName);
220 if (!file_util::PathExists(compiler_path)) {
221 version = Version(kNullVersion);
222 } else {
223 // Register the existing path for now, before checking for updates.
224 // TODO(jvoung): Will this always happen "early" or will it
225 // race with the NaCl plugin in browser tests?
226 PathService::Override(chrome::FILE_PNACL_COMPONENT, path);
227 }
228 }
229
230 BrowserThread::PostTask(
231 BrowserThread::UI, FROM_HERE,
232 base::Bind(&FinishPnaclUpdateRegistration, cus, version));
233 }
234
235 } // namespace
236
237 void RegisterPnaclComponent(ComponentUpdateService* cus) {
238 BrowserThread::PostTask(
239 BrowserThread::FILE, FROM_HERE,
240 base::Bind(&StartPnaclUpdateRegistration, cus));
241 }
OLDNEW
« no previous file with comments | « chrome/browser/component_updater/pnacl/pnacl_component_installer.h ('k') | chrome/browser/ui/browser_init.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698