[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / component_updater / component_installer.cc
1 // Copyright 2014 The Chromium Authors
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 "components/component_updater/component_installer.h"
6
7 #include <cstdint>
8 #include <string>
9 #include <tuple>
10 #include <utility>
11 #include <vector>
12
13 #include "base/files/file_enumerator.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/functional/bind.h"
18 #include "base/functional/callback.h"
19 #include "base/location.h"
20 #include "base/logging.h"
21 #include "base/path_service.h"
22 #include "base/ranges/algorithm.h"
23 #include "base/sequence_checker.h"
24 #include "base/strings/string_util.h"
25 #include "base/task/sequenced_task_runner.h"
26 #include "base/task/task_traits.h"
27 #include "base/task/thread_pool.h"
28 #include "base/values.h"
29 #include "base/version.h"
30 #include "build/build_config.h"
31 #include "build/chromeos_buildflags.h"
32 #include "components/component_updater/component_updater_paths.h"
33 #include "components/component_updater/component_updater_service.h"
34 #include "components/crx_file/crx_verifier.h"
35 #include "components/update_client/component_unpacker.h"
36 #include "components/update_client/update_client.h"
37 #include "components/update_client/update_client_errors.h"
38 #include "components/update_client/update_query_params.h"
39 #include "components/update_client/utils.h"
40 #include "third_party/abseil-cpp/absl/types/optional.h"
41
42 #if BUILDFLAG(IS_APPLE)
43 #include "base/apple/backup_util.h"
44 #endif
45
46 namespace component_updater {
47
48 const char kNullVersion[] = "0.0.0.0";
49
50 namespace {
51 using Result = update_client::CrxInstaller::Result;
52 using InstallError = update_client::InstallError;
53 }  // namespace
54
55 ComponentInstallerPolicy::~ComponentInstallerPolicy() = default;
56
57 ComponentInstaller::RegistrationInfo::RegistrationInfo()
58     : version(kNullVersion) {}
59
60 ComponentInstaller::RegistrationInfo::~RegistrationInfo() = default;
61
62 ComponentInstaller::ComponentInstaller(
63     std::unique_ptr<ComponentInstallerPolicy> installer_policy,
64     scoped_refptr<update_client::ActionHandler> action_handler)
65     : current_version_(kNullVersion),
66       installer_policy_(std::move(installer_policy)),
67       action_handler_(action_handler),
68       main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
69
70 ComponentInstaller::~ComponentInstaller() = default;
71
72 void ComponentInstaller::Register(ComponentUpdateService* cus,
73                                   base::OnceClosure callback,
74                                   base::TaskPriority task_priority) {
75   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
76   DCHECK(cus);
77
78   std::vector<uint8_t> public_key_hash;
79   installer_policy_->GetHash(&public_key_hash);
80   Register(base::BindOnce(&ComponentUpdateService::RegisterComponent,
81                           base::Unretained(cus)),
82            std::move(callback), task_priority,
83            cus->GetRegisteredVersion(
84                update_client::GetCrxIdFromPublicKeyHash(public_key_hash)));
85 }
86
87 void ComponentInstaller::Register(RegisterCallback register_callback,
88                                   base::OnceClosure callback,
89                                   base::TaskPriority task_priority,
90                                   const base::Version& registered_version) {
91   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
92
93   task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
94       {base::MayBlock(), task_priority,
95        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
96
97   if (!installer_policy_) {
98     VLOG(0) << "A ComponentInstaller has been created but "
99             << "has no installer policy.";
100     return;
101   }
102
103   auto registration_info = base::MakeRefCounted<RegistrationInfo>();
104   task_runner_->PostTaskAndReply(
105       FROM_HERE,
106       base::BindOnce(&ComponentInstaller::StartRegistration, this,
107                      registered_version, registration_info),
108       base::BindOnce(&ComponentInstaller::FinishRegistration, this,
109                      registration_info, std::move(register_callback),
110                      std::move(callback)));
111 }
112
113 void ComponentInstaller::OnUpdateError(int error) {
114   VLOG(0) << "Component update error: " << error;
115 }
116
117 Result ComponentInstaller::InstallHelper(const base::FilePath& unpack_path,
118                                          base::Value::Dict* manifest,
119                                          base::Version* version,
120                                          base::FilePath* install_path) {
121   absl::optional<base::Value::Dict> local_manifest =
122       update_client::ReadManifest(unpack_path);
123   if (!local_manifest) {
124     return Result(InstallError::BAD_MANIFEST);
125   }
126
127   const std::string* version_ascii = local_manifest->FindString("version");
128   if (!version_ascii || !base::IsStringASCII(*version_ascii))
129     return Result(InstallError::INVALID_VERSION);
130
131   const base::Version manifest_version(*version_ascii);
132
133   VLOG(1) << "Install: version=" << manifest_version.GetString()
134           << " current version=" << current_version_.GetString();
135
136   if (!manifest_version.IsValid())
137     return Result(InstallError::INVALID_VERSION);
138   base::FilePath local_install_path;
139   if (!base::PathService::Get(DIR_COMPONENT_USER, &local_install_path))
140     return Result(InstallError::NO_DIR_COMPONENT_USER);
141   local_install_path =
142       local_install_path.Append(installer_policy_->GetRelativeInstallDir())
143           .AppendASCII(manifest_version.GetString());
144   if (base::PathExists(local_install_path)) {
145     if (!base::DeletePathRecursively(local_install_path))
146       return Result(InstallError::CLEAN_INSTALL_DIR_FAILED);
147   }
148
149   VLOG(1) << "unpack_path=" << unpack_path.AsUTF8Unsafe()
150           << " install_path=" << local_install_path.AsUTF8Unsafe();
151
152   if (!base::Move(unpack_path, local_install_path)) {
153     VPLOG(0) << "Move failed.";
154     base::DeletePathRecursively(local_install_path);
155     return Result(InstallError::MOVE_FILES_ERROR);
156   }
157
158   // Acquire the ownership of the |local_install_path|.
159   base::ScopedTempDir install_path_owner;
160   std::ignore = install_path_owner.Set(local_install_path);
161
162 #if BUILDFLAG(IS_CHROMEOS_ASH)
163   if (!base::SetPosixFilePermissions(local_install_path, 0755)) {
164     VPLOG(0) << "SetPosixFilePermissions failed: "
165              << local_install_path.value();
166     return Result(InstallError::SET_PERMISSIONS_FAILED);
167   }
168 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
169
170   DCHECK(!base::PathExists(unpack_path));
171   DCHECK(base::PathExists(local_install_path));
172
173 #if BUILDFLAG(IS_APPLE)
174   // Since components can be large and can be re-downloaded when needed, they
175   // are excluded from backups.
176   base::apple::SetBackupExclusion(local_install_path);
177 #endif
178
179   const Result result =
180       installer_policy_->OnCustomInstall(*local_manifest, local_install_path);
181   if (result.error)
182     return result;
183
184   if (!installer_policy_->VerifyInstallation(*local_manifest,
185                                              local_install_path)) {
186     return Result(InstallError::INSTALL_VERIFICATION_FAILED);
187   }
188
189   *manifest = std::move(local_manifest.value());
190   *version = manifest_version;
191   *install_path = install_path_owner.Take();
192
193   return Result(InstallError::NONE);
194 }
195
196 void ComponentInstaller::Install(
197     const base::FilePath& unpack_path,
198     const std::string& /*public_key*/,
199     std::unique_ptr<InstallParams> /*install_params*/,
200     ProgressCallback /*progress_callback*/,
201     Callback callback) {
202   base::Value::Dict manifest;
203   base::Version version;
204   base::FilePath install_path;
205   const Result result =
206       InstallHelper(unpack_path, &manifest, &version, &install_path);
207   base::DeletePathRecursively(unpack_path);
208   if (result.error) {
209     main_task_runner_->PostTask(FROM_HERE,
210                                 base::BindOnce(std::move(callback), result));
211     return;
212   }
213
214   current_version_ = version;
215   current_install_dir_ = install_path;
216
217   main_task_runner_->PostTask(
218       FROM_HERE, base::BindOnce(&ComponentInstaller::ComponentReady, this,
219                                 std::move(manifest)));
220   main_task_runner_->PostTask(FROM_HERE,
221                               base::BindOnce(std::move(callback), result));
222 }
223
224 bool ComponentInstaller::GetInstalledFile(const std::string& file,
225                                           base::FilePath* installed_file) {
226   if (current_version_ == base::Version(kNullVersion))
227     return false;  // No component has been installed yet.
228   *installed_file = current_install_dir_.AppendASCII(file);
229   return true;
230 }
231
232 bool ComponentInstaller::Uninstall() {
233   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
234   task_runner_->PostTask(
235       FROM_HERE,
236       base::BindOnce(&ComponentInstaller::UninstallOnTaskRunner, this));
237   return true;
238 }
239
240 bool ComponentInstaller::FindPreinstallation(
241     const base::FilePath& root,
242     scoped_refptr<RegistrationInfo> registration_info) {
243   base::FilePath path = root.Append(installer_policy_->GetRelativeInstallDir());
244   if (!base::PathExists(path)) {
245     DVLOG(1) << "Relative install dir does not exist: " << path.MaybeAsASCII();
246     return false;
247   }
248
249   absl::optional<base::Value::Dict> manifest =
250       update_client::ReadManifest(path);
251   if (!manifest) {
252     DVLOG(1) << "Manifest does not exist: " << path.MaybeAsASCII();
253     return false;
254   }
255
256   if (!installer_policy_->VerifyInstallation(*manifest, path)) {
257     DVLOG(1) << "Installation verification failed: " << path.MaybeAsASCII();
258     return false;
259   }
260
261   std::string* version_lexical = manifest->FindString("version");
262   if (!version_lexical || !base::IsStringASCII(*version_lexical)) {
263     DVLOG(1) << "Failed to get component version from the manifest.";
264     return false;
265   }
266
267   const base::Version version(*version_lexical);
268   if (!version.IsValid()) {
269     DVLOG(1) << "Version in the manifest is invalid:" << *version_lexical;
270     return false;
271   }
272
273   VLOG(1) << "Preinstalled component found for " << installer_policy_->GetName()
274           << " at " << path.MaybeAsASCII() << " with version " << version
275           << ".";
276
277   registration_info->install_dir = path;
278   registration_info->version = version;
279   registration_info->manifest = std::move(manifest);
280
281   return true;
282 }
283
284 // Checks to see if the installation found in |path| is valid, and returns
285 // its manifest if it is.
286 absl::optional<base::Value::Dict>
287 ComponentInstaller::GetValidInstallationManifest(const base::FilePath& path) {
288   absl::optional<base::Value::Dict> manifest =
289       update_client::ReadManifest(path);
290   if (!manifest) {
291     VPLOG(0) << "Failed to read manifest for " << installer_policy_->GetName()
292              << " (" << path.MaybeAsASCII() << ").";
293     return absl::nullopt;
294   }
295
296   if (!installer_policy_->VerifyInstallation(*manifest, path)) {
297     VPLOG(0) << "Failed to verify installation for "
298              << installer_policy_->GetName() << " (" << path.MaybeAsASCII()
299              << ").";
300     return absl::nullopt;
301   }
302
303   const base::Value::List* accept_archs = manifest->FindList("accept_arch");
304   if (accept_archs != nullptr &&
305       base::ranges::none_of(*accept_archs, [](const base::Value& v) {
306         static const char* current_arch =
307             update_client::UpdateQueryParams::GetArch();
308         return v.is_string() && v.GetString() == current_arch;
309       })) {
310     return absl::nullopt;
311   }
312
313   return manifest;
314 }
315
316 // Processes the user component directory to select an appropriate component
317 // version, and saves its data to |registration_info|.
318 absl::optional<base::Version> ComponentInstaller::SelectComponentVersion(
319     const base::Version& registered_version,
320     const base::FilePath& base_dir,
321     scoped_refptr<RegistrationInfo> registration_info) {
322   base::FileEnumerator file_enumerator(base_dir, false,
323                                        base::FileEnumerator::DIRECTORIES);
324
325   absl::optional<base::Version> selected_version;
326   base::FilePath selected_path;
327   absl::optional<base::Value::Dict> selected_manifest;
328
329   const base::Version bundled_version = registration_info->version.IsValid()
330                                             ? registration_info->version
331                                             : base::Version(kNullVersion);
332
333   // Only look for a previously registered version if it is higher than the
334   // bundled version, else default to the highest version.
335   const absl::optional<base::Version> target_version =
336       (registered_version > bundled_version)
337           ? absl::optional<base::Version>(registered_version)
338           : absl::nullopt;
339
340   for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
341        path = file_enumerator.Next()) {
342     // Ignore folders that don't have valid version names. These
343     // are not managed by component installer.
344     base::Version version(path.BaseName().MaybeAsASCII());
345     if (!version.IsValid()) {
346       continue;
347     }
348
349     if (!selected_version || version > *selected_version ||
350         (target_version && version == *target_version)) {
351       absl::optional<base::Value::Dict> candidate_manifest =
352           GetValidInstallationManifest(path);
353       if (candidate_manifest) {
354         selected_version = version;
355         selected_path = path;
356         selected_manifest = std::move(*candidate_manifest);
357       }
358     }
359     // Stop searching if |target_version| is located.
360     if (selected_version && target_version &&
361         *selected_version == *target_version) {
362       break;
363     }
364   }
365
366   // No suitable version was found.
367   if (!selected_version || bundled_version >= *selected_version) {
368     return absl::nullopt;
369   }
370
371   registration_info->version = selected_version.value();
372   registration_info->manifest = std::move(*selected_manifest);
373   registration_info->install_dir = selected_path;
374   base::ReadFileToString(selected_path.AppendASCII("manifest.fingerprint"),
375                          &registration_info->fingerprint);
376
377   return selected_version;
378 }
379
380 void ComponentInstaller::DeleteUnselectedComponentVersions(
381     const base::FilePath& base_dir,
382     const absl::optional<base::Version>& selected_version) {
383   base::FileEnumerator file_enumerator(base_dir, false,
384                                        base::FileEnumerator::DIRECTORIES);
385
386   for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
387        path = file_enumerator.Next()) {
388     base::Version version(path.BaseName().MaybeAsASCII());
389     // Delete any component version directory that was not selected.
390     if (version.IsValid() &&
391         !(selected_version && version == *selected_version)) {
392       base::DeletePathRecursively(path);
393     }
394   }
395 }
396
397 absl::optional<base::FilePath> ComponentInstaller::GetComponentDirectory() {
398   base::FilePath base_component_dir;
399   if (!base::PathService::Get(DIR_COMPONENT_USER, &base_component_dir))
400     return absl::nullopt;
401   base::FilePath base_dir =
402       base_component_dir.Append(installer_policy_->GetRelativeInstallDir());
403   if (!base::CreateDirectory(base_dir)) {
404     VPLOG(0) << "Could not create the base directory for "
405              << installer_policy_->GetName() << " (" << base_dir.MaybeAsASCII()
406              << ").";
407     return absl::nullopt;
408   }
409
410 #if BUILDFLAG(IS_CHROMEOS_ASH)
411   base::FilePath base_dir_ = base_component_dir;
412   for (const base::FilePath::StringType& component :
413        installer_policy_->GetRelativeInstallDir().GetComponents()) {
414     base_dir_ = base_dir_.Append(component);
415     if (!base::SetPosixFilePermissions(base_dir_, 0755)) {
416       VPLOG(0) << "SetPosixFilePermissions failed: " << base_dir.value();
417       return absl::nullopt;
418     }
419   }
420 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
421
422   return base_dir;
423 }
424
425 void ComponentInstaller::StartRegistration(
426     const base::Version& registered_version,
427     scoped_refptr<RegistrationInfo> registration_info) {
428   VLOG(1) << __func__ << " for " << installer_policy_->GetName();
429   DCHECK(task_runner_);
430   DCHECK(task_runner_->RunsTasksInCurrentSequence());
431
432   // First check for an installation set up alongside Chrome itself.
433   base::FilePath root;
434   if (base::PathService::Get(DIR_COMPONENT_PREINSTALLED, &root) &&
435       FindPreinstallation(root, registration_info)) {
436   }
437
438   // If there is a distinct alternate root, check there as well, and override
439   // anything found in the basic root.
440   base::FilePath root_alternate;
441   if (base::PathService::Get(DIR_COMPONENT_PREINSTALLED_ALT, &root_alternate) &&
442       root != root_alternate &&
443       FindPreinstallation(root_alternate, registration_info)) {
444   }
445
446   absl::optional<base::FilePath> base_dir = GetComponentDirectory();
447
448   if (!base_dir) {
449     return;
450   }
451
452   DeleteUnselectedComponentVersions(
453       base_dir.value(),
454       SelectComponentVersion(registered_version, base_dir.value(),
455                              registration_info));
456 }
457
458 void ComponentInstaller::UninstallOnTaskRunner() {
459   DCHECK(task_runner_);
460   DCHECK(task_runner_->RunsTasksInCurrentSequence());
461
462   // Only try to delete any files that are in our user-level install path.
463   base::FilePath userInstallPath;
464   if (!base::PathService::Get(DIR_COMPONENT_USER, &userInstallPath))
465     return;
466   if (!userInstallPath.IsParent(current_install_dir_))
467     return;
468
469   const base::FilePath base_dir = current_install_dir_.DirName();
470   base::FileEnumerator file_enumerator(base_dir, false,
471                                        base::FileEnumerator::DIRECTORIES);
472   for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
473        path = file_enumerator.Next()) {
474     base::Version version(path.BaseName().MaybeAsASCII());
475
476     // Ignore folders that don't have valid version names. These folders are not
477     // managed by the component installer, so do not try to remove them.
478     if (!version.IsValid())
479       continue;
480
481     if (!base::DeletePathRecursively(path))
482       DVLOG(0) << "Couldn't delete " << path.value();
483   }
484
485   // Delete the base directory if it's empty now.
486   if (base::IsDirectoryEmpty(base_dir)) {
487     if (!base::DeleteFile(base_dir))
488       DVLOG(0) << "Couldn't delete " << base_dir.value();
489   }
490
491   // Customized operations for individual component.
492   installer_policy_->OnCustomUninstall();
493 }
494
495 void ComponentInstaller::FinishRegistration(
496     scoped_refptr<RegistrationInfo> registration_info,
497     RegisterCallback register_callback,
498     base::OnceClosure callback) {
499   VLOG(1) << __func__ << " for " << installer_policy_->GetName();
500   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
501
502   current_install_dir_ = registration_info->install_dir;
503   current_version_ = registration_info->version;
504   current_fingerprint_ = registration_info->fingerprint;
505
506   std::vector<uint8_t> public_key_hash;
507   installer_policy_->GetHash(&public_key_hash);
508
509   if (!std::move(register_callback)
510            .Run(ComponentRegistration(
511                update_client::GetCrxIdFromPublicKeyHash(public_key_hash),
512                installer_policy_->GetName(), public_key_hash, current_version_,
513                current_fingerprint_,
514                installer_policy_->GetInstallerAttributes(), action_handler_,
515                this, installer_policy_->RequiresNetworkEncryption(),
516                installer_policy_
517                    ->SupportsGroupPolicyEnabledComponentUpdates()))) {
518     VLOG(0) << "Component registration failed for "
519             << installer_policy_->GetName();
520     if (!callback.is_null())
521       std::move(callback).Run();
522     return;
523   }
524
525   if (registration_info->manifest) {
526     ComponentReady(std::move(*registration_info->manifest));
527   } else {
528     DVLOG(1) << "No component found for " << installer_policy_->GetName();
529   }
530
531   if (!callback.is_null())
532     std::move(callback).Run();
533 }
534
535 void ComponentInstaller::ComponentReady(base::Value::Dict manifest) {
536   VLOG(1) << "Component ready, version " << current_version_.GetString()
537           << " in " << current_install_dir_.value();
538   installer_policy_->ComponentReady(current_version_, current_install_dir_,
539                                     std::move(manifest));
540 }
541
542 }  // namespace component_updater