Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / component_updater / default_component_installer.cc
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 "base/bind.h"
6 #include "base/file_util.h"
7 #include "base/files/file_enumerator.h"
8 #include "base/files/file_path.h"
9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/values.h"
14 #include "base/version.h"
15 // TODO(ddorwin): Find a better place for ReadManifest.
16 #include "chrome/browser/component_updater/component_unpacker.h"
17 #include "chrome/browser/component_updater/component_updater_configurator.h"
18 #include "chrome/browser/component_updater/default_component_installer.h"
19
20 namespace component_updater {
21
22 namespace {
23 // Version "0" corresponds to no installed version. By the server's conventions,
24 // we represent it as a dotted quad.
25 const char kNullVersion[] = "0.0.0.0";
26 }  // namespace
27
28 ComponentInstallerTraits::~ComponentInstallerTraits() {
29 }
30
31 DefaultComponentInstaller::DefaultComponentInstaller(
32     scoped_ptr<ComponentInstallerTraits> installer_traits)
33     : current_version_(kNullVersion),
34       main_task_runner_(base::MessageLoopProxy::current()) {
35   installer_traits_ = installer_traits.Pass();
36 }
37
38 DefaultComponentInstaller::~DefaultComponentInstaller() {
39   DCHECK(thread_checker_.CalledOnValidThread());
40 }
41
42 void DefaultComponentInstaller::Register(ComponentUpdateService* cus) {
43   DCHECK(thread_checker_.CalledOnValidThread());
44   task_runner_ = cus->GetSequencedTaskRunner();
45
46   if (!installer_traits_) {
47     NOTREACHED() << "A DefaultComponentInstaller has been created but "
48                  << "has no installer traits.";
49     return;
50   }
51   task_runner_->PostTask(
52       FROM_HERE,
53       base::Bind(&DefaultComponentInstaller::StartRegistration,
54                  base::Unretained(this),
55                  cus));
56 }
57
58 void DefaultComponentInstaller::OnUpdateError(int error) {
59   NOTREACHED() << "Component update error: " << error;
60 }
61
62 bool DefaultComponentInstaller::InstallHelper(
63     const base::DictionaryValue& manifest,
64     const base::FilePath& unpack_path,
65     const base::FilePath& install_path) {
66   if (!base::Move(unpack_path, install_path))
67     return false;
68   if (!installer_traits_->OnCustomInstall(manifest, install_path))
69     return false;
70   if (!installer_traits_->VerifyInstallation(install_path))
71     return false;
72   return true;
73 }
74
75 bool DefaultComponentInstaller::Install(const base::DictionaryValue& manifest,
76                                         const base::FilePath& unpack_path) {
77   std::string manifest_version;
78   manifest.GetStringASCII("version", &manifest_version);
79   base::Version version(manifest_version.c_str());
80   if (!version.IsValid())
81     return false;
82   if (current_version_.CompareTo(version) > 0)
83     return false;
84   base::FilePath install_path =
85       installer_traits_->GetBaseDirectory().AppendASCII(version.GetString());
86   if (base::PathExists(install_path)) {
87     if (!base::DeleteFile(install_path, true))
88       return false;
89   }
90   if (!InstallHelper(manifest, unpack_path, install_path)) {
91     base::DeleteFile(install_path, true);
92     return false;
93   }
94   current_version_ = version;
95   // TODO(ddorwin): Change the parameter to scoped_ptr<base::DictionaryValue>
96   // so we can avoid this DeepCopy.
97   current_manifest_.reset(manifest.DeepCopy());
98   scoped_ptr<base::DictionaryValue> manifest_copy(
99       current_manifest_->DeepCopy());
100   main_task_runner_->PostTask(
101       FROM_HERE,
102       base::Bind(&ComponentInstallerTraits::ComponentReady,
103                  base::Unretained(installer_traits_.get()),
104                  current_version_,
105                  GetInstallDirectory(),
106                  base::Passed(&manifest_copy)));
107   return true;
108 }
109
110 bool DefaultComponentInstaller::GetInstalledFile(
111     const std::string& file,
112     base::FilePath* installed_file) {
113   if (current_version_.Equals(base::Version(kNullVersion)))
114     return false;  // No component has been installed yet.
115
116   *installed_file = installer_traits_->GetBaseDirectory()
117                         .AppendASCII(current_version_.GetString())
118                         .AppendASCII(file);
119   return true;
120 }
121
122 void DefaultComponentInstaller::StartRegistration(ComponentUpdateService* cus) {
123   DCHECK(task_runner_);
124   DCHECK(task_runner_->RunsTasksOnCurrentThread());
125   base::FilePath base_dir = installer_traits_->GetBaseDirectory();
126   if (!base::PathExists(base_dir) && !base::CreateDirectory(base_dir)) {
127     NOTREACHED() << "Could not create the base directory for "
128                  << installer_traits_->GetName() << " ("
129                  << base_dir.MaybeAsASCII() << ").";
130     return;
131   }
132
133   base::FilePath latest_dir;
134   base::Version latest_version(kNullVersion);
135   std::vector<base::FilePath> older_dirs;
136   bool found = false;
137   base::FileEnumerator file_enumerator(
138       base_dir, false, base::FileEnumerator::DIRECTORIES);
139   for (base::FilePath path = file_enumerator.Next();
140        !path.value().empty();
141        path = file_enumerator.Next()) {
142     base::Version version(path.BaseName().MaybeAsASCII());
143     // Ignore folders that don't have valid version names. These folders are not
144     // managed by component installer so do not try to remove them.
145     if (!version.IsValid())
146       continue;
147     if (!installer_traits_->VerifyInstallation(path)) {
148       older_dirs.push_back(path);
149       continue;
150     }
151     if (found) {
152       if (version.CompareTo(latest_version) > 0) {
153         older_dirs.push_back(latest_dir);
154         latest_dir = path;
155         latest_version = version;
156       } else {
157         older_dirs.push_back(path);
158       }
159     } else {
160       latest_dir = path;
161       latest_version = version;
162       found = true;
163     }
164   }
165
166   if (found) {
167     current_manifest_ = ReadManifest(latest_dir);
168     if (current_manifest_) {
169       current_version_ = latest_version;
170       // TODO(ddorwin): Remove these members and pass them directly to
171       // FinishRegistration().
172       base::ReadFileToString(latest_dir.AppendASCII("manifest.fingerprint"),
173                              &current_fingerprint_);
174     } else {
175       // If the manifest can't be read, mark the directory for deletion and
176       // continue as if there were no versioned directories at all.
177       DLOG(ERROR) << "Failed to read manifest for "
178                   << installer_traits_->GetName() << " ("
179                   << base_dir.MaybeAsASCII() << ").";
180       older_dirs.push_back(latest_dir);
181     }
182   }
183
184   // Remove older versions of the component. None should be in use during
185   // browser startup.
186   for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
187        iter != older_dirs.end();
188        ++iter) {
189     base::DeleteFile(*iter, true);
190   }
191
192   main_task_runner_->PostTask(
193       FROM_HERE,
194       base::Bind(&DefaultComponentInstaller::FinishRegistration,
195                  base::Unretained(this),
196                  cus));
197 }
198
199 base::FilePath DefaultComponentInstaller::GetInstallDirectory() {
200   return installer_traits_->GetBaseDirectory()
201       .AppendASCII(current_version_.GetString());
202 }
203
204 void DefaultComponentInstaller::FinishRegistration(
205     ComponentUpdateService* cus) {
206   DCHECK(thread_checker_.CalledOnValidThread());
207   if (installer_traits_->CanAutoUpdate()) {
208     CrxComponent crx;
209     crx.name = installer_traits_->GetName();
210     crx.installer = this;
211     crx.version = current_version_;
212     crx.fingerprint = current_fingerprint_;
213     installer_traits_->GetHash(&crx.pk_hash);
214     ComponentUpdateService::Status status = cus->RegisterComponent(crx);
215     if (status != ComponentUpdateService::kOk &&
216         status != ComponentUpdateService::kReplaced) {
217       NOTREACHED() << "Component registration failed for "
218                    << installer_traits_->GetName();
219       return;
220     }
221   }
222
223   if (current_version_.CompareTo(base::Version(kNullVersion)) > 0) {
224     scoped_ptr<base::DictionaryValue> manifest_copy(
225         current_manifest_->DeepCopy());
226     installer_traits_->ComponentReady(
227         current_version_, GetInstallDirectory(), manifest_copy.Pass());
228   }
229 }
230
231 }  // namespace component_updater