Home | History | Annotate | Download | only in component_updater
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/component_updater/component_patcher.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/file_util.h"
     12 #include "base/files/file_path.h"
     13 #include "base/json/json_file_value_serializer.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/component_updater/component_patcher_operation.h"
     17 #include "chrome/browser/component_updater/component_updater_service.h"
     18 #include "content/public/browser/browser_thread.h"
     19 
     20 namespace component_updater {
     21 
     22 namespace {
     23 
     24 // Deserialize the commands file (present in delta update packages). The top
     25 // level must be a list.
     26 base::ListValue* ReadCommands(const base::FilePath& unpack_path) {
     27   const base::FilePath commands =
     28       unpack_path.Append(FILE_PATH_LITERAL("commands.json"));
     29   if (!base::PathExists(commands))
     30     return NULL;
     31 
     32   JSONFileValueSerializer serializer(commands);
     33   scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL));
     34 
     35   return (root.get() && root->IsType(base::Value::TYPE_LIST))
     36              ? static_cast<base::ListValue*>(root.release())
     37              : NULL;
     38 }
     39 
     40 }  // namespace
     41 
     42 ComponentPatcher::ComponentPatcher(
     43     const base::FilePath& input_dir,
     44     const base::FilePath& unpack_dir,
     45     ComponentInstaller* installer,
     46     bool in_process,
     47     scoped_refptr<base::SequencedTaskRunner> task_runner)
     48     : input_dir_(input_dir),
     49       unpack_dir_(unpack_dir),
     50       installer_(installer),
     51       in_process_(in_process),
     52       task_runner_(task_runner) {
     53 }
     54 
     55 ComponentPatcher::~ComponentPatcher() {
     56 }
     57 
     58 void ComponentPatcher::Start(const ComponentUnpacker::Callback& callback) {
     59   callback_ = callback;
     60   task_runner_->PostTask(FROM_HERE,
     61                          base::Bind(&ComponentPatcher::StartPatching,
     62                                     scoped_refptr<ComponentPatcher>(this)));
     63 }
     64 
     65 void ComponentPatcher::StartPatching() {
     66   commands_.reset(ReadCommands(input_dir_));
     67   if (!commands_.get()) {
     68     DonePatching(ComponentUnpacker::kDeltaBadCommands, 0);
     69   } else {
     70     next_command_ = commands_->begin();
     71     PatchNextFile();
     72   }
     73 }
     74 
     75 void ComponentPatcher::PatchNextFile() {
     76   if (next_command_ == commands_->end()) {
     77     DonePatching(ComponentUnpacker::kNone, 0);
     78     return;
     79   }
     80   if (!(*next_command_)->IsType(base::Value::TYPE_DICTIONARY)) {
     81     DonePatching(ComponentUnpacker::kDeltaBadCommands, 0);
     82     return;
     83   }
     84   const base::DictionaryValue* command_args =
     85       static_cast<base::DictionaryValue*>(*next_command_);
     86   current_operation_ = CreateDeltaUpdateOp(*command_args);
     87   if (!current_operation_) {
     88     DonePatching(ComponentUnpacker::kDeltaUnsupportedCommand, 0);
     89     return;
     90   }
     91   current_operation_->Run(command_args,
     92                           input_dir_,
     93                           unpack_dir_,
     94                           installer_,
     95                           in_process_,
     96                           base::Bind(&ComponentPatcher::DonePatchingFile,
     97                                      scoped_refptr<ComponentPatcher>(this)),
     98                           task_runner_);
     99 }
    100 
    101 void ComponentPatcher::DonePatchingFile(ComponentUnpacker::Error error,
    102                                         int extended_error) {
    103   if (error != ComponentUnpacker::kNone) {
    104     DonePatching(error, extended_error);
    105   } else {
    106     ++next_command_;
    107     PatchNextFile();
    108   }
    109 }
    110 
    111 void ComponentPatcher::DonePatching(ComponentUnpacker::Error error,
    112                                     int extended_error) {
    113   current_operation_ = NULL;
    114   task_runner_->PostTask(FROM_HERE,
    115                          base::Bind(callback_, error, extended_error));
    116   callback_.Reset();
    117 }
    118 
    119 }  // namespace component_updater
    120