Commit 91b8d879 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

Reland "Reland "[Background Fetch] Move all updatable UI options to their own proto.""

This is a reland of 9311d412

TBR=avi@chromium.org

Original change's description:
> Reland "[Background Fetch] Move all updatable UI options to their own proto."
>
> This is a reland of d3981964
>
> TBR=avi@chromium.org
>
> Original change's description:
> > [Background Fetch] Move all updatable UI options to their own proto.
> >
> > Bundle up the icon and the title since they will be accessed/modified
> > together in the updateUI call.
> >
> > It also makes sense to move the icon from the metadata proto since that
> > will speed up getting the registration info.
> >
> > TBR=avi@chromium.org
> >
> > Bug: 865063
> > Change-Id: I661062f19fddfa6b9c3bf11b5e146d5289a02593
> > Reviewed-on: https://chromium-review.googlesource.com/1146650
> > Commit-Queue: Rayan Kanso <rayankans@chromium.org>
> > Reviewed-by: Avi Drissman <avi@chromium.org>
> > Reviewed-by: Peter Beverloo <peter@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#577272}
>
> Bug: 865063
> Change-Id: I77567e8e2e0ea59ede514c77b40326e7ece48a25
> Reviewed-on: https://chromium-review.googlesource.com/1148261
> Commit-Queue: Rayan Kanso <rayankans@chromium.org>
> Reviewed-by: Peter Beverloo <peter@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#577500}

Bug: 865063
Change-Id: I766da48a901bc9da8e70acc02855b770f71e09e3
Reviewed-on: https://chromium-review.googlesource.com/1148361
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577843}
parent 2cfbe6ab
...@@ -446,6 +446,8 @@ jumbo_source_set("browser") { ...@@ -446,6 +446,8 @@ jumbo_source_set("browser") {
"background_fetch/storage/get_metadata_task.h", "background_fetch/storage/get_metadata_task.h",
"background_fetch/storage/get_settled_fetches_task.cc", "background_fetch/storage/get_settled_fetches_task.cc",
"background_fetch/storage/get_settled_fetches_task.h", "background_fetch/storage/get_settled_fetches_task.h",
"background_fetch/storage/image_helpers.cc",
"background_fetch/storage/image_helpers.h",
"background_fetch/storage/mark_registration_for_deletion_task.cc", "background_fetch/storage/mark_registration_for_deletion_task.cc",
"background_fetch/storage/mark_registration_for_deletion_task.h", "background_fetch/storage/mark_registration_for_deletion_task.h",
"background_fetch/storage/mark_request_complete_task.cc", "background_fetch/storage/mark_request_complete_task.cc",
......
...@@ -30,6 +30,8 @@ message BackgroundFetchRegistration { ...@@ -30,6 +30,8 @@ message BackgroundFetchRegistration {
// //
// Next Tag: 3 // Next Tag: 3
message BackgroundFetchOptions { message BackgroundFetchOptions {
// The initial title provided by the developer. This can be updated,
// and the most recent value is stored in BackgroundFetchUIOptions.
optional string title = 1; optional string title = 1;
// https://w3c.github.io/manifest/#dom-imageresource // https://w3c.github.io/manifest/#dom-imageresource
...@@ -66,7 +68,7 @@ message BackgroundFetchOptions { ...@@ -66,7 +68,7 @@ message BackgroundFetchOptions {
// in memory. This information should be everything needed to reconstruct // in memory. This information should be everything needed to reconstruct
// the state of an interrupted background fetch. // the state of an interrupted background fetch.
// //
// Next Tag: 7 // Next Tag: 6
message BackgroundFetchMetadata { message BackgroundFetchMetadata {
optional int64 creation_microseconds_since_unix_epoch = 1; optional int64 creation_microseconds_since_unix_epoch = 1;
optional string origin = 2; optional string origin = 2;
...@@ -76,10 +78,17 @@ message BackgroundFetchMetadata { ...@@ -76,10 +78,17 @@ message BackgroundFetchMetadata {
// Number of fetches initiated by the developer. // Number of fetches initiated by the developer.
optional int32 num_fetches = 5; optional int32 num_fetches = 5;
}
// All the updateable options that show up in the UI (e.g. notification).
//
// Next Tag: 3
message BackgroundFetchUIOptions {
optional string title = 1;
// Raw bytes needed to deserialize into a PNG icon. Only used if the icon // Raw bytes needed to deserialize into a PNG icon. Only used if the icon
// has a max resolution of 256x256. This means this is at most ~256KB. // has a max resolution of 256x256. This means this is at most ~256KB.
optional bytes icon = 6; optional bytes icon = 2;
} }
// A background fetch request that is still in a pending state. // A background fetch request that is still in a pending state.
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/guid.h" #include "base/guid.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_data_manager_observer.h" #include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
#include "content/browser/background_fetch/background_fetch_request_info.h" #include "content/browser/background_fetch/background_fetch_request_info.h"
#include "content/browser/background_fetch/background_fetch_request_match_params.h" #include "content/browser/background_fetch/background_fetch_request_match_params.h"
...@@ -407,6 +408,22 @@ class BackgroundFetchDataManagerTest ...@@ -407,6 +408,22 @@ class BackgroundFetchDataManagerTest
return result; return result;
} }
proto::BackgroundFetchUIOptions GetUIOptions(
int64_t service_worker_registration_id) {
auto results = GetRegistrationUserDataByKeyPrefix(
service_worker_registration_id, background_fetch::kUIOptionsKeyPrefix);
DCHECK_LT(results.size(), 2u)
<< "Using GetUIOptions with multiple registrations is unimplemented";
proto::BackgroundFetchUIOptions ui_options;
if (results.empty())
return ui_options;
bool did_parse = ui_options.ParseFromString(results[0]);
DCHECK(did_parse);
return ui_options;
}
// Gets information about the number of background fetch requests by state. // Gets information about the number of background fetch requests by state.
ResponseStateStats GetRequestStats(int64_t service_worker_registration_id) { ResponseStateStats GetRequestStats(int64_t service_worker_registration_id) {
ResponseStateStats stats; ResponseStateStats stats;
...@@ -763,7 +780,7 @@ TEST_F(BackgroundFetchDataManagerTest, LargeIconNotPersisted) { ...@@ -763,7 +780,7 @@ TEST_F(BackgroundFetchDataManagerTest, LargeIconNotPersisted) {
EXPECT_EQ(metadata->origin(), origin().Serialize()); EXPECT_EQ(metadata->origin(), origin().Serialize());
EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0); EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0);
EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size())); EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size()));
EXPECT_TRUE(metadata->icon().empty()); EXPECT_TRUE(GetUIOptions(sw_id).icon().empty());
} }
TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) { TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
...@@ -779,19 +796,14 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) { ...@@ -779,19 +796,14 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
blink::mojom::BackgroundFetchError error; blink::mojom::BackgroundFetchError error;
// There should be no title before the registration. // There should be no title before the registration.
std::vector<std::string> title = GetRegistrationUserDataByKeyPrefix( EXPECT_TRUE(GetUIOptions(sw_id).title().empty());
sw_id, background_fetch::kTitleKeyPrefix);
EXPECT_TRUE(title.empty());
// Create a single registration. // Create a single registration.
CreateRegistration(registration_id, requests, options, SkBitmap(), &error); CreateRegistration(registration_id, requests, options, SkBitmap(), &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// Verify that the title can be retrieved. // Verify that the title can be retrieved.
title = GetRegistrationUserDataByKeyPrefix(sw_id, ASSERT_EQ(GetUIOptions(sw_id).title(), kInitialTitle);
background_fetch::kTitleKeyPrefix);
EXPECT_EQ(title.size(), 1u);
ASSERT_EQ(title.front(), kInitialTitle);
// Update the title. // Update the title.
{ {
...@@ -804,10 +816,7 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) { ...@@ -804,10 +816,7 @@ TEST_F(BackgroundFetchDataManagerTest, UpdateRegistrationUI) {
RestartDataManagerFromPersistentStorage(); RestartDataManagerFromPersistentStorage();
// After a restart, GetMetadata should find the new title. // After a restart, GetMetadata should find the new title.
title = GetRegistrationUserDataByKeyPrefix(sw_id, ASSERT_EQ(GetUIOptions(sw_id).title(), kUpdatedTitle);
background_fetch::kTitleKeyPrefix);
EXPECT_EQ(title.size(), 1u);
ASSERT_EQ(title.front(), kUpdatedTitle);
} }
TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) { TEST_F(BackgroundFetchDataManagerTest, CreateAndDeleteRegistration) {
...@@ -1357,8 +1366,6 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) { ...@@ -1357,8 +1366,6 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
icon.eraseColor(SK_ColorGREEN); icon.eraseColor(SK_ColorGREEN);
CreateRegistration(registration_id, requests, options, icon, &error); CreateRegistration(registration_id, requests, options, icon, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
UpdateRegistrationUI(registration_id, kUpdatedTitle, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
{ {
std::vector<BackgroundFetchInitializationData> data = std::vector<BackgroundFetchInitializationData> data =
GetInitializationData(); GetInitializationData();
...@@ -1370,7 +1377,7 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) { ...@@ -1370,7 +1377,7 @@ TEST_F(BackgroundFetchDataManagerTest, GetInitializationData) {
EXPECT_EQ(init.registration.developer_id, kExampleDeveloperId); EXPECT_EQ(init.registration.developer_id, kExampleDeveloperId);
EXPECT_EQ(init.options.title, kInitialTitle); EXPECT_EQ(init.options.title, kInitialTitle);
EXPECT_EQ(init.options.download_total, 42u); EXPECT_EQ(init.options.download_total, 42u);
EXPECT_EQ(init.ui_title, kUpdatedTitle); EXPECT_EQ(init.ui_title, kInitialTitle);
EXPECT_EQ(init.num_requests, requests.size()); EXPECT_EQ(init.num_requests, requests.size());
EXPECT_EQ(init.num_completed_requests, 0u); EXPECT_EQ(init.num_completed_requests, 0u);
EXPECT_TRUE(init.active_fetch_guids.empty()); EXPECT_TRUE(init.active_fetch_guids.empty());
......
...@@ -26,8 +26,8 @@ value: "<serialized content::proto::BackgroundFetchMetadata>" ...@@ -26,8 +26,8 @@ value: "<serialized content::proto::BackgroundFetchMetadata>"
``` ```
``` ```
key: "bgfetch_title_<unique_id>" key: "bgfetch_ui_options_<unique_id>"
value: "<ui_title>" value: "<serialized content::proto::BackgroundFetchUIOptions>"
``` ```
``` ```
......
...@@ -6,37 +6,17 @@ ...@@ -6,37 +6,17 @@
#include <utility> #include <utility>
#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "content/browser/background_fetch/storage/database_helpers.h" #include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "ui/gfx/image/image.h"
namespace content { namespace content {
namespace background_fetch { namespace background_fetch {
namespace {
std::string ConvertAndSerializeIcon(const SkBitmap& icon) {
// Serialize the icon and copy the bytes over.
std::string serialized_icon;
auto icon_bytes = gfx::Image::CreateFrom1xBitmap(icon).As1xPNGBytes();
serialized_icon.assign(icon_bytes->front_as<char>(),
icon_bytes->front_as<char>() + icon_bytes->size());
return serialized_icon;
}
} // namespace
// The max icon resolution, this is used as a threshold to decide
// whether the icon should be persisted.
constexpr int kMaxIconResolution = 256 * 256;
CreateMetadataTask::CreateMetadataTask( CreateMetadataTask::CreateMetadataTask(
DatabaseTaskHost* host, DatabaseTaskHost* host,
const BackgroundFetchRegistrationId& registration_id, const BackgroundFetchRegistrationId& registration_id,
...@@ -66,8 +46,7 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data, ...@@ -66,8 +46,7 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) { blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) { switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kNotFound: case DatabaseStatus::kNotFound:
InitializeMetadataProto(); break;
return;
case DatabaseStatus::kOk: case DatabaseStatus::kOk:
// Can't create a registration since there is already an active // Can't create a registration since there is already an active
// registration with the same |developer_id|. It must be deactivated // registration with the same |developer_id|. It must be deactivated
...@@ -79,6 +58,17 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data, ...@@ -79,6 +58,17 @@ void CreateMetadataTask::DidGetUniqueId(const std::vector<std::string>& data,
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR); FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return; return;
} }
InitializeMetadataProto();
if (ShouldPersistIcon(icon_)) {
// Serialize the icon, then store all the metadata.
SerializeIcon(icon_, base::BindOnce(&CreateMetadataTask::DidSerializeIcon,
weak_factory_.GetWeakPtr()));
} else {
// Directly store the metadata.
StoreMetadata();
}
} }
void CreateMetadataTask::InitializeMetadataProto() { void CreateMetadataTask::InitializeMetadataProto() {
...@@ -126,35 +116,21 @@ void CreateMetadataTask::InitializeMetadataProto() { ...@@ -126,35 +116,21 @@ void CreateMetadataTask::InitializeMetadataProto() {
metadata_proto_->set_creation_microseconds_since_unix_epoch( metadata_proto_->set_creation_microseconds_since_unix_epoch(
(base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds()); (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds());
metadata_proto_->set_num_fetches(requests_.size()); metadata_proto_->set_num_fetches(requests_.size());
// Check if |icon_| should be persisted.
if (icon_.height() * icon_.width() > kMaxIconResolution) {
StoreMetadata();
return;
}
// Do the initialization on a seperate thread to avoid blocking on
// expensive operations (image conversions), then post back to IO thread
// and continue normally.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::BACKGROUND},
base::BindOnce(&ConvertAndSerializeIcon, icon_),
base::BindOnce(&CreateMetadataTask::StoreIcon,
weak_factory_.GetWeakPtr()));
} }
void CreateMetadataTask::StoreIcon(std::string serialized_icon) { void CreateMetadataTask::DidSerializeIcon(std::string serialized_icon) {
DCHECK(metadata_proto_); serialized_icon_ = std::move(serialized_icon);
metadata_proto_->set_icon(std::move(serialized_icon));
StoreMetadata(); StoreMetadata();
} }
void CreateMetadataTask::StoreMetadata() { void CreateMetadataTask::StoreMetadata() {
DCHECK(metadata_proto_); DCHECK(metadata_proto_);
std::vector<std::pair<std::string, std::string>> entries; std::vector<std::pair<std::string, std::string>> entries;
entries.reserve(requests_.size() * 2 + 1); // - One BackgroundFetchPendingRequest per request
// - DeveloperId -> UniqueID
// - BackgroundFetchMetadata
// - BackgroundFetchUIOptions
entries.reserve(requests_.size() + 3);
std::string serialized_metadata_proto; std::string serialized_metadata_proto;
...@@ -163,12 +139,24 @@ void CreateMetadataTask::StoreMetadata() { ...@@ -163,12 +139,24 @@ void CreateMetadataTask::StoreMetadata() {
return; return;
} }
std::string serialized_ui_options_proto;
proto::BackgroundFetchUIOptions ui_options;
ui_options.set_title(options_.title);
if (!serialized_icon_.empty())
ui_options.set_icon(std::move(serialized_icon_));
if (!ui_options.SerializeToString(&serialized_ui_options_proto)) {
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return;
}
entries.emplace_back( entries.emplace_back(
ActiveRegistrationUniqueIdKey(registration_id_.developer_id()), ActiveRegistrationUniqueIdKey(registration_id_.developer_id()),
registration_id_.unique_id()); registration_id_.unique_id());
entries.emplace_back(RegistrationKey(registration_id_.unique_id()), entries.emplace_back(RegistrationKey(registration_id_.unique_id()),
std::move(serialized_metadata_proto)); std::move(serialized_metadata_proto));
entries.emplace_back(TitleKey(registration_id_.unique_id()), options_.title); entries.emplace_back(UIOptionsKey(registration_id_.unique_id()),
serialized_ui_options_proto);
// Signed integers are used for request indexes to avoid unsigned gotchas. // Signed integers are used for request indexes to avoid unsigned gotchas.
for (int i = 0; i < base::checked_cast<int>(requests_.size()); i++) { for (int i = 0; i < base::checked_cast<int>(requests_.size()); i++) {
......
...@@ -41,7 +41,7 @@ class CreateMetadataTask : public DatabaseTask { ...@@ -41,7 +41,7 @@ class CreateMetadataTask : public DatabaseTask {
void DidGetUniqueId(const std::vector<std::string>& data, void DidGetUniqueId(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status); blink::ServiceWorkerStatusCode status);
void StoreIcon(std::string serialized_icon); void DidSerializeIcon(std::string serialized_icon);
void StoreMetadata(); void StoreMetadata();
...@@ -60,6 +60,8 @@ class CreateMetadataTask : public DatabaseTask { ...@@ -60,6 +60,8 @@ class CreateMetadataTask : public DatabaseTask {
std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_; std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_;
std::string serialized_icon_;
base::WeakPtrFactory<CreateMetadataTask> weak_factory_; // Keep as last. base::WeakPtrFactory<CreateMetadataTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(CreateMetadataTask); DISALLOW_COPY_AND_ASSIGN(CreateMetadataTask);
......
...@@ -23,8 +23,8 @@ std::string RegistrationKey(const std::string& unique_id) { ...@@ -23,8 +23,8 @@ std::string RegistrationKey(const std::string& unique_id) {
return kRegistrationKeyPrefix + unique_id; return kRegistrationKeyPrefix + unique_id;
} }
std::string TitleKey(const std::string& unique_id) { std::string UIOptionsKey(const std::string& unique_id) {
return kTitleKeyPrefix + unique_id; return kUIOptionsKeyPrefix + unique_id;
} }
std::string PendingRequestKeyPrefix(const std::string& unique_id) { std::string PendingRequestKeyPrefix(const std::string& unique_id) {
......
...@@ -24,16 +24,17 @@ const char kSeparator[] = "_"; ...@@ -24,16 +24,17 @@ const char kSeparator[] = "_";
const char kActiveRegistrationUniqueIdKeyPrefix[] = const char kActiveRegistrationUniqueIdKeyPrefix[] =
"bgfetch_active_registration_unique_id_"; "bgfetch_active_registration_unique_id_";
const char kRegistrationKeyPrefix[] = "bgfetch_registration_"; const char kRegistrationKeyPrefix[] = "bgfetch_registration_";
const char kTitleKeyPrefix[] = "bgfetch_title_"; const char kUIOptionsKeyPrefix[] = "bgfetch_ui_options_";
const char kPendingRequestKeyPrefix[] = "bgfetch_pending_request_"; const char kPendingRequestKeyPrefix[] = "bgfetch_pending_request_";
const char kActiveRequestKeyPrefix[] = "bgfetch_active_request_"; const char kActiveRequestKeyPrefix[] = "bgfetch_active_request_";
const char kCompletedRequestKeyPrefix[] = "bgfetch_completed_request_"; const char kCompletedRequestKeyPrefix[] = "bgfetch_completed_request_";
// Database Keys.
std::string ActiveRegistrationUniqueIdKey(const std::string& developer_id); std::string ActiveRegistrationUniqueIdKey(const std::string& developer_id);
std::string RegistrationKey(const std::string& unique_id); std::string RegistrationKey(const std::string& unique_id);
std::string TitleKey(const std::string& unique_id); std::string UIOptionsKey(const std::string& unique_id);
std::string PendingRequestKeyPrefix(const std::string& unique_id); std::string PendingRequestKeyPrefix(const std::string& unique_id);
...@@ -48,6 +49,7 @@ std::string CompletedRequestKeyPrefix(const std::string& unique_id); ...@@ -48,6 +49,7 @@ std::string CompletedRequestKeyPrefix(const std::string& unique_id);
std::string CompletedRequestKey(const std::string& unique_id, std::string CompletedRequestKey(const std::string& unique_id,
int request_index); int request_index);
// Database status.
enum class DatabaseStatus { kOk, kFailed, kNotFound }; enum class DatabaseStatus { kOk, kFailed, kNotFound };
DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status); DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status);
......
...@@ -107,7 +107,7 @@ void DeleteRegistrationTask::DidGetRegistration( ...@@ -107,7 +107,7 @@ void DeleteRegistrationTask::DidGetRegistration(
#endif // DCHECK_IS_ON() #endif // DCHECK_IS_ON()
std::vector<std::string> deletion_key_prefixes{ std::vector<std::string> deletion_key_prefixes{
RegistrationKey(unique_id_), TitleKey(unique_id_), RegistrationKey(unique_id_), UIOptionsKey(unique_id_),
PendingRequestKeyPrefix(unique_id_), ActiveRequestKeyPrefix(unique_id_), PendingRequestKeyPrefix(unique_id_), ActiveRequestKeyPrefix(unique_id_),
CompletedRequestKeyPrefix(unique_id_)}; CompletedRequestKeyPrefix(unique_id_)};
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "content/browser/background_fetch/background_fetch.pb.h" #include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/background_fetch_data_manager.h" #include "content/browser/background_fetch/background_fetch_data_manager.h"
#include "content/browser/background_fetch/storage/database_helpers.h" #include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/background_fetch/storage/image_helpers.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h" #include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "third_party/blink/public/common/manifest/manifest.h" #include "third_party/blink/public/common/manifest/manifest.h"
...@@ -69,26 +70,27 @@ class InitializationSubTask : public DatabaseTask { ...@@ -69,26 +70,27 @@ class InitializationSubTask : public DatabaseTask {
}; };
// Fills the BackgroundFetchInitializationData with the most recent UI title. // Fills the BackgroundFetchInitializationData with the most recent UI title.
class GetTitleTask : public InitializationSubTask { class GetUIOptionsTask : public InitializationSubTask {
public: public:
GetTitleTask(DatabaseTaskHost* host, GetUIOptionsTask(DatabaseTaskHost* host,
const SubTaskInit& sub_task_init, const SubTaskInit& sub_task_init,
base::OnceClosure done_closure) base::OnceClosure done_closure)
: InitializationSubTask(host, sub_task_init, std::move(done_closure)), : InitializationSubTask(host, sub_task_init, std::move(done_closure)),
weak_factory_(this) {} weak_factory_(this) {}
~GetTitleTask() override = default; ~GetUIOptionsTask() override = default;
void Start() override { void Start() override {
service_worker_context()->GetRegistrationUserData( service_worker_context()->GetRegistrationUserData(
sub_task_init().service_worker_registration_id, sub_task_init().service_worker_registration_id,
{TitleKey(sub_task_init().unique_id)}, {UIOptionsKey(sub_task_init().unique_id)},
base::BindOnce(&GetTitleTask::DidGetTitle, weak_factory_.GetWeakPtr())); base::BindOnce(&GetUIOptionsTask::DidGetUIOptions,
weak_factory_.GetWeakPtr()));
} }
private: private:
void DidGetTitle(const std::vector<std::string>& data, void DidGetUIOptions(const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) { blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) { switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kFailed: case DatabaseStatus::kFailed:
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR); FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
...@@ -98,12 +100,36 @@ class GetTitleTask : public InitializationSubTask { ...@@ -98,12 +100,36 @@ class GetTitleTask : public InitializationSubTask {
break; break;
} }
if (!data.empty()) if (data.size() != 1u) {
sub_task_init().initialization_data->ui_title = data.front(); FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return;
}
proto::BackgroundFetchUIOptions ui_options;
if (!ui_options.ParseFromString(data[0])) {
FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return;
}
if (!ui_options.title().empty())
sub_task_init().initialization_data->ui_title = ui_options.title();
if (!ui_options.icon().empty()) {
// Start an icon deserialization SubTask on another thread, then finish.
DeserializeIcon(std::unique_ptr<std::string>(ui_options.release_icon()),
base::BindOnce(&GetUIOptionsTask::DidDeserializeIcon,
weak_factory_.GetWeakPtr()));
} else {
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
}
void DidDeserializeIcon(SkBitmap icon) {
sub_task_init().initialization_data->icon = std::move(icon);
FinishWithError(blink::mojom::BackgroundFetchError::NONE); FinishWithError(blink::mojom::BackgroundFetchError::NONE);
} }
base::WeakPtrFactory<GetTitleTask> weak_factory_; // Keep as last. base::WeakPtrFactory<GetUIOptionsTask> weak_factory_; // Keep as last.
}; };
// Gets the number of completed fetches, the number of active fetches, // Gets the number of completed fetches, the number of active fetches,
...@@ -243,48 +269,6 @@ class GetRequestsTask : public InitializationSubTask { ...@@ -243,48 +269,6 @@ class GetRequestsTask : public InitializationSubTask {
DISALLOW_COPY_AND_ASSIGN(GetRequestsTask); DISALLOW_COPY_AND_ASSIGN(GetRequestsTask);
}; };
// Deserializes the icon and creates an SkBitmap from it.
class DeserializeIconTask : public InitializationSubTask {
public:
DeserializeIconTask(DatabaseTaskHost* host,
const SubTaskInit& sub_task_init,
base::OnceClosure done_closure,
std::string* serialized_icon)
: InitializationSubTask(host, sub_task_init, std::move(done_closure)),
serialized_icon_(serialized_icon),
weak_factory_(this) {}
~DeserializeIconTask() override = default;
void Start() override {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::BACKGROUND},
base::BindOnce(&DeserializeIcon, std::move(serialized_icon_)),
base::BindOnce(&DeserializeIconTask::StoreIcon,
weak_factory_.GetWeakPtr()));
}
private:
static SkBitmap DeserializeIcon(
std::unique_ptr<std::string> serialized_icon) {
return gfx::Image::CreateFrom1xPNGBytes(
reinterpret_cast<const unsigned char*>(serialized_icon->c_str()),
serialized_icon->size())
.AsBitmap();
}
void StoreIcon(SkBitmap icon) {
sub_task_init().initialization_data->icon = std::move(icon);
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
std::unique_ptr<std::string> serialized_icon_;
base::WeakPtrFactory<DeserializeIconTask> weak_factory_; // Keep as last.
};
// Fills the BackgroundFetchInitializationData with all the relevant information // Fills the BackgroundFetchInitializationData with all the relevant information
// stored in the BackgroundFetchMetadata proto. // stored in the BackgroundFetchMetadata proto.
class FillFromMetadataTask : public InitializationSubTask { class FillFromMetadataTask : public InitializationSubTask {
...@@ -382,18 +366,7 @@ class FillFromMetadataTask : public InitializationSubTask { ...@@ -382,18 +366,7 @@ class FillFromMetadataTask : public InitializationSubTask {
} }
} }
if (!metadata.icon().empty()) { FinishWithError(blink::mojom::BackgroundFetchError::NONE);
// Start an icon deserialization SubTask on another thread, then finish.
AddSubTask(std::make_unique<DeserializeIconTask>(
this, sub_task_init(),
base::BindOnce(&FillFromMetadataTask::FinishWithError,
weak_factory_.GetWeakPtr(),
blink::mojom::BackgroundFetchError::NONE),
metadata.release_icon()));
} else {
// Immediately finish.
FinishWithError(blink::mojom::BackgroundFetchError::NONE);
}
} }
base::WeakPtrFactory<FillFromMetadataTask> weak_factory_; // Keep as last. base::WeakPtrFactory<FillFromMetadataTask> weak_factory_; // Keep as last.
...@@ -416,9 +389,9 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask { ...@@ -416,9 +389,9 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask {
void Start() override { void Start() override {
// We need 3 queries to get the initialization data. These are wrapped // We need 3 queries to get the initialization data. These are wrapped
// in a BarrierClosure to avoid querying them serially. // in a BarrierClosure to avoid querying them serially.
// 1. Metadata (+ icon deserialization) // 1. Metadata
// 2. Request statuses and state sanitization // 2. Request statuses and state sanitization
// 3. UI Title // 3. UI Options (+ icon deserialization)
base::RepeatingClosure barrier_closure = base::BarrierClosure( base::RepeatingClosure barrier_closure = base::BarrierClosure(
3u, 3u,
base::BindOnce( base::BindOnce(
...@@ -432,8 +405,8 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask { ...@@ -432,8 +405,8 @@ class FillBackgroundFetchInitializationDataTask : public InitializationSubTask {
barrier_closure)); barrier_closure));
AddSubTask(std::make_unique<GetRequestsTask>(this, sub_task_init(), AddSubTask(std::make_unique<GetRequestsTask>(this, sub_task_init(),
barrier_closure)); barrier_closure));
AddSubTask( AddSubTask(std::make_unique<GetUIOptionsTask>(this, sub_task_init(),
std::make_unique<GetTitleTask>(this, sub_task_init(), barrier_closure)); barrier_closure));
} }
private: private:
......
// Copyright 2018 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/background_fetch/storage/image_helpers.h"
#include "base/sequenced_task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "ui/gfx/image/image.h"
namespace content {
namespace background_fetch {
namespace {
// The max icon resolution, this is used as a threshold to decide
// whether the icon should be persisted.
constexpr int kMaxIconResolution = 256 * 256;
std::string ConvertAndSerializeIcon(const SkBitmap& icon) {
std::string serialized_icon;
auto icon_bytes = gfx::Image::CreateFrom1xBitmap(icon).As1xPNGBytes();
serialized_icon.assign(icon_bytes->front_as<char>(),
icon_bytes->front_as<char>() + icon_bytes->size());
return serialized_icon;
}
SkBitmap DeserializeAndConvertIcon(
std::unique_ptr<std::string> serialized_icon) {
return gfx::Image::CreateFrom1xPNGBytes(
reinterpret_cast<const unsigned char*>(serialized_icon->c_str()),
serialized_icon->size())
.AsBitmap();
}
} // namespace
bool ShouldPersistIcon(const SkBitmap& icon) {
return !icon.isNull() && (icon.height() * icon.width() <= kMaxIconResolution);
}
void SerializeIcon(const SkBitmap& icon, SerializeIconCallback callback) {
DCHECK(!icon.isNull());
// Do the serialization on a seperate thread to avoid blocking on
// expensive operations (image conversions), then post back to current
// thread and continue normally.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::BACKGROUND},
base::BindOnce(&ConvertAndSerializeIcon, icon), std::move(callback));
}
void DeserializeIcon(std::unique_ptr<std::string> serialized_icon,
DeserializeIconCallback callback) {
DCHECK(serialized_icon);
// Do the deserialization on a seperate thread to avoid blocking on
// expensive operations (image conversions), then post back to current
// thread and continue normally.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::BACKGROUND},
base::BindOnce(&DeserializeAndConvertIcon, std::move(serialized_icon)),
base::BindOnce(std::move(callback)));
}
} // namespace background_fetch
} // namespace content
// Copyright 2018 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.
#ifndef CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
#include <memory>
#include <string>
#include "base/callback_forward.h"
#include "content/common/content_export.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace content {
namespace background_fetch {
using SerializeIconCallback = base::OnceCallback<void(std::string)>;
using DeserializeIconCallback = base::OnceCallback<void(SkBitmap)>;
// Checks whether the icon should be stored on disk. This is only the case for
// non-null |icon|s with a resolution of at most 256x256 pixels.
CONTENT_EXPORT bool ShouldPersistIcon(const SkBitmap& icon);
// Serializes the icon on a separate Task Runner. The |icon| will be serialized
// as a 1x bitmap to raw PNG-encoded data
CONTENT_EXPORT void SerializeIcon(const SkBitmap& icon,
SerializeIconCallback callback);
// Deserializes the icon on a separate Task Runner. he |serialized_icon| must
// contain raw PNG-encoded data, which will be decoded to a 1x bitmap.
CONTENT_EXPORT void DeserializeIcon(
std::unique_ptr<std::string> serialized_icon,
DeserializeIconCallback callback);
} // namespace background_fetch
} // namespace content
#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_IMAGE_HELPERS_H_
// Copyright 2018 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/background_fetch/storage/image_helpers.h"
#include <memory>
#include <string>
#include "base/bind.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace content {
namespace background_fetch {
namespace {
void DidSerializeIcon(base::OnceClosure quit_closure,
std::string* out_icon,
std::string icon) {
DCHECK(out_icon);
*out_icon = std::move(icon);
std::move(quit_closure).Run();
}
void DidDeserializeIcon(base::OnceClosure quit_closure,
SkBitmap* out_icon,
SkBitmap icon) {
DCHECK(out_icon);
*out_icon = std::move(icon);
std::move(quit_closure).Run();
}
TEST(BackgroundFetchImageHelpers, ShouldPersistIcon) {
SkBitmap null_icon;
EXPECT_FALSE(ShouldPersistIcon(null_icon));
SkBitmap large_icon;
large_icon.allocN32Pixels(512, 512);
EXPECT_FALSE(ShouldPersistIcon(large_icon));
SkBitmap valid_icon;
valid_icon.allocN32Pixels(42, 42);
EXPECT_TRUE(ShouldPersistIcon(valid_icon));
}
TEST(BackgroundFetchImageHelpers, SerializeRoundTrip) {
base::test::ScopedTaskEnvironment scoped_task_environment;
SkBitmap icon;
icon.allocN32Pixels(42, 42);
icon.eraseColor(SK_ColorGREEN);
// Serialize.
std::string serialized_icon;
{
base::RunLoop run_loop;
SerializeIcon(icon,
base::BindOnce(&DidSerializeIcon, run_loop.QuitClosure(),
&serialized_icon));
run_loop.Run();
}
// Deserialize.
SkBitmap result_icon;
{
base::RunLoop run_loop;
DeserializeIcon(std::make_unique<std::string>(serialized_icon),
base::BindOnce(&DidDeserializeIcon, run_loop.QuitClosure(),
&result_icon));
run_loop.Run();
}
ASSERT_FALSE(result_icon.isNull());
EXPECT_EQ(icon.height(), result_icon.height());
EXPECT_EQ(icon.width(), result_icon.width());
for (int i = 0; i < result_icon.width(); i++) {
for (int j = 0; j < result_icon.height(); j++)
EXPECT_EQ(result_icon.getColor(i, j), SK_ColorGREEN);
}
}
} // namespace
} // namespace background_fetch
} // namespace content
...@@ -28,15 +28,21 @@ UpdateRegistrationUITask::UpdateRegistrationUITask( ...@@ -28,15 +28,21 @@ UpdateRegistrationUITask::UpdateRegistrationUITask(
UpdateRegistrationUITask::~UpdateRegistrationUITask() = default; UpdateRegistrationUITask::~UpdateRegistrationUITask() = default;
void UpdateRegistrationUITask::Start() { void UpdateRegistrationUITask::Start() {
// TODO(crbug.com/865063): Persist new icon if applicable and don't
// overwrite unupdated values.
proto::BackgroundFetchUIOptions ui_options;
ui_options.set_title(updated_title_);
service_worker_context()->StoreRegistrationUserData( service_worker_context()->StoreRegistrationUserData(
registration_id_.service_worker_registration_id(), registration_id_.service_worker_registration_id(),
registration_id_.origin().GetURL(), registration_id_.origin().GetURL(),
{{TitleKey(registration_id_.unique_id()), updated_title_}}, {{UIOptionsKey(registration_id_.unique_id()),
base::BindOnce(&UpdateRegistrationUITask::DidUpdateTitle, ui_options.SerializeAsString()}},
base::BindOnce(&UpdateRegistrationUITask::DidUpdateUIOptions,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
void UpdateRegistrationUITask::DidUpdateTitle( void UpdateRegistrationUITask::DidUpdateUIOptions(
blink::ServiceWorkerStatusCode status) { blink::ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) { switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk: case DatabaseStatus::kOk:
......
...@@ -33,7 +33,7 @@ class UpdateRegistrationUITask : public DatabaseTask { ...@@ -33,7 +33,7 @@ class UpdateRegistrationUITask : public DatabaseTask {
void Start() override; void Start() override;
private: private:
void DidUpdateTitle(blink::ServiceWorkerStatusCode status); void DidUpdateUIOptions(blink::ServiceWorkerStatusCode status);
void FinishWithError(blink::mojom::BackgroundFetchError error) override; void FinishWithError(blink::mojom::BackgroundFetchError error) override;
......
...@@ -1266,6 +1266,7 @@ test("content_unittests") { ...@@ -1266,6 +1266,7 @@ test("content_unittests") {
"../browser/background_fetch/background_fetch_registration_notifier_unittest.cc", "../browser/background_fetch/background_fetch_registration_notifier_unittest.cc",
"../browser/background_fetch/background_fetch_scheduler_unittest.cc", "../browser/background_fetch/background_fetch_scheduler_unittest.cc",
"../browser/background_fetch/background_fetch_service_unittest.cc", "../browser/background_fetch/background_fetch_service_unittest.cc",
"../browser/background_fetch/storage/image_helpers_unittest.cc",
"../browser/background_sync/background_sync_manager_unittest.cc", "../browser/background_sync/background_sync_manager_unittest.cc",
"../browser/background_sync/background_sync_network_observer_unittest.cc", "../browser/background_sync/background_sync_network_observer_unittest.cc",
"../browser/background_sync/background_sync_service_impl_unittest.cc", "../browser/background_sync/background_sync_service_impl_unittest.cc",
...@@ -1792,6 +1793,7 @@ test("content_unittests") { ...@@ -1792,6 +1793,7 @@ test("content_unittests") {
"//content:resources", "//content:resources",
"//content/app:both_for_content_tests", "//content/app:both_for_content_tests",
"//content/browser:for_content_tests", "//content/browser:for_content_tests",
"//content/browser/background_fetch:background_fetch_proto",
"//content/browser/cache_storage:cache_storage_proto", "//content/browser/cache_storage:cache_storage_proto",
"//content/browser/dom_storage:local_storage_proto", "//content/browser/dom_storage:local_storage_proto",
"//content/browser/notifications:notification_proto", "//content/browser/notifications:notification_proto",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment