Commit a8583d14 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Background Fetch] Update download total after fetch is complete.

After a fetch is complete, the metadata in the ServiceWorker database
is updated with the new total_downloaded value.

Bug: 826257
Change-Id: I8167683cc89f0d8567ddc861e934b3a4f4a20bd7
Reviewed-on: https://chromium-review.googlesource.com/1080816Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569352}
parent 073af19d
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#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 "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_test_base.h" #include "content/browser/background_fetch/background_fetch_test_base.h"
#include "content/browser/background_fetch/background_fetch_test_data_manager.h" #include "content/browser/background_fetch/background_fetch_test_data_manager.h"
...@@ -44,6 +45,8 @@ const char kAlternativeUniqueId[] = "bb48a9fb-c21f-4c2d-a9ae-58bd48a9fb53"; ...@@ -44,6 +45,8 @@ const char kAlternativeUniqueId[] = "bb48a9fb-c21f-4c2d-a9ae-58bd48a9fb53";
const char kInitialTitle[] = "Initial Title"; const char kInitialTitle[] = "Initial Title";
const char kUpdatedTitle[] = "Updated Title"; const char kUpdatedTitle[] = "Updated Title";
constexpr size_t kResponseFileSize = 42u;
void DidCreateRegistration( void DidCreateRegistration(
base::Closure quit_closure, base::Closure quit_closure,
blink::mojom::BackgroundFetchError* out_error, blink::mojom::BackgroundFetchError* out_error,
...@@ -84,7 +87,7 @@ void AnnotateRequestInfoWithFakeDownloadManagerData( ...@@ -84,7 +87,7 @@ void AnnotateRequestInfoWithFakeDownloadManagerData(
base::Time::Now(), BackgroundFetchResult::FailureReason::UNKNOWN)); base::Time::Now(), BackgroundFetchResult::FailureReason::UNKNOWN));
} else { } else {
request_info->SetResult(std::make_unique<BackgroundFetchResult>( request_info->SetResult(std::make_unique<BackgroundFetchResult>(
base::Time::Now(), base::FilePath(), 42u /* file_size */)); base::Time::Now(), base::FilePath(), kResponseFileSize));
} }
} }
...@@ -110,6 +113,17 @@ bool operator==(const ResponseStateStats& s1, const ResponseStateStats& s2) { ...@@ -110,6 +113,17 @@ bool operator==(const ResponseStateStats& s1, const ResponseStateStats& s2) {
s1.completed_requests == s2.completed_requests; s1.completed_requests == s2.completed_requests;
} }
std::vector<ServiceWorkerFetchRequest> CreateValidRequests(
const url::Origin& origin,
size_t num_requests = 1u) {
std::vector<ServiceWorkerFetchRequest> requests(num_requests);
for (size_t i = 0; i < requests.size(); i++) {
// Creates a URL of the form: `http://example.com/x`
requests[i].url = GURL(origin.GetURL().spec() + base::NumberToString(i));
}
return requests;
}
} // namespace } // namespace
class BackgroundFetchDataManagerTest : public BackgroundFetchTestBase { class BackgroundFetchDataManagerTest : public BackgroundFetchTestBase {
...@@ -885,21 +899,66 @@ TEST_F(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) { ...@@ -885,21 +899,66 @@ TEST_F(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) {
2 /* completed_requests */})); 2 /* completed_requests */}));
} }
TEST_F(BackgroundFetchDataManagerTest, DownloadTotalUpdated) {
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
auto requests = CreateValidRequests(origin(), 3u /* num_requests */);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
CreateRegistration(registration_id, requests, options, &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
auto registration =
GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(registration->download_total, 0u);
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
true /* succeeded */);
MarkRequestAsComplete(registration_id, request_info.get());
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(registration->download_total, kResponseFileSize);
PopNextRequest(registration_id, &request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
true /* succeeded */);
MarkRequestAsComplete(registration_id, request_info.get());
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
PopNextRequest(registration_id, &request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
false /* succeeded */);
MarkRequestAsComplete(registration_id, request_info.get());
registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// |download_total| is unchanged.
EXPECT_EQ(registration->download_total, 2 * kResponseFileSize);
}
TEST_F(BackgroundFetchDataManagerTest, WriteToCache) { TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
int64_t sw_id = RegisterServiceWorker(); int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id); ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
BackgroundFetchRegistrationId registration_id( BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
ServiceWorkerFetchRequest request1; auto requests = CreateValidRequests(origin(), 2u /* num_requests */);
request1.url = GURL(origin().GetURL().spec() + "1");
ServiceWorkerFetchRequest request2;
request2.url = GURL(origin().GetURL().spec() + "2");
BackgroundFetchOptions options; BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error; blink::mojom::BackgroundFetchError error;
CreateRegistration(registration_id, {request1, request2}, options, &error); CreateRegistration(registration_id, requests, options, &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
scoped_refptr<BackgroundFetchRequestInfo> request_info; scoped_refptr<BackgroundFetchRequestInfo> request_info;
...@@ -913,8 +972,8 @@ TEST_F(BackgroundFetchDataManagerTest, WriteToCache) { ...@@ -913,8 +972,8 @@ TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
EXPECT_TRUE(HasCache(kExampleUniqueId)); EXPECT_TRUE(HasCache(kExampleUniqueId));
EXPECT_FALSE(HasCache("foo")); EXPECT_FALSE(HasCache("foo"));
EXPECT_TRUE(MatchCache(request1)); EXPECT_TRUE(MatchCache(requests[0]));
EXPECT_FALSE(MatchCache(request2)); EXPECT_FALSE(MatchCache(requests[1]));
PopNextRequest(registration_id, &request_info); PopNextRequest(registration_id, &request_info);
ASSERT_TRUE(request_info); ASSERT_TRUE(request_info);
...@@ -922,12 +981,12 @@ TEST_F(BackgroundFetchDataManagerTest, WriteToCache) { ...@@ -922,12 +981,12 @@ TEST_F(BackgroundFetchDataManagerTest, WriteToCache) {
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(), AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(),
true /* success */); true /* success */);
MarkRequestAsComplete(registration_id, request_info.get()); MarkRequestAsComplete(registration_id, request_info.get());
EXPECT_TRUE(MatchCache(request1)); EXPECT_TRUE(MatchCache(requests[0]));
EXPECT_TRUE(MatchCache(request2)); EXPECT_TRUE(MatchCache(requests[1]));
RestartDataManagerFromPersistentStorage(); RestartDataManagerFromPersistentStorage();
EXPECT_TRUE(MatchCache(request1)); EXPECT_TRUE(MatchCache(requests[0]));
EXPECT_TRUE(MatchCache(request2)); EXPECT_TRUE(MatchCache(requests[1]));
} }
TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) { TEST_F(BackgroundFetchDataManagerTest, CacheDeleted) {
...@@ -1021,14 +1080,11 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) { ...@@ -1021,14 +1080,11 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
BackgroundFetchRegistrationId registration_id( BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
ServiceWorkerFetchRequest request1; auto requests = CreateValidRequests(origin(), 2u /* num_requests */);
request1.url = GURL(origin().GetURL().spec() + "1");
ServiceWorkerFetchRequest request2;
request2.url = GURL(origin().GetURL().spec() + "2");
BackgroundFetchOptions options; BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error; blink::mojom::BackgroundFetchError error;
CreateRegistration(registration_id, {request1, request2}, options, &error); CreateRegistration(registration_id, requests, options, &error);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
bool succeeded = false; bool succeeded = false;
...@@ -1066,8 +1122,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) { ...@@ -1066,8 +1122,8 @@ TEST_F(BackgroundFetchDataManagerTest, GetSettledFetchesFromCache) {
ASSERT_EQ(settled_fetches.size(), 2u); ASSERT_EQ(settled_fetches.size(), 2u);
// Sanity check that the responses are written to / read from the cache. // Sanity check that the responses are written to / read from the cache.
EXPECT_TRUE(MatchCache(request1)); EXPECT_TRUE(MatchCache(requests[0]));
EXPECT_TRUE(MatchCache(request2)); EXPECT_TRUE(MatchCache(requests[1]));
EXPECT_EQ(settled_fetches[0].response.cache_storage_cache_name, EXPECT_EQ(settled_fetches[0].response.cache_storage_cache_name,
kExampleUniqueId); kExampleUniqueId);
EXPECT_EQ(settled_fetches[1].response.cache_storage_cache_name, EXPECT_EQ(settled_fetches[1].response.cache_storage_cache_name,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "content/browser/background_fetch/storage/mark_request_complete_task.h" #include "content/browser/background_fetch/storage/mark_request_complete_task.h"
#include "base/barrier_closure.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/cache_storage/cache_storage_manager.h" #include "content/browser/cache_storage/cache_storage_manager.h"
...@@ -32,10 +33,15 @@ MarkRequestCompleteTask::MarkRequestCompleteTask( ...@@ -32,10 +33,15 @@ MarkRequestCompleteTask::MarkRequestCompleteTask(
MarkRequestCompleteTask::~MarkRequestCompleteTask() = default; MarkRequestCompleteTask::~MarkRequestCompleteTask() = default;
void MarkRequestCompleteTask::Start() { void MarkRequestCompleteTask::Start() {
StoreResponse(); base::RepeatingClosure barrier_closure = base::BarrierClosure(
2u, base::BindOnce(&MarkRequestCompleteTask::CheckAndCallFinished,
weak_factory_.GetWeakPtr()));
StoreResponse(barrier_closure);
UpdateMetadata(barrier_closure);
} }
void MarkRequestCompleteTask::StoreResponse() { void MarkRequestCompleteTask::StoreResponse(base::OnceClosure done_closure) {
auto response = std::make_unique<ServiceWorkerResponse>(); auto response = std::make_unique<ServiceWorkerResponse>();
is_response_successful_ = data_manager()->FillServiceWorkerResponse( is_response_successful_ = data_manager()->FillServiceWorkerResponse(
...@@ -43,7 +49,7 @@ void MarkRequestCompleteTask::StoreResponse() { ...@@ -43,7 +49,7 @@ void MarkRequestCompleteTask::StoreResponse() {
// A valid non-empty url is needed if we want to write to the cache. // A valid non-empty url is needed if we want to write to the cache.
if (!request_info_->fetch_request().url.is_valid()) { if (!request_info_->fetch_request().url.is_valid()) {
CreateAndStoreCompletedRequest(); CreateAndStoreCompletedRequest(std::move(done_closure));
return; return;
} }
...@@ -51,16 +57,18 @@ void MarkRequestCompleteTask::StoreResponse() { ...@@ -51,16 +57,18 @@ void MarkRequestCompleteTask::StoreResponse() {
registration_id_.origin(), CacheStorageOwner::kBackgroundFetch, registration_id_.origin(), CacheStorageOwner::kBackgroundFetch,
registration_id_.unique_id() /* cache_name */, registration_id_.unique_id() /* cache_name */,
base::BindOnce(&MarkRequestCompleteTask::DidOpenCache, base::BindOnce(&MarkRequestCompleteTask::DidOpenCache,
weak_factory_.GetWeakPtr(), std::move(response))); weak_factory_.GetWeakPtr(), std::move(response),
std::move(done_closure)));
} }
void MarkRequestCompleteTask::DidOpenCache( void MarkRequestCompleteTask::DidOpenCache(
std::unique_ptr<ServiceWorkerResponse> response, std::unique_ptr<ServiceWorkerResponse> response,
base::OnceClosure done_closure,
CacheStorageCacheHandle handle, CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error) { blink::mojom::CacheStorageError error) {
if (error != blink::mojom::CacheStorageError::kSuccess) { if (error != blink::mojom::CacheStorageError::kSuccess) {
// TODO(crbug.com/780025): Log failures to UMA. // TODO(crbug.com/780025): Log failures to UMA.
CreateAndStoreCompletedRequest(); CreateAndStoreCompletedRequest(std::move(done_closure));
return; return;
} }
DCHECK(handle.value()); DCHECK(handle.value());
...@@ -73,17 +81,20 @@ void MarkRequestCompleteTask::DidOpenCache( ...@@ -73,17 +81,20 @@ void MarkRequestCompleteTask::DidOpenCache(
handle.value()->Put( handle.value()->Put(
std::move(request), std::move(response), std::move(request), std::move(response),
base::BindOnce(&MarkRequestCompleteTask::DidWriteToCache, base::BindOnce(&MarkRequestCompleteTask::DidWriteToCache,
weak_factory_.GetWeakPtr(), std::move(handle))); weak_factory_.GetWeakPtr(), std::move(handle),
std::move(done_closure)));
} }
void MarkRequestCompleteTask::DidWriteToCache( void MarkRequestCompleteTask::DidWriteToCache(
CacheStorageCacheHandle handle, CacheStorageCacheHandle handle,
base::OnceClosure done_closure,
blink::mojom::CacheStorageError error) { blink::mojom::CacheStorageError error) {
// TODO(crbug.com/780025): Log failures to UMA. // TODO(crbug.com/780025): Log failures to UMA.
CreateAndStoreCompletedRequest(); CreateAndStoreCompletedRequest(std::move(done_closure));
} }
void MarkRequestCompleteTask::CreateAndStoreCompletedRequest() { void MarkRequestCompleteTask::CreateAndStoreCompletedRequest(
base::OnceClosure done_closure) {
completed_request_.set_unique_id(registration_id_.unique_id()); completed_request_.set_unique_id(registration_id_.unique_id());
completed_request_.set_request_index(request_info_->request_index()); completed_request_.set_request_index(request_info_->request_index());
completed_request_.set_serialized_request( completed_request_.set_serialized_request(
...@@ -97,11 +108,12 @@ void MarkRequestCompleteTask::CreateAndStoreCompletedRequest() { ...@@ -97,11 +108,12 @@ void MarkRequestCompleteTask::CreateAndStoreCompletedRequest() {
{{CompletedRequestKey(completed_request_.unique_id(), {{CompletedRequestKey(completed_request_.unique_id(),
completed_request_.request_index()), completed_request_.request_index()),
completed_request_.SerializeAsString()}}, completed_request_.SerializeAsString()}},
base::BindRepeating(&MarkRequestCompleteTask::DidStoreCompletedRequest, base::BindOnce(&MarkRequestCompleteTask::DidStoreCompletedRequest,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr(), std::move(done_closure)));
} }
void MarkRequestCompleteTask::DidStoreCompletedRequest( void MarkRequestCompleteTask::DidStoreCompletedRequest(
base::OnceClosure done_closure,
ServiceWorkerStatusCode status) { ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) { switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk: case DatabaseStatus::kOk:
...@@ -109,7 +121,7 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest( ...@@ -109,7 +121,7 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest(
case DatabaseStatus::kFailed: case DatabaseStatus::kFailed:
case DatabaseStatus::kNotFound: case DatabaseStatus::kNotFound:
// TODO(crbug.com/780025): Log failures to UMA. // TODO(crbug.com/780025): Log failures to UMA.
Finished(); // Destroys |this|. std::move(done_closure).Run();
return; return;
} }
...@@ -119,24 +131,70 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest( ...@@ -119,24 +131,70 @@ void MarkRequestCompleteTask::DidStoreCompletedRequest(
{ActiveRequestKey(completed_request_.unique_id(), {ActiveRequestKey(completed_request_.unique_id(),
completed_request_.request_index())}, completed_request_.request_index())},
base::BindOnce(&MarkRequestCompleteTask::DidDeleteActiveRequest, base::BindOnce(&MarkRequestCompleteTask::DidDeleteActiveRequest,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr(), std::move(done_closure)));
} }
void MarkRequestCompleteTask::DidDeleteActiveRequest( void MarkRequestCompleteTask::DidDeleteActiveRequest(
base::OnceClosure done_closure,
ServiceWorkerStatusCode status) {
// TODO(crbug.com/780025): Log failures to UMA.
std::move(done_closure).Run();
}
void MarkRequestCompleteTask::UpdateMetadata(base::OnceClosure done_closure) {
if (!request_info_->IsResultSuccess() || request_info_->GetFileSize() == 0u) {
std::move(done_closure).Run();
return;
}
service_worker_context()->GetRegistrationUserData(
registration_id_.service_worker_registration_id(),
{RegistrationKey(registration_id_.unique_id())},
base::BindOnce(&MarkRequestCompleteTask::DidGetMetadata,
weak_factory_.GetWeakPtr(), std::move(done_closure)));
}
void MarkRequestCompleteTask::DidGetMetadata(
base::OnceClosure done_closure,
const std::vector<std::string>& data,
ServiceWorkerStatusCode status) { ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) { switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kNotFound: case DatabaseStatus::kNotFound:
case DatabaseStatus::kFailed: case DatabaseStatus::kFailed:
// TODO(crbug.com/780025): Log failures to UMA. // TODO(crbug.com/780025): Log failures to UMA.
break; std::move(done_closure).Run();
return;
case DatabaseStatus::kOk: case DatabaseStatus::kOk:
std::move(callback_).Run(); DCHECK_EQ(1u, data.size());
break; break;
} }
Finished(); // Destroys |this|. proto::BackgroundFetchMetadata metadata;
if (!metadata.ParseFromString(data.front())) {
NOTREACHED() << "Database is corrupt"; // TODO(crbug.com/780027): Nuke it.
}
metadata.mutable_registration()->set_download_total(
metadata.registration().download_total() + request_info_->GetFileSize());
service_worker_context()->StoreRegistrationUserData(
registration_id_.service_worker_registration_id(),
registration_id_.origin().GetURL(),
{{RegistrationKey(registration_id_.unique_id()),
metadata.SerializeAsString()}},
base::BindOnce(&MarkRequestCompleteTask::DidStoreMetadata,
weak_factory_.GetWeakPtr(), std::move(done_closure)));
}
void MarkRequestCompleteTask::DidStoreMetadata(base::OnceClosure done_closure,
ServiceWorkerStatusCode status) {
// TODO(crbug.com/780025): Log failures to UMA.
std::move(done_closure).Run();
}
// TODO(rayankans): Update download stats. void MarkRequestCompleteTask::CheckAndCallFinished() {
std::move(callback_).Run();
Finished();
} }
} // namespace background_fetch } // namespace background_fetch
......
...@@ -38,20 +38,35 @@ class MarkRequestCompleteTask : public DatabaseTask { ...@@ -38,20 +38,35 @@ class MarkRequestCompleteTask : public DatabaseTask {
void Start() override; void Start() override;
private: private:
void StoreResponse(); void StoreResponse(base::OnceClosure done_closure);
void DidOpenCache(std::unique_ptr<ServiceWorkerResponse> response, void DidOpenCache(std::unique_ptr<ServiceWorkerResponse> response,
base::OnceClosure done_closure,
CacheStorageCacheHandle handle, CacheStorageCacheHandle handle,
blink::mojom::CacheStorageError error); blink::mojom::CacheStorageError error);
void DidWriteToCache(CacheStorageCacheHandle handle, void DidWriteToCache(CacheStorageCacheHandle handle,
base::OnceClosure done_closure,
blink::mojom::CacheStorageError error); blink::mojom::CacheStorageError error);
void CreateAndStoreCompletedRequest(); void CreateAndStoreCompletedRequest(base::OnceClosure done_closure);
void DidStoreCompletedRequest(ServiceWorkerStatusCode status); void DidStoreCompletedRequest(base::OnceClosure done_closure,
ServiceWorkerStatusCode status);
void DidDeleteActiveRequest(ServiceWorkerStatusCode status); void DidDeleteActiveRequest(base::OnceClosure done_closure,
ServiceWorkerStatusCode status);
void UpdateMetadata(base::OnceClosure done_closure);
void DidGetMetadata(base::OnceClosure done_closure,
const std::vector<std::string>& data,
ServiceWorkerStatusCode status);
void DidStoreMetadata(base::OnceClosure done_closure,
ServiceWorkerStatusCode status);
void CheckAndCallFinished();
BackgroundFetchRegistrationId registration_id_; BackgroundFetchRegistrationId registration_id_;
scoped_refptr<BackgroundFetchRequestInfo> request_info_; scoped_refptr<BackgroundFetchRequestInfo> request_info_;
......
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