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

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: stuff 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[] = {
cpu_(ooo_6.6-7.5) 2011/11/23 01:51:33 is this the final hash? if so it is important to p
jvoung - send to chromium... 2011/12/14 19:34:31 Good point I'll move this into a pnacl subdir and
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).
cpu_(ooo_6.6-7.5) 2011/11/23 01:51:33 this caveat is worthy of a bug number.
jvoung - send to chromium... 2011/12/14 19:34:31 Done, filed a bug.
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
« chrome/common/chrome_switches.cc ('K') | « chrome/nacl/pnacl_component_installer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698