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

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

Powered by Google App Engine
This is Rietveld 408576698