910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/android/webapk/webapk_database.h"

#include <memory>
#include <string>

#include "base/check.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "chrome/browser/android/webapk/proto/webapk_database.pb.h"
#include "chrome/browser/android/webapk/webapk_registry_update.h"
#include "chrome/browser/android/webapk/webapk_sync_bridge.h"
#include "components/sync/model/data_type_store.h"
#include "components/sync/model/data_type_store_service.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "components/sync/protocol/web_apk_specifics.pb.h"

namespace webapk {
WebApkDatabase::WebApkDatabase(
    syncer::DataTypeStoreService* data_type_store_service,
    ReportErrorCallback error_callback)
    : data_type_store_service_(data_type_store_service),
      error_callback_(std::move(error_callback)) {
  CHECK(data_type_store_service_);
}

WebApkDatabase::~WebApkDatabase() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

void WebApkDatabase::OpenDatabase(RegistryOpenedCallback callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  CHECK(!store_);

  syncer::OnceDataTypeStoreFactory store_factory =
      data_type_store_service_->GetStoreFactory();

  std::move(store_factory)
      .Run(syncer::WEB_APKS,
           base::BindOnce(&WebApkDatabase::OnDatabaseOpened,
                          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void WebApkDatabase::Write(
    const RegistryUpdateData& update_data,
    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
    CompletionCallback callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  CHECK(opened_);

  std::unique_ptr<syncer::DataTypeStore::WriteBatch> write_batch =
      store_->CreateWriteBatch();

  // |update_data| can be empty here but we should write |metadata_change_list|
  // anyway.
  write_batch->TakeMetadataChangesFrom(std::move(metadata_change_list));

  for (const std::unique_ptr<WebApkProto>& webapk :
       update_data.apps_to_create) {
    write_batch->WriteData(
        ManifestIdStrToAppId(webapk->sync_data().manifest_id()),
        webapk->SerializeAsString());
  }

  for (const std::string& app_id : update_data.apps_to_delete) {
    write_batch->DeleteData(app_id);
  }

  store_->CommitWriteBatch(
      std::move(write_batch),
      base::BindOnce(&WebApkDatabase::OnDataWritten,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void WebApkDatabase::DeleteAllDataAndMetadata(
    syncer::DataTypeStore::CallbackWithResult callback) {
  CHECK(store_);
  store_->DeleteAllDataAndMetadata(std::move(callback));
}

void WebApkDatabase::OnDatabaseOpened(
    RegistryOpenedCallback callback,
    const std::optional<syncer::ModelError>& error,
    std::unique_ptr<syncer::DataTypeStore> store) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  if (error) {
    error_callback_.Run(*error);
    DLOG(ERROR) << "WebApks LevelDB opening error: " << error->ToString();
    return;
  }

  store_ = std::move(store);
  store_->ReadAllDataAndMetadata(
      base::BindOnce(&WebApkDatabase::OnAllDataAndMetadataRead,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void WebApkDatabase::OnAllDataAndMetadataRead(
    RegistryOpenedCallback callback,
    const std::optional<syncer::ModelError>& error,
    std::unique_ptr<syncer::DataTypeStore::RecordList> data_records,
    std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (error) {
    error_callback_.Run(*error);
    DLOG(ERROR) << "WebApks LevelDB read error: " << error->ToString();
    return;
  }

  Registry registry;
  for (const syncer::DataTypeStore::Record& record : *data_records) {
    std::unique_ptr<WebApkProto> proto = std::make_unique<WebApkProto>();
    const bool parsed = proto->ParseFromString(record.value);
    if (!parsed) {
      DLOG(ERROR) << "WebApks LevelDB parse error: can't parse proto.";
    }

    registry.emplace(record.id, std::move(proto));
  }

  RecordSyncedWebApkCountHistogram(registry.size());

  opened_ = true;
  // This should be a tail call: a callback code may indirectly call |this|
  // methods, like WebApkDatabase::Write()
  std::move(callback).Run(std::move(registry), std::move(metadata_batch));
}

void WebApkDatabase::OnDataWritten(
    CompletionCallback callback,
    const std::optional<syncer::ModelError>& error) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (error) {
    error_callback_.Run(*error);
    DLOG(ERROR) << "WebApks LevelDB write error: " << error->ToString();
  }

  std::move(callback).Run(!error);
}

void WebApkDatabase::RecordSyncedWebApkCountHistogram(int num_web_apks) const {
  base::UmaHistogramExactLinear("WebApk.Sync.SyncedWebApkCount", num_web_apks,
                                51 /* max_count */);
}

}  // namespace webapk