blob: 0788d1bca01adabf613a08316352aca1a6eaac18 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/nonembedded/component_updater/aw_component_update_service.h"
#include <memory>
#include "android_webview/common/aw_paths.h"
#include "android_webview/nonembedded/component_updater/aw_component_updater_configurator.h"
#include "android_webview/nonembedded/component_updater/registration.h"
#include "android_webview/nonembedded/nonembedded_jni_headers/AwComponentUpdateService_jni.h"
#include "android_webview/nonembedded/webview_apk_process.h"
#include "base/android/callback_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/component_updater/component_installer.h"
#include "components/component_updater/component_updater_paths.h"
#include "components/component_updater/component_updater_service.h"
#include "components/component_updater/component_updater_utils.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/update_client.h"
namespace android_webview {
// static
AwComponentUpdateService* AwComponentUpdateService::GetInstance() {
static base::NoDestructor<AwComponentUpdateService> instance;
return instance.get();
}
// static
void JNI_AwComponentUpdateService_StartComponentUpdateService(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_finished_callback) {
// Has to be called after init WebViewApkProcess, should only happen once
// during the lifetime of webview_apk process.
component_updater::RegisterPathProvider(
/*components_system_root_key=*/android_webview::DIR_COMPONENTS_ROOT,
/*components_system_root_key_alt=*/android_webview::DIR_COMPONENTS_ROOT,
/*components_user_root_key=*/android_webview::DIR_COMPONENTS_ROOT);
AwComponentUpdateService::GetInstance()->StartComponentUpdateService(
base::BindOnce(
&base::android::RunIntCallbackAndroid,
base::android::ScopedJavaGlobalRef<jobject>(j_finished_callback)));
}
AwComponentUpdateService::AwComponentUpdateService()
: AwComponentUpdateService(MakeAwComponentUpdaterConfigurator(
base::CommandLine::ForCurrentProcess(),
WebViewApkProcess::GetInstance()->GetPrefService())) {}
AwComponentUpdateService::AwComponentUpdateService(
scoped_refptr<update_client::Configurator> configurator)
: update_client_(update_client::UpdateClientFactory(configurator)) {}
AwComponentUpdateService::~AwComponentUpdateService() = default;
// Start ComponentUpdateService once.
void AwComponentUpdateService::StartComponentUpdateService(
UpdateCallback finished_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
RegisterComponents(
base::BindRepeating(&AwComponentUpdateService::RegisterComponent,
base::Unretained(this)),
base::BindOnce(
&AwComponentUpdateService::ScheduleUpdatesOfRegisteredComponents,
weak_ptr_factory_.GetWeakPtr(), std::move(finished_callback)));
}
bool AwComponentUpdateService::RegisterComponent(
const update_client::CrxComponent& component) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/1180595): Add the histograms being logged in
// CrxUpdateService once we support logging metrics from nonembedded WebView.
if (component.app_id.empty() || !component.version.IsValid() ||
!component.installer) {
return false;
}
// Update the registration data if the component has been registered before.
auto it = components_.find(component.app_id);
if (it != components_.end()) {
it->second = component;
return true;
}
components_.insert(std::make_pair(component.app_id, component));
components_order_.push_back(component.app_id);
return true;
}
void AwComponentUpdateService::CheckForUpdates(UpdateCallback on_finished) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/1180595): Add the histograms being logged in
// CrxUpdateService once we support logging metrics from nonembedded WebView.
std::vector<std::string> secure_ids; // Require HTTPS for update checks.
std::vector<std::string> unsecure_ids; // Can fallback to HTTP.
for (const auto& id : components_order_) {
DCHECK(components_.find(id) != components_.end());
const auto component = component_updater::GetComponent(components_, id);
if (!component || component->requires_network_encryption)
secure_ids.push_back(id);
else
unsecure_ids.push_back(id);
}
if (unsecure_ids.empty() && secure_ids.empty()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(on_finished), 0));
return;
}
auto on_finished_callback =
base::BindOnce(&AwComponentUpdateService::RecordComponentsUpdated,
weak_ptr_factory_.GetWeakPtr(), std::move(on_finished));
// Reset updated components counter.
components_updated_count_ = 0;
if (!unsecure_ids.empty()) {
update_client_->Update(
unsecure_ids,
base::BindOnce(&AwComponentUpdateService::GetCrxComponents,
base::Unretained(this)),
{}, false,
base::BindOnce(&AwComponentUpdateService::OnUpdateComplete,
weak_ptr_factory_.GetWeakPtr(),
secure_ids.empty() ? std::move(on_finished_callback)
: update_client::Callback(),
base::TimeTicks::Now()));
}
if (!secure_ids.empty()) {
update_client_->Update(
secure_ids,
base::BindOnce(&AwComponentUpdateService::GetCrxComponents,
base::Unretained(this)),
{}, false,
base::BindOnce(&AwComponentUpdateService::OnUpdateComplete,
weak_ptr_factory_.GetWeakPtr(),
std::move(on_finished_callback),
base::TimeTicks::Now()));
}
return;
}
void AwComponentUpdateService::OnUpdateComplete(
update_client::Callback callback,
const base::TimeTicks& start_time,
update_client::Error error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/1180595): Add the histograms being logged in
// CrxUpdateService once we support logging metrics from nonembedded WebView.
if (!callback.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), error));
}
}
absl::optional<update_client::CrxComponent>
AwComponentUpdateService::GetComponent(const std::string& id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return component_updater::GetComponent(components_, id);
}
std::vector<absl::optional<update_client::CrxComponent>>
AwComponentUpdateService::GetCrxComponents(
const std::vector<std::string>& ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return component_updater::GetCrxComponents(components_, ids);
}
void AwComponentUpdateService::ScheduleUpdatesOfRegisteredComponents(
UpdateCallback on_finished_updates) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CheckForUpdates(std::move(on_finished_updates));
}
void AwComponentUpdateService::RegisterComponents(
RegisterComponentsCallback register_callback,
base::OnceClosure on_finished) {
RegisterComponentsForUpdate(register_callback, std::move(on_finished));
}
void AwComponentUpdateService::IncrementComponentsUpdatedCount() {
components_updated_count_++;
}
void AwComponentUpdateService::RecordComponentsUpdated(
UpdateCallback on_finished,
update_client::Error error) {
std::move(on_finished).Run(components_updated_count_);
}
} // namespace android_webview