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

Side by Side Diff: chrome/browser/component_updater/component_patcher_operation.cc

Issue 25909005: Use UtilityProcessHost to patch files. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@nonblocking
Patch Set: Rebase to LKGR/248226 Created 6 years, 10 months 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/component_updater/component_patcher_operation.h" 5 #include "chrome/browser/component_updater/component_patcher_operation.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h"
10 #include "base/file_util.h" 11 #include "base/file_util.h"
11 #include "base/files/memory_mapped_file.h" 12 #include "base/files/memory_mapped_file.h"
12 #include "base/json/json_file_value_serializer.h" 13 #include "base/json/json_file_value_serializer.h"
13 #include "base/memory/scoped_handle.h" 14 #include "base/memory/scoped_handle.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
16 #include "chrome/browser/component_updater/component_patcher.h" 17 #include "chrome/browser/component_updater/component_patcher.h"
17 #include "chrome/browser/component_updater/component_updater_service.h" 18 #include "chrome/browser/component_updater/component_updater_service.h"
19 #include "chrome/common/chrome_utility_messages.h"
18 #include "chrome/common/extensions/extension_constants.h" 20 #include "chrome/common/extensions/extension_constants.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/utility_process_host.h"
23 #include "courgette/courgette.h"
24 #include "courgette/third_party/bsdiff.h"
19 #include "crypto/secure_hash.h" 25 #include "crypto/secure_hash.h"
20 #include "crypto/sha2.h" 26 #include "crypto/sha2.h"
21 #include "crypto/signature_verifier.h" 27 #include "crypto/signature_verifier.h"
22 #include "extensions/common/crx_file.h" 28 #include "extensions/common/crx_file.h"
29 #include "ipc/ipc_message_macros.h"
23 #include "third_party/zlib/google/zip.h" 30 #include "third_party/zlib/google/zip.h"
24 31
25 using crypto::SecureHash; 32 using crypto::SecureHash;
26 33
27 namespace component_updater { 34 namespace component_updater {
28 35
29 namespace { 36 namespace {
30 37
31 const char kInput[] = "input"; 38 const char kInput[] = "input";
32 const char kOp[] = "op"; 39 const char kOp[] = "op";
33 const char kOutput[] = "output"; 40 const char kOutput[] = "output";
34 const char kPatch[] = "patch"; 41 const char kPatch[] = "patch";
35 const char kSha256[] = "sha256"; 42 const char kSha256[] = "sha256";
36 43
44 // These error ranges are overlapping, so we use an offset to disambiguate
Sorin Jianu 2014/02/03 20:57:57 The integer offset disambiguates between overlappi
waffles 2014/02/07 01:00:59 Done.
45 // them.
46 const int kCourgetteErrorOffset = 300;
47 const int kBsdiffErrorOffset = 600;
48
37 } // namespace 49 } // namespace
38 50
39 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { 51 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) {
Sorin Jianu 2014/02/03 20:57:57 can the argument be const?
waffles 2014/02/07 01:00:59 Done.
40 std::string operation; 52 std::string operation;
41 if (!command->GetString(kOp, &operation)) 53 if (!command->GetString(kOp, &operation))
42 return NULL; 54 return NULL;
43 if (operation == "copy") 55 if (operation == "copy")
44 return new DeltaUpdateOpCopy(); 56 return new DeltaUpdateOpCopy();
45 else if (operation == "create") 57 else if (operation == "create")
46 return new DeltaUpdateOpCreate(); 58 return new DeltaUpdateOpCreate();
47 else if (operation == "bsdiff") 59 else if (operation == "bsdiff")
48 return new DeltaUpdateOpPatchBsdiff(); 60 return new DeltaUpdateOpPatch(component_updater::kPatchTypeBsdiff);
49 else if (operation == "courgette") 61 else if (operation == "courgette")
50 return new DeltaUpdateOpPatchCourgette(); 62 return new DeltaUpdateOpPatch(component_updater::kPatchTypeCourgette);
51 return NULL; 63 return NULL;
52 } 64 }
53 65
54 DeltaUpdateOp::DeltaUpdateOp() {} 66 DeltaUpdateOp::DeltaUpdateOp() : in_process_(false), ptr_factory_(this) {}
55 67
56 DeltaUpdateOp::~DeltaUpdateOp() {} 68 DeltaUpdateOp::~DeltaUpdateOp() {}
57 69
58 ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args, 70 void DeltaUpdateOp::Run(
59 const base::FilePath& input_dir, 71 base::DictionaryValue* command_args,
60 const base::FilePath& unpack_dir, 72 const base::FilePath& input_dir,
61 ComponentPatcher* patcher, 73 const base::FilePath& unpack_dir,
62 ComponentInstaller* installer, 74 ComponentInstaller* installer,
63 int* error) { 75 bool in_process,
76 const base::Callback<void(ComponentUnpacker::Error, int)>& callback,
77 scoped_refptr<base::SequencedTaskRunner> task_runner) {
78 callback_ = callback;
79 in_process_ = in_process;
80 task_runner_ = task_runner;
64 std::string output_rel_path; 81 std::string output_rel_path;
65 if (!command_args->GetString(kOutput, &output_rel_path) || 82 if (!command_args->GetString(kOutput, &output_rel_path) ||
66 !command_args->GetString(kSha256, &output_sha256_)) 83 !command_args->GetString(kSha256, &output_sha256_)) {
67 return ComponentUnpacker::kDeltaBadCommands; 84 DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0);
85 return;
86 }
68 87
69 output_abs_path_ = unpack_dir.Append( 88 output_abs_path_ = unpack_dir.Append(
70 base::FilePath::FromUTF8Unsafe(output_rel_path)); 89 base::FilePath::FromUTF8Unsafe(output_rel_path));
71 ComponentUnpacker::Error parse_result = DoParseArguments( 90 ComponentUnpacker::Error parse_result = DoParseArguments(
72 command_args, input_dir, installer); 91 command_args, input_dir, installer);
73 if (parse_result != ComponentUnpacker::kNone) 92 if (parse_result != ComponentUnpacker::kNone) {
74 return parse_result; 93 DoneRunning(parse_result, 0);
94 return;
95 }
75 96
76 const base::FilePath parent = output_abs_path_.DirName(); 97 const base::FilePath parent = output_abs_path_.DirName();
77 if (!base::DirectoryExists(parent)) { 98 if (!base::DirectoryExists(parent)) {
78 if (!base::CreateDirectory(parent)) 99 if (!base::CreateDirectory(parent)) {
79 return ComponentUnpacker::kIoError; 100 DoneRunning(ComponentUnpacker::kIoError, 0);
101 return;
102 }
80 } 103 }
81 104
82 ComponentUnpacker::Error run_result = DoRun(patcher, error); 105 DoRun(base::Bind(&DeltaUpdateOp::DoneRunning, GetWeakPtr()));
83 if (run_result != ComponentUnpacker::kNone) 106 }
84 return run_result;
85 107
86 return CheckHash(); 108 void DeltaUpdateOp::DoneRunning(
109 ComponentUnpacker::Error error, int extended_error) {
Sorin Jianu 2014/02/03 20:57:57 does this line fit on the line above?
Sorin Jianu 2014/02/03 20:57:57 Coding style nit: http://google-styleguide.googlec
waffles 2014/02/07 01:00:59 Not the whole line, no.
waffles 2014/02/07 01:00:59 Done.
110 if (error == ComponentUnpacker::kNone)
111 error = CheckHash();
112 task_runner_->PostTask(
113 FROM_HERE,
Sorin Jianu 2014/02/03 20:57:57 params vertical align as above?
waffles 2014/02/07 01:00:59 Done.
114 base::Bind(callback_, error, extended_error));
87 } 115 }
88 116
89 // Uses the hash as a checksum to confirm that the file now residing in the 117 // Uses the hash as a checksum to confirm that the file now residing in the
90 // output directory probably has the contents it should. 118 // output directory probably has the contents it should.
91 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { 119 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
92 std::vector<uint8> expected_hash; 120 std::vector<uint8> expected_hash;
93 if (!base::HexStringToBytes(output_sha256_, &expected_hash) || 121 if (!base::HexStringToBytes(output_sha256_, &expected_hash) ||
94 expected_hash.size() != crypto::kSHA256Length) 122 expected_hash.size() != crypto::kSHA256Length)
95 return ComponentUnpacker::kDeltaVerificationFailure; 123 return ComponentUnpacker::kDeltaVerificationFailure;
96 124
97 base::MemoryMappedFile output_file_mmapped; 125 base::MemoryMappedFile output_file_mmapped;
98 if (!output_file_mmapped.Initialize(output_abs_path_)) 126 if (!output_file_mmapped.Initialize(output_abs_path_))
99 return ComponentUnpacker::kDeltaVerificationFailure; 127 return ComponentUnpacker::kDeltaVerificationFailure;
100 128
101 uint8 actual_hash[crypto::kSHA256Length] = {0}; 129 uint8 actual_hash[crypto::kSHA256Length] = {0};
102 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256)); 130 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256));
103 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length()); 131 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length());
104 hasher->Finish(actual_hash, sizeof(actual_hash)); 132 hasher->Finish(actual_hash, sizeof(actual_hash));
105 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash))) 133 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)))
106 return ComponentUnpacker::kDeltaVerificationFailure; 134 return ComponentUnpacker::kDeltaVerificationFailure;
107 135
108 return ComponentUnpacker::kNone; 136 return ComponentUnpacker::kNone;
109 } 137 }
110 138
139 base::WeakPtr<DeltaUpdateOp> DeltaUpdateOp::GetWeakPtr() {
140 return ptr_factory_.GetWeakPtr();
141 }
142
111 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {} 143 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
112 144
113 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( 145 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
114 base::DictionaryValue* command_args, 146 base::DictionaryValue* command_args,
115 const base::FilePath& input_dir, 147 const base::FilePath& input_dir,
116 ComponentInstaller* installer) { 148 ComponentInstaller* installer) {
117 std::string input_rel_path; 149 std::string input_rel_path;
118 if (!command_args->GetString(kInput, &input_rel_path)) 150 if (!command_args->GetString(kInput, &input_rel_path))
119 return ComponentUnpacker::kDeltaBadCommands; 151 return ComponentUnpacker::kDeltaBadCommands;
120 152
121 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) 153 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
122 return ComponentUnpacker::kDeltaMissingExistingFile; 154 return ComponentUnpacker::kDeltaMissingExistingFile;
123 155
124 return ComponentUnpacker::kNone; 156 return ComponentUnpacker::kNone;
125 } 157 }
126 158
127 ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*, 159 void DeltaUpdateOpCopy::DoRun(
128 int* error) { 160 const base::Callback<void(ComponentUnpacker::Error, int)>& callback) {
129 *error = 0;
130 if (!base::CopyFile(input_abs_path_, output_abs_path_)) 161 if (!base::CopyFile(input_abs_path_, output_abs_path_))
131 return ComponentUnpacker::kDeltaOperationFailure; 162 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
132 163 else
133 return ComponentUnpacker::kNone; 164 callback.Run(ComponentUnpacker::kNone, 0);
134 } 165 }
135 166
136 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {} 167 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
137 168
138 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( 169 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
139 base::DictionaryValue* command_args, 170 base::DictionaryValue* command_args,
140 const base::FilePath& input_dir, 171 const base::FilePath& input_dir,
141 ComponentInstaller* installer) { 172 ComponentInstaller* installer) {
142 std::string patch_rel_path; 173 std::string patch_rel_path;
143 if (!command_args->GetString(kPatch, &patch_rel_path)) 174 if (!command_args->GetString(kPatch, &patch_rel_path))
144 return ComponentUnpacker::kDeltaBadCommands; 175 return ComponentUnpacker::kDeltaBadCommands;
145 176
146 patch_abs_path_ = input_dir.Append( 177 patch_abs_path_ = input_dir.Append(
147 base::FilePath::FromUTF8Unsafe(patch_rel_path)); 178 base::FilePath::FromUTF8Unsafe(patch_rel_path));
148 179
149 return ComponentUnpacker::kNone; 180 return ComponentUnpacker::kNone;
150 } 181 }
151 182
152 ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*, 183 void DeltaUpdateOpCreate::DoRun(
153 int* error) { 184 const base::Callback<void(ComponentUnpacker::Error, int)>& callback) {
154 *error = 0;
155 if (!base::Move(patch_abs_path_, output_abs_path_)) 185 if (!base::Move(patch_abs_path_, output_abs_path_))
156 return ComponentUnpacker::kDeltaOperationFailure; 186 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
157 187 else
158 return ComponentUnpacker::kNone; 188 callback.Run(ComponentUnpacker::kNone, 0);
159 } 189 }
160 190
161 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
162 191
163 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( 192 DeltaUpdateOpPatch::DeltaUpdateOpPatch(
193 component_updater::PatchType patch_type) : patch_type_(patch_type) {
Sorin Jianu 2014/02/03 20:57:57 Formatting of function params and initializers.
waffles 2014/02/07 01:00:59 Done.
194 }
195
196 DeltaUpdateOpPatch::~DeltaUpdateOpPatch() {
197 }
198
199 ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments(
164 base::DictionaryValue* command_args, 200 base::DictionaryValue* command_args,
165 const base::FilePath& input_dir, 201 const base::FilePath& input_dir,
166 ComponentInstaller* installer) { 202 ComponentInstaller* installer) {
167 std::string patch_rel_path; 203 std::string patch_rel_path;
168 std::string input_rel_path; 204 std::string input_rel_path;
169 if (!command_args->GetString(kPatch, &patch_rel_path) || 205 if (!command_args->GetString(kPatch, &patch_rel_path) ||
170 !command_args->GetString(kInput, &input_rel_path)) 206 !command_args->GetString(kInput, &input_rel_path))
171 return ComponentUnpacker::kDeltaBadCommands; 207 return ComponentUnpacker::kDeltaBadCommands;
172 208
173 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) 209 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
174 return ComponentUnpacker::kDeltaMissingExistingFile; 210 return ComponentUnpacker::kDeltaMissingExistingFile;
175 211
176 patch_abs_path_ = input_dir.Append( 212 patch_abs_path_ = input_dir.Append(
177 base::FilePath::FromUTF8Unsafe(patch_rel_path)); 213 base::FilePath::FromUTF8Unsafe(patch_rel_path));
178 214
179 return ComponentUnpacker::kNone; 215 return ComponentUnpacker::kNone;
180 } 216 }
181 217
182 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun( 218 void DeltaUpdateOpPatch::DoRun(
183 ComponentPatcher* patcher, 219 const base::Callback<void(ComponentUnpacker::Error, int)>& callback) {
184 int* error) { 220 callback_ = callback;
185 *error = 0; 221 if (!in_process_) {
186 return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff, 222 content::BrowserThread::PostTask(
187 input_abs_path_, 223 content::BrowserThread::IO,
188 patch_abs_path_, 224 FROM_HERE,
189 output_abs_path_, 225 base::Bind(&DeltaUpdateOpPatch::StartProcess, base::Unretained(this)));
Sorin Jianu 2014/02/03 20:57:57 Can we have a race here due to ownership issues, n
waffles 2014/02/07 01:00:59 Yes - this should be resolved now that this class
190 error); 226 return;
227 }
228 switch (patch_type_) {
229 case component_updater::kPatchTypeCourgette: {
230 const int result = courgette::ApplyEnsemblePatch(
231 input_abs_path_.value().c_str(),
232 patch_abs_path_.value().c_str(),
233 output_abs_path_.value().c_str());
234 if (result == courgette::C_OK)
235 callback_.Run(ComponentUnpacker::kNone, 0);
236 else
237 DonePatching(false, result);
Sorin Jianu 2014/02/03 20:57:57 I've noticed that is most cases DonePatching is ca
waffles 2014/02/07 01:00:59 This should all be much more organized now.
238 break;
239 }
240 case component_updater::kPatchTypeBsdiff: {
241 const int result = courgette::ApplyBinaryPatch(
242 input_abs_path_, patch_abs_path_, output_abs_path_);
243 if (result == courgette::OK)
244 callback_.Run(ComponentUnpacker::kNone, 0);
245 else
246 DonePatching(false, result);
247 break;
248 }
249 default: {
250 NOTREACHED() << "Invalid patch type.";
251 callback_.Run(ComponentUnpacker::kDeltaUnsupportedCommand, 0);
252 }
253 }
191 } 254 }
192 255
193 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {} 256 void DeltaUpdateOpPatch::StartProcess() {
194 257 content::UtilityProcessHost* host = content::UtilityProcessHost::Create(
195 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments( 258 new PatcherBridge(this), base::MessageLoopProxy::current().get());
196 base::DictionaryValue* command_args, 259 host->DisableSandbox();
197 const base::FilePath& input_dir, 260 switch (patch_type_) {
198 ComponentInstaller* installer) { 261 case component_updater::kPatchTypeCourgette: {
199 std::string patch_rel_path; 262 host->Send(new ChromeUtilityMsg_PatchFileCourgette(
200 std::string input_rel_path; 263 input_abs_path_, patch_abs_path_, output_abs_path_));
201 if (!command_args->GetString(kPatch, &patch_rel_path) || 264 break;
202 !command_args->GetString(kInput, &input_rel_path)) 265 }
203 return ComponentUnpacker::kDeltaBadCommands; 266 case component_updater::kPatchTypeBsdiff: {
204 267 host->Send(new ChromeUtilityMsg_PatchFileBsdiff(
205 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) 268 input_abs_path_, patch_abs_path_, output_abs_path_));
206 return ComponentUnpacker::kDeltaMissingExistingFile; 269 break;
207 270 }
208 patch_abs_path_ = input_dir.Append( 271 default: {
209 base::FilePath::FromUTF8Unsafe(patch_rel_path)); 272 NOTREACHED() << "Invalid patch type.";
210 273 callback_.Run(ComponentUnpacker::kDeltaUnsupportedCommand, 0);
211 return ComponentUnpacker::kNone; 274 }
275 }
212 } 276 }
213 277
214 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun( 278 void DeltaUpdateOpPatch::DonePatching(bool success, int error_code) {
215 ComponentPatcher* patcher, 279 if (success) {
216 int* error) { 280 callback_.Run(ComponentUnpacker::kNone, error_code);
217 *error = 0; 281 } else {
218 return patcher->Patch(ComponentPatcher::kPatchTypeCourgette, 282 int offset = patch_type_ == component_updater::kPatchTypeCourgette
Sorin Jianu 2014/02/03 20:57:57 we have the switch on the patch_type_ in three dif
waffles 2014/02/07 01:00:59 I've tried out a using a traits class - let me kno
219 input_abs_path_, 283 ? kCourgetteErrorOffset : kBsdiffErrorOffset;
220 patch_abs_path_, 284 callback_.Run(ComponentUnpacker::kDeltaOperationFailure,
221 output_abs_path_, 285 error_code + offset);
222 error); 286 }
287 }
288
289 DeltaUpdateOpPatch::PatcherBridge::PatcherBridge(DeltaUpdateOpPatch* op)
290 : op_(op) {
291 }
292
293 DeltaUpdateOpPatch::PatcherBridge::~PatcherBridge() {
294 }
295
296 bool DeltaUpdateOpPatch::PatcherBridge::OnMessageReceived(
297 const IPC::Message& message) {
298 bool handled = true;
299 IPC_BEGIN_MESSAGE_MAP(PatcherBridge, message)
300 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Succeeded,
301 OnPatchSucceeded)
302 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Failed,
303 OnPatchFailed)
304 IPC_MESSAGE_UNHANDLED(handled = false)
305 IPC_END_MESSAGE_MAP()
306 return handled;
307 }
308
309 void DeltaUpdateOpPatch::PatcherBridge::OnProcessCrashed(int exit_code) {
310 if (op_)
311 op_->callback_.Run(ComponentUnpacker::kDeltaPatchProcessFailure, exit_code);
312 }
313
314 void DeltaUpdateOpPatch::PatcherBridge::OnPatchSucceeded() {
315 if (op_)
316 op_->DonePatching(true, 0);
317 }
318
319 void DeltaUpdateOpPatch::PatcherBridge::OnPatchFailed(int error_code) {
320 if (op_)
321 op_->DonePatching(false, error_code);
223 } 322 }
224 323
225 } // namespace component_updater 324 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698