blob: f3aaaa4dbbecfa2177ea1268f47c19a1ae831c01 [file] [log] [blame]
// Copyright 2019 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 "content/browser/content_index/content_index_database.h"
#include <set>
#include <string>
#include "base/barrier_closure.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/task/post_task.h"
#include "base/time/time.h"
#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/content_index/content_index.pb.h"
#include "content/browser/content_index/content_index_metrics.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
#include "url/origin.h"
// TODO(crbug.com/973844): Move image utility functions to common library.
using content::background_fetch::DeserializeIcon;
using content::background_fetch::SerializeIcon;
namespace content {
namespace {
constexpr char kEntryPrefix[] = "content_index:entry_";
constexpr char kIconPrefix[] = "content_index:icon_";
std::string EntryKey(const std::string& id) {
return kEntryPrefix + id;
}
std::string IconsKey(const std::string& id) {
return kIconPrefix + id;
}
std::string CreateSerializedContentEntry(
const blink::mojom::ContentDescription& description,
const GURL& launch_url,
base::Time entry_time) {
// Convert description.
proto::ContentDescription description_proto;
description_proto.set_id(description.id);
description_proto.set_title(description.title);
description_proto.set_description(description.description);
description_proto.set_category(static_cast<int>(description.category));
for (const auto& icon : description.icons) {
auto* icon_proto = description_proto.add_icons();
icon_proto->set_src(icon->src);
if (icon->sizes)
icon_proto->set_sizes(*icon->sizes);
if (icon->type)
icon_proto->set_type(*icon->type);
}
description_proto.set_launch_url(description.launch_url);
// Create entry.
proto::ContentEntry entry;
*entry.mutable_description() = std::move(description_proto);
entry.set_launch_url(launch_url.spec());
entry.set_timestamp(entry_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
return entry.SerializeAsString();
}
blink::mojom::ContentDescriptionPtr DescriptionFromProto(
const proto::ContentDescription& description) {
// Validate.
if (description.category() <
static_cast<int>(blink::mojom::ContentCategory::kMinValue) ||
description.category() >
static_cast<int>(blink::mojom::ContentCategory::kMaxValue)) {
return nullptr;
}
// Convert.
auto result = blink::mojom::ContentDescription::New();
result->id = description.id();
result->title = description.title();
result->description = description.description();
result->category =
static_cast<blink::mojom::ContentCategory>(description.category());
for (const auto& icon : description.icons()) {
auto mojo_icon = blink::mojom::ContentIconDefinition::New();
mojo_icon->src = icon.src();
if (icon.has_sizes())
mojo_icon->sizes = icon.sizes();
if (icon.has_type())
mojo_icon->type = icon.type();
result->icons.push_back(std::move(mojo_icon));
}
result->launch_url = description.launch_url();
return result;
}
base::Optional<ContentIndexEntry> EntryFromSerializedProto(
int64_t service_worker_registration_id,
const std::string& serialized_proto) {
proto::ContentEntry entry_proto;
if (!entry_proto.ParseFromString(serialized_proto))
return base::nullopt;
GURL launch_url(entry_proto.launch_url());
if (!launch_url.is_valid())
return base::nullopt;
auto description = DescriptionFromProto(entry_proto.description());
base::Time registration_time = base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(entry_proto.timestamp()));
return ContentIndexEntry(service_worker_registration_id,
std::move(description), std::move(launch_url),
registration_time);
}
} // namespace
ContentIndexDatabase::ContentIndexDatabase(
BrowserContext* browser_context,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
: provider_(browser_context->GetContentIndexProvider()),
service_worker_context_(std::move(service_worker_context)) {}
ContentIndexDatabase::~ContentIndexDatabase() = default;
void ContentIndexDatabase::AddEntry(
int64_t service_worker_registration_id,
const url::Origin& origin,
blink::mojom::ContentDescriptionPtr description,
const std::vector<SkBitmap>& icons,
const GURL& launch_url,
blink::mojom::ContentIndexService::AddCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](blink::mojom::ContentIndexService::AddCallback callback,
blink::mojom::ContentIndexError error) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), error));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::AddEntryOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin,
std::move(description), icons, launch_url,
std::move(wrapped_callback)));
}
void ContentIndexDatabase::AddEntryOnCoreThread(
int64_t service_worker_registration_id,
const url::Origin& origin,
blink::mojom::ContentDescriptionPtr description,
const std::vector<SkBitmap>& icons,
const GURL& launch_url,
blink::mojom::ContentIndexService::AddCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (blocked_origins_.count(origin)) {
// TODO(crbug.com/973844): Does this need a more specific error?
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
content_index::RecordRegistrationBlocked(description->category);
return;
}
auto* service_worker_registration =
service_worker_context_->GetLiveRegistration(
service_worker_registration_id);
if (!service_worker_registration ||
!service_worker_registration->active_version()) {
std::move(callback).Run(blink::mojom::ContentIndexError::NO_SERVICE_WORKER);
return;
}
auto serialized_icons = std::make_unique<proto::SerializedIcons>();
proto::SerializedIcons* serialized_icons_ptr = serialized_icons.get();
auto barrier_closure = base::BarrierClosure(
icons.size(),
base::BindOnce(&ContentIndexDatabase::DidSerializeIcons,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin,
std::move(description), launch_url,
std::move(serialized_icons), std::move(callback)));
for (const auto& icon : icons) {
SerializeIcon(icon,
base::BindOnce(
[](base::OnceClosure done_closure,
proto::SerializedIcons* icons, std::string icon) {
icons->add_icons()->set_icon(std::move(icon));
std::move(done_closure).Run();
},
barrier_closure, serialized_icons_ptr));
}
}
void ContentIndexDatabase::DidSerializeIcons(
int64_t service_worker_registration_id,
const url::Origin& origin,
blink::mojom::ContentDescriptionPtr description,
const GURL& launch_url,
std::unique_ptr<proto::SerializedIcons> serialized_icons,
blink::mojom::ContentIndexService::AddCallback callback) {
base::Time entry_time = base::Time::Now();
std::string entry_key = EntryKey(description->id);
std::string icon_key = IconsKey(description->id);
std::string entry_value =
CreateSerializedContentEntry(*description, launch_url, entry_time);
std::string icons_value = serialized_icons->SerializeAsString();
// Entry to pass over to the provider.
ContentIndexEntry entry(service_worker_registration_id,
std::move(description), launch_url, entry_time);
service_worker_context_->StoreRegistrationUserData(
service_worker_registration_id, origin.GetURL(),
{{std::move(entry_key), std::move(entry_value)},
{std::move(icon_key), std::move(icons_value)}},
base::BindOnce(&ContentIndexDatabase::DidAddEntry,
weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
std::move(entry)));
}
void ContentIndexDatabase::DidAddEntry(
blink::mojom::ContentIndexService::AddCallback callback,
ContentIndexEntry entry,
blink::ServiceWorkerStatusCode status) {
content_index::RecordDatabaseOperationStatus("Add", status);
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
return;
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
std::vector<ContentIndexEntry> entries;
entries.push_back(std::move(entry));
base::PostTask(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&ContentIndexDatabase::NotifyProviderContentAdded,
weak_ptr_factory_ui_.GetWeakPtr(), std::move(entries)));
}
void ContentIndexDatabase::DeleteEntry(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& entry_id,
blink::mojom::ContentIndexService::DeleteCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](blink::mojom::ContentIndexService::DeleteCallback callback,
blink::mojom::ContentIndexError error) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), error));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin, entry_id,
std::move(wrapped_callback)));
}
void ContentIndexDatabase::DeleteEntryOnCoreThread(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& entry_id,
blink::mojom::ContentIndexService::DeleteCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->ClearRegistrationUserData(
service_worker_registration_id, {EntryKey(entry_id), IconsKey(entry_id)},
base::BindOnce(&ContentIndexDatabase::DidDeleteEntry,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin, entry_id,
std::move(callback)));
}
void ContentIndexDatabase::DidDeleteEntry(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& entry_id,
blink::mojom::ContentIndexService::DeleteCallback callback,
blink::ServiceWorkerStatusCode status) {
content_index::RecordDatabaseOperationStatus("Delete", status);
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
return;
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
base::PostTask(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&ContentIndexDatabase::NotifyProviderContentDeleted,
weak_ptr_factory_ui_.GetWeakPtr(),
service_worker_registration_id, origin, entry_id));
}
void ContentIndexDatabase::GetDescriptions(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
blink::mojom::ContentIndexError error,
std::vector<blink::mojom::ContentDescriptionPtr> descriptions) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), error,
std::move(descriptions)));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::GetDescriptionsOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id,
std::move(wrapped_callback)));
}
void ContentIndexDatabase::GetDescriptionsOnCoreThread(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->GetRegistrationUserDataByKeyPrefix(
service_worker_registration_id, kEntryPrefix,
base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, std::move(callback)));
}
void ContentIndexDatabase::DidGetDescriptions(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
content_index::RecordDatabaseOperationStatus("GetDescriptions", status);
if (status == blink::ServiceWorkerStatusCode::kErrorNotFound) {
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
/* descriptions= */ {});
return;
} else if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {});
return;
}
std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
descriptions.reserve(data.size());
for (const auto& serialized_entry : data) {
proto::ContentEntry entry;
if (!entry.ParseFromString(serialized_entry)) {
ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {});
return;
}
auto description = DescriptionFromProto(entry.description());
if (!description) {
// Clear entry data.
service_worker_context_->ClearRegistrationUserData(
service_worker_registration_id,
{EntryKey(entry.description().id()),
IconsKey(entry.description().id())},
base::BindOnce(&content_index::RecordDatabaseOperationStatus,
"ClearCorruptedData"));
continue;
}
descriptions.push_back(std::move(description));
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
std::move(descriptions));
}
void ContentIndexDatabase::GetIcons(
int64_t service_worker_registration_id,
const std::string& description_id,
ContentIndexContext::GetIconsCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](ContentIndexContext::GetIconsCallback callback,
std::vector<SkBitmap> icons) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), std::move(icons)));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::GetIconsOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, description_id,
std::move(wrapped_callback)));
}
void ContentIndexDatabase::GetIconsOnCoreThread(
int64_t service_worker_registration_id,
const std::string& description_id,
ContentIndexContext::GetIconsCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->GetRegistrationUserData(
service_worker_registration_id, {IconsKey(description_id)},
base::BindOnce(&ContentIndexDatabase::DidGetSerializedIcons,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, std::move(callback)));
}
void ContentIndexDatabase::DidGetSerializedIcons(
int64_t service_worker_registration_id,
ContentIndexContext::GetIconsCallback callback,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
content_index::RecordDatabaseOperationStatus("GetIcon", status);
if (status != blink::ServiceWorkerStatusCode::kOk || data.empty()) {
std::move(callback).Run({});
return;
}
DCHECK_EQ(data.size(), 1u);
proto::SerializedIcons serialized_icons;
if (!serialized_icons.ParseFromString(data.front())) {
ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
std::move(callback).Run({});
return;
}
if (serialized_icons.icons_size() == 0u) {
// There are no icons.
std::move(callback).Run({});
return;
}
auto icons = std::make_unique<std::vector<SkBitmap>>();
std::vector<SkBitmap>* icons_ptr = icons.get();
auto barrier_closure = base::BarrierClosure(
serialized_icons.icons_size(),
base::BindOnce(&ContentIndexDatabase::DidDeserializeIcons,
weak_ptr_factory_core_.GetWeakPtr(), std::move(callback),
std::move(icons)));
for (auto& serialized_icon : *serialized_icons.mutable_icons()) {
DeserializeIcon(base::WrapUnique(serialized_icon.release_icon()),
base::BindOnce(
[](base::OnceClosure done_closure,
std::vector<SkBitmap>* icons, SkBitmap icon) {
icons->push_back(std::move(icon));
std::move(done_closure).Run();
},
barrier_closure, icons_ptr));
}
}
void ContentIndexDatabase::DidDeserializeIcons(
ContentIndexContext::GetIconsCallback callback,
std::unique_ptr<std::vector<SkBitmap>> icons) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
RunOrPostTaskOnThread(FROM_HERE, BrowserThread::UI,
base::BindOnce(std::move(callback), std::move(*icons)));
}
void ContentIndexDatabase::GetAllEntries(
ContentIndexContext::GetAllEntriesCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](ContentIndexContext::GetAllEntriesCallback callback,
blink::mojom::ContentIndexError error,
std::vector<ContentIndexEntry> entries) {
base::PostTask(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), error, std::move(entries)));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::GetAllEntriesOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
std::move(wrapped_callback)));
}
void ContentIndexDatabase::GetAllEntriesOnCoreThread(
ContentIndexContext::GetAllEntriesCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->GetUserDataForAllRegistrationsByKeyPrefix(
kEntryPrefix,
base::BindOnce(&ContentIndexDatabase::DidGetEntries,
weak_ptr_factory_core_.GetWeakPtr(), std::move(callback)));
}
void ContentIndexDatabase::DidGetEntries(
ContentIndexContext::GetAllEntriesCallback callback,
const std::vector<std::pair<int64_t, std::string>>& user_data,
blink::ServiceWorkerStatusCode status) {
content_index::RecordDatabaseOperationStatus("GetAllEntries", status);
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* entries= */ {});
return;
}
if (user_data.empty()) {
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
/* entries= */ {});
return;
}
std::vector<ContentIndexEntry> entries;
entries.reserve(user_data.size());
std::set<int64_t> corrupted_sw_ids;
for (const auto& ud : user_data) {
auto entry = EntryFromSerializedProto(ud.first, ud.second);
if (!entry) {
corrupted_sw_ids.insert(ud.first);
continue;
}
entries.emplace_back(std::move(*entry));
}
if (!corrupted_sw_ids.empty()) {
// Remove soon-to-be-deleted entries.
base::EraseIf(entries, [&corrupted_sw_ids](const auto& entry) {
return corrupted_sw_ids.count(entry.service_worker_registration_id);
});
for (int64_t service_worker_registration_id : corrupted_sw_ids)
ClearServiceWorkerDataOnCorruption(service_worker_registration_id);
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
std::move(entries));
}
void ContentIndexDatabase::GetEntry(
int64_t service_worker_registration_id,
const std::string& description_id,
ContentIndexContext::GetEntryCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto wrapped_callback = base::BindOnce(
[](ContentIndexContext::GetEntryCallback callback,
base::Optional<ContentIndexEntry> entry) {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), std::move(entry)));
},
std::move(callback));
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::GetEntryOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, description_id,
std::move(wrapped_callback)));
}
void ContentIndexDatabase::GetEntryOnCoreThread(
int64_t service_worker_registration_id,
const std::string& description_id,
ContentIndexContext::GetEntryCallback callback) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->GetRegistrationUserData(
service_worker_registration_id, {EntryKey(description_id)},
base::BindOnce(&ContentIndexDatabase::DidGetEntry,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, std::move(callback)));
}
void ContentIndexDatabase::DidGetEntry(
int64_t service_worker_registration_id,
ContentIndexContext::GetEntryCallback callback,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
content_index::RecordDatabaseOperationStatus("GetEntry", status);
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(base::nullopt);
return;
}
DCHECK_EQ(data.size(), 1u);
std::move(callback).Run(
EntryFromSerializedProto(service_worker_registration_id, data.front()));
}
void ContentIndexDatabase::ClearServiceWorkerDataOnCorruption(
int64_t service_worker_registration_id) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
service_worker_context_->ClearRegistrationUserDataByKeyPrefixes(
service_worker_registration_id, {kEntryPrefix, kIconPrefix},
base::BindOnce(&content_index::RecordDatabaseOperationStatus,
"ClearCorruptedData"));
}
void ContentIndexDatabase::DeleteItem(int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& description_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&ContentIndexDatabase::DeleteEntryOnCoreThread,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin, description_id,
base::BindOnce(&ContentIndexDatabase::DidDeleteItem,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker_registration_id, origin,
description_id)));
}
void ContentIndexDatabase::DidDeleteItem(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& description_id,
blink::mojom::ContentIndexError error) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (error != blink::mojom::ContentIndexError::NONE)
return;
service_worker_context_->FindReadyRegistrationForId(
service_worker_registration_id, origin.GetURL(),
base::BindOnce(&ContentIndexDatabase::StartActiveWorkerForDispatch,
weak_ptr_factory_core_.GetWeakPtr(), description_id));
}
void ContentIndexDatabase::StartActiveWorkerForDispatch(
const std::string& description_id,
blink::ServiceWorkerStatusCode service_worker_status,
scoped_refptr<ServiceWorkerRegistration> registration) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
content_index::RecordDisptachStatus("Find", service_worker_status);
if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
return;
ServiceWorkerVersion* service_worker_version = registration->active_version();
DCHECK(service_worker_version);
service_worker_version->RunAfterStartWorker(
ServiceWorkerMetrics::EventType::CONTENT_DELETE,
base::BindOnce(&ContentIndexDatabase::DeliverMessageToWorker,
weak_ptr_factory_core_.GetWeakPtr(),
base::WrapRefCounted(service_worker_version),
std::move(registration), description_id));
}
void ContentIndexDatabase::DeliverMessageToWorker(
scoped_refptr<ServiceWorkerVersion> service_worker,
scoped_refptr<ServiceWorkerRegistration> registration,
const std::string& description_id,
blink::ServiceWorkerStatusCode service_worker_status) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
content_index::RecordDisptachStatus("Start", service_worker_status);
if (service_worker_status != blink::ServiceWorkerStatusCode::kOk)
return;
// Don't allow DB operations while the `contentdelete` event is firing.
// This is to prevent re-registering the deleted content within the event.
BlockOrigin(service_worker->script_origin());
int request_id = service_worker->StartRequest(
ServiceWorkerMetrics::EventType::CONTENT_DELETE,
base::BindOnce(&ContentIndexDatabase::DidDispatchEvent,
weak_ptr_factory_core_.GetWeakPtr(),
service_worker->script_origin()));
service_worker->endpoint()->DispatchContentDeleteEvent(
description_id, service_worker->CreateSimpleEventCallback(request_id));
}
void ContentIndexDatabase::DidDispatchEvent(
const url::Origin& origin,
blink::ServiceWorkerStatusCode service_worker_status) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
content_index::RecordDisptachStatus("Dispatch", service_worker_status);
UnblockOrigin(origin);
}
void ContentIndexDatabase::BlockOrigin(const url::Origin& origin) {
blocked_origins_[origin]++;
}
void ContentIndexDatabase::UnblockOrigin(const url::Origin& origin) {
DCHECK(blocked_origins_.count(origin));
auto it = blocked_origins_.find(origin);
if (it->second == 1)
blocked_origins_.erase(it);
else
it->second--;
}
void ContentIndexDatabase::Shutdown() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
provider_ = nullptr;
}
void ContentIndexDatabase::NotifyProviderContentAdded(
std::vector<ContentIndexEntry> entries) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!provider_)
return;
for (auto& entry : entries)
provider_->OnContentAdded(std::move(entry));
}
void ContentIndexDatabase::NotifyProviderContentDeleted(
int64_t service_worker_registration_id,
const url::Origin& origin,
const std::string& entry_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!provider_)
return;
provider_->OnContentDeleted(service_worker_registration_id, origin, entry_id);
}
} // namespace content