Commit 271c1807 authored by Josh Nohle's avatar Josh Nohle Committed by Commit Bot

[Nearby] Remove public certificates when they expire

Use an expiration scheduler to notify the certificate manager when a
public certificate has expired. Then, remove all expired public
certificates from storage.

Fixed: b/166117022
Change-Id: I28b019d805518e9f9520ccd427840f75bd5bee1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2377070
Commit-Queue: Josh Nohle <nohle@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805294}
parent 01e90fd6
...@@ -49,6 +49,10 @@ enum GetDecryptedPublicCertificateResult { ...@@ -49,6 +49,10 @@ enum GetDecryptedPublicCertificateResult {
kMaxValue = kStorageFailure kMaxValue = kStorageFailure
}; };
size_t NumExpectedPrivateCertificates() {
return kVisibilities.size() * kNearbyShareNumPrivateCertificates;
}
void RecordGetDecryptedPublicCertificateResultMetric( void RecordGetDecryptedPublicCertificateResultMetric(
GetDecryptedPublicCertificateResult result) { GetDecryptedPublicCertificateResult result) {
base::UmaHistogramEnumeration( base::UmaHistogramEnumeration(
...@@ -167,6 +171,10 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl( ...@@ -167,6 +171,10 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl(
pref_service_(pref_service), pref_service_(pref_service),
client_factory_(client_factory), client_factory_(client_factory),
clock_(clock), clock_(clock),
certificate_storage_(NearbyShareCertificateStorageImpl::Factory::Create(
pref_service_,
proto_database_provider,
profile_path)),
private_certificate_expiration_scheduler_( private_certificate_expiration_scheduler_(
NearbyShareSchedulerFactory::CreateExpirationScheduler( NearbyShareSchedulerFactory::CreateExpirationScheduler(
base::BindRepeating(&NearbyShareCertificateManagerImpl:: base::BindRepeating(&NearbyShareCertificateManagerImpl::
...@@ -181,6 +189,19 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl( ...@@ -181,6 +189,19 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl(
OnPrivateCertificateExpiration, OnPrivateCertificateExpiration,
base::Unretained(this)), base::Unretained(this)),
clock_)), clock_)),
public_certificate_expiration_scheduler_(
NearbyShareSchedulerFactory::CreateExpirationScheduler(
base::BindRepeating(&NearbyShareCertificateManagerImpl::
NextPublicCertificateExpirationTime,
base::Unretained(this)),
/*retry_failures=*/true,
/*require_connectivity=*/false,
prefs::kNearbySharingSchedulerPublicCertificateExpirationPrefName,
pref_service_,
base::BindRepeating(&NearbyShareCertificateManagerImpl::
OnPublicCertificateExpiration,
base::Unretained(this)),
clock_)),
upload_local_device_certificates_scheduler_( upload_local_device_certificates_scheduler_(
NearbyShareSchedulerFactory::CreateOnDemandScheduler( NearbyShareSchedulerFactory::CreateOnDemandScheduler(
/*retry_failures=*/true, /*retry_failures=*/true,
...@@ -205,11 +226,7 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl( ...@@ -205,11 +226,7 @@ NearbyShareCertificateManagerImpl::NearbyShareCertificateManagerImpl(
/*page_token=*/base::nullopt, /*page_token=*/base::nullopt,
/*page_number=*/1, /*page_number=*/1,
/*certificate_count=*/0), /*certificate_count=*/0),
clock_)), clock_)) {}
cert_store_(NearbyShareCertificateStorageImpl::Factory::Create(
pref_service_,
proto_database_provider,
profile_path)) {}
NearbyShareCertificateManagerImpl::~NearbyShareCertificateManagerImpl() = NearbyShareCertificateManagerImpl::~NearbyShareCertificateManagerImpl() =
default; default;
...@@ -218,7 +235,7 @@ NearbySharePrivateCertificate ...@@ -218,7 +235,7 @@ NearbySharePrivateCertificate
NearbyShareCertificateManagerImpl::GetValidPrivateCertificate( NearbyShareCertificateManagerImpl::GetValidPrivateCertificate(
NearbyShareVisibility visibility) { NearbyShareVisibility visibility) {
std::vector<NearbySharePrivateCertificate> certs = std::vector<NearbySharePrivateCertificate> certs =
*cert_store_->GetPrivateCertificates(); *certificate_storage_->GetPrivateCertificates();
for (auto& cert : certs) { for (auto& cert : certs) {
if (IsNearbyShareCertificateWithinValidityPeriod( if (IsNearbyShareCertificateWithinValidityPeriod(
clock_->Now(), cert.not_before(), cert.not_after(), clock_->Now(), cert.not_before(), cert.not_after(),
...@@ -246,7 +263,7 @@ NearbyShareCertificateManagerImpl::GetPrivateCertificatesAsPublicCertificates( ...@@ -246,7 +263,7 @@ NearbyShareCertificateManagerImpl::GetPrivateCertificatesAsPublicCertificates(
void NearbyShareCertificateManagerImpl::GetDecryptedPublicCertificate( void NearbyShareCertificateManagerImpl::GetDecryptedPublicCertificate(
NearbyShareEncryptedMetadataKey encrypted_metadata_key, NearbyShareEncryptedMetadataKey encrypted_metadata_key,
CertDecryptedCallback callback) { CertDecryptedCallback callback) {
cert_store_->GetPublicCertificates( certificate_storage_->GetPublicCertificates(
base::BindOnce(&TryDecryptPublicCertificates, base::BindOnce(&TryDecryptPublicCertificates,
std::move(encrypted_metadata_key), std::move(callback))); std::move(encrypted_metadata_key), std::move(callback)));
} }
...@@ -257,22 +274,36 @@ void NearbyShareCertificateManagerImpl::DownloadPublicCertificates() { ...@@ -257,22 +274,36 @@ void NearbyShareCertificateManagerImpl::DownloadPublicCertificates() {
void NearbyShareCertificateManagerImpl::OnStart() { void NearbyShareCertificateManagerImpl::OnStart() {
private_certificate_expiration_scheduler_->Start(); private_certificate_expiration_scheduler_->Start();
public_certificate_expiration_scheduler_->Start();
upload_local_device_certificates_scheduler_->Start(); upload_local_device_certificates_scheduler_->Start();
download_public_certificates_scheduler_->Start(); download_public_certificates_scheduler_->Start();
} }
void NearbyShareCertificateManagerImpl::OnStop() { void NearbyShareCertificateManagerImpl::OnStop() {
private_certificate_expiration_scheduler_->Stop(); private_certificate_expiration_scheduler_->Stop();
public_certificate_expiration_scheduler_->Stop();
upload_local_device_certificates_scheduler_->Stop(); upload_local_device_certificates_scheduler_->Stop();
download_public_certificates_scheduler_->Stop(); download_public_certificates_scheduler_->Stop();
} }
base::Time base::Optional<base::Time>
NearbyShareCertificateManagerImpl::NextPrivateCertificateExpirationTime() { NearbyShareCertificateManagerImpl::NextPrivateCertificateExpirationTime() {
// If no private certificates are present, return the minimum time to trigger // We enforce that a fixed number--kNearbyShareNumPrivateCertificates for each
// an immediate refresh. // visibility--of private certificates be present at all times. This might not
return cert_store_->NextPrivateCertificateExpirationTime().value_or( // be true the first time the user enables Nearby Share or after certificates
base::Time::Min()); // are revoked. For simplicity, consider the case of missing certificates an
// "expired" state. Return the minimum time to immediately trigger the private
// certificate creation flow.
if (certificate_storage_->GetPrivateCertificates()->size() <
NumExpectedPrivateCertificates()) {
return base::Time::Min();
}
base::Optional<base::Time> expiration_time =
certificate_storage_->NextPrivateCertificateExpirationTime();
DCHECK(expiration_time);
return *expiration_time;
} }
void NearbyShareCertificateManagerImpl::OnPrivateCertificateExpiration() { void NearbyShareCertificateManagerImpl::OnPrivateCertificateExpiration() {
...@@ -289,7 +320,7 @@ void NearbyShareCertificateManagerImpl::OnPrivateCertificateExpiration() { ...@@ -289,7 +320,7 @@ void NearbyShareCertificateManagerImpl::OnPrivateCertificateExpiration() {
// Remove all expired certificates. // Remove all expired certificates.
std::vector<NearbySharePrivateCertificate> old_certs = std::vector<NearbySharePrivateCertificate> old_certs =
*cert_store_->GetPrivateCertificates(); *certificate_storage_->GetPrivateCertificates();
std::vector<NearbySharePrivateCertificate> new_certs; std::vector<NearbySharePrivateCertificate> new_certs;
for (const NearbySharePrivateCertificate& cert : old_certs) { for (const NearbySharePrivateCertificate& cert : old_certs) {
if (IsNearbyShareCertificateExpired( if (IsNearbyShareCertificateExpired(
...@@ -377,7 +408,7 @@ void NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh( ...@@ -377,7 +408,7 @@ void NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh(
} }
} }
cert_store_->ReplacePrivateCertificates(new_certs); certificate_storage_->ReplacePrivateCertificates(new_certs);
NotifyPrivateCertificatesChanged(); NotifyPrivateCertificatesChanged();
private_certificate_expiration_scheduler_->HandleResult(/*success=*/true); private_certificate_expiration_scheduler_->HandleResult(/*success=*/true);
...@@ -388,7 +419,7 @@ void NearbyShareCertificateManagerImpl:: ...@@ -388,7 +419,7 @@ void NearbyShareCertificateManagerImpl::
OnLocalDeviceCertificateUploadRequest() { OnLocalDeviceCertificateUploadRequest() {
std::vector<nearbyshare::proto::PublicCertificate> public_certs; std::vector<nearbyshare::proto::PublicCertificate> public_certs;
std::vector<NearbySharePrivateCertificate> private_certs = std::vector<NearbySharePrivateCertificate> private_certs =
*cert_store_->GetPrivateCertificates(); *certificate_storage_->GetPrivateCertificates();
for (const NearbySharePrivateCertificate& private_cert : private_certs) { for (const NearbySharePrivateCertificate& private_cert : private_certs) {
public_certs.push_back(*private_cert.ToPublicCertificate()); public_certs.push_back(*private_cert.ToPublicCertificate());
} }
...@@ -408,6 +439,33 @@ void NearbyShareCertificateManagerImpl::OnLocalDeviceCertificateUploadFinished( ...@@ -408,6 +439,33 @@ void NearbyShareCertificateManagerImpl::OnLocalDeviceCertificateUploadFinished(
upload_local_device_certificates_scheduler_->HandleResult(success); upload_local_device_certificates_scheduler_->HandleResult(success);
} }
base::Optional<base::Time>
NearbyShareCertificateManagerImpl::NextPublicCertificateExpirationTime() {
base::Optional<base::Time> next_expiration_time =
certificate_storage_->NextPublicCertificateExpirationTime();
// Supposedly there are no store public certificates.
if (!next_expiration_time)
return base::nullopt;
// To account for clock skew between devices, we accept public certificates
// that are slightly past their validity period. This conforms with the
// GmsCore implementation.
return *next_expiration_time +
kNearbySharePublicCertificateValidityBoundOffsetTolerance;
}
void NearbyShareCertificateManagerImpl::OnPublicCertificateExpiration() {
certificate_storage_->RemoveExpiredPublicCertificates(
clock_->Now(), base::BindOnce(&NearbyShareCertificateManagerImpl::
OnExpiredPublicCertificatesRemoved,
base::Unretained(this)));
}
void NearbyShareCertificateManagerImpl::OnExpiredPublicCertificatesRemoved(
bool success) {
public_certificate_expiration_scheduler_->HandleResult(success);
}
void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest( void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest(
base::Optional<std::string> page_token, base::Optional<std::string> page_token,
size_t page_number, size_t page_number,
...@@ -419,7 +477,8 @@ void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest( ...@@ -419,7 +477,8 @@ void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest(
if (page_token) if (page_token)
request.set_page_token(*page_token); request.set_page_token(*page_token);
for (const std::string& id : cert_store_->GetPublicCertificateIds()) { for (const std::string& id :
certificate_storage_->GetPublicCertificateIds()) {
request.add_secret_ids(id); request.add_secret_ids(id);
} }
...@@ -429,13 +488,15 @@ void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest( ...@@ -429,13 +488,15 @@ void NearbyShareCertificateManagerImpl::OnDownloadPublicCertificatesRequest(
client_ = client_factory_->CreateInstance(); client_ = client_factory_->CreateInstance();
client_->ListPublicCertificates( client_->ListPublicCertificates(
request, request,
base::BindOnce(&NearbyShareCertificateManagerImpl::OnRpcSuccess, base::BindOnce(
base::Unretained(this), page_number, certificate_count), &NearbyShareCertificateManagerImpl::OnListPublicCertificatesSuccess,
base::BindOnce(&NearbyShareCertificateManagerImpl::OnRpcFailure, base::Unretained(this), page_number, certificate_count),
base::Unretained(this), page_number, certificate_count)); base::BindOnce(
&NearbyShareCertificateManagerImpl::OnListPublicCertificatesFailure,
base::Unretained(this), page_number, certificate_count));
} }
void NearbyShareCertificateManagerImpl::OnRpcSuccess( void NearbyShareCertificateManagerImpl::OnListPublicCertificatesSuccess(
size_t page_number, size_t page_number,
size_t certificate_count, size_t certificate_count,
const nearbyshare::proto::ListPublicCertificatesResponse& response) { const nearbyshare::proto::ListPublicCertificatesResponse& response) {
...@@ -452,14 +513,14 @@ void NearbyShareCertificateManagerImpl::OnRpcSuccess( ...@@ -452,14 +513,14 @@ void NearbyShareCertificateManagerImpl::OnRpcSuccess(
NS_LOG(VERBOSE) << __func__ << ": " << certs.size() NS_LOG(VERBOSE) << __func__ << ": " << certs.size()
<< " public certificates downloaded."; << " public certificates downloaded.";
cert_store_->AddPublicCertificates( certificate_storage_->AddPublicCertificates(
certs, base::BindOnce( certs, base::BindOnce(&NearbyShareCertificateManagerImpl::
&NearbyShareCertificateManagerImpl::OnPublicCertificatesAdded, OnPublicCertificatesAddedToStorage,
base::Unretained(this), page_token, page_number, base::Unretained(this), page_token, page_number,
certificate_count + certs.size())); certificate_count + certs.size()));
} }
void NearbyShareCertificateManagerImpl::OnRpcFailure( void NearbyShareCertificateManagerImpl::OnListPublicCertificatesFailure(
size_t page_number, size_t page_number,
size_t certificate_count, size_t certificate_count,
NearbyShareHttpError error) { NearbyShareHttpError error) {
...@@ -470,7 +531,7 @@ void NearbyShareCertificateManagerImpl::OnRpcFailure( ...@@ -470,7 +531,7 @@ void NearbyShareCertificateManagerImpl::OnRpcFailure(
certificate_count); certificate_count);
} }
void NearbyShareCertificateManagerImpl::OnPublicCertificatesAdded( void NearbyShareCertificateManagerImpl::OnPublicCertificatesAddedToStorage(
base::Optional<std::string> page_token, base::Optional<std::string> page_token,
size_t page_number, size_t page_number,
size_t certificate_count, size_t certificate_count,
...@@ -494,6 +555,9 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates( ...@@ -494,6 +555,9 @@ void NearbyShareCertificateManagerImpl::FinishDownloadPublicCertificates(
<< __func__ << __func__
<< ": Public certificates successfully downloaded and stored."; << ": Public certificates successfully downloaded and stored.";
NotifyPublicCertificatesDownloaded(); NotifyPublicCertificatesDownloaded();
// Recompute the expiration timer to account for new certificates.
public_certificate_expiration_scheduler_->Reschedule();
} else if (http_result == NearbyShareHttpResult::kSuccess) { } else if (http_result == NearbyShareHttpResult::kSuccess) {
NS_LOG(ERROR) << __func__ << ": Public certificates not stored."; NS_LOG(ERROR) << __func__ << ": Public certificates not stored.";
} else { } else {
......
...@@ -104,35 +104,61 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager { ...@@ -104,35 +104,61 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
void OnStart() override; void OnStart() override;
void OnStop() override; void OnStop() override;
// Removes expired privates certificates, ensures that at least // Used by the private certificate expiration scheduler to determine the next
// kNearbyShareNumPrivateCertificates are present for each visibility with // private certificate expiration time. Returns base::Time::Min() if
// contiguous validity periods, and uploads any changes to the Nearby Share // certificates are missing. This function never returns base::nullopt.
// server. base::Optional<base::Time> NextPrivateCertificateExpirationTime();
base::Time NextPrivateCertificateExpirationTime();
// Used by the public certificate expiration scheduler to determine the next
// public certificate expiration time. Returns base::nullopt if no public
// certificates are present, and no expiration event is scheduled.
base::Optional<base::Time> NextPublicCertificateExpirationTime();
// Invoked by the private certificate expiration scheduler when an expired
// private certificate needs to be removed or if no private certificates exist
// yet. New certificate(s) will be created, and an upload to the Nearby Share
// server will be requested.
void OnPrivateCertificateExpiration(); void OnPrivateCertificateExpiration();
void FinishPrivateCertificateRefresh( void FinishPrivateCertificateRefresh(
std::vector<NearbySharePrivateCertificate> new_certs, std::vector<NearbySharePrivateCertificate> new_certs,
base::flat_map<NearbyShareVisibility, size_t> num_valid_certs, base::flat_map<NearbyShareVisibility, size_t> num_valid_certs,
base::flat_map<NearbyShareVisibility, base::Time> latest_not_after, base::flat_map<NearbyShareVisibility, base::Time> latest_not_after,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter); scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
// Invoked by the certificate upload scheduler when private certificates need
// to be converted to public certificates and uploaded to the Nearby Share
// server.
void OnLocalDeviceCertificateUploadRequest(); void OnLocalDeviceCertificateUploadRequest();
void OnLocalDeviceCertificateUploadFinished(bool success); void OnLocalDeviceCertificateUploadFinished(bool success);
// Invoked by the public certificate expiration scheduler when an expired
// public certificate needs to be removed from storage.
void OnPublicCertificateExpiration();
void OnExpiredPublicCertificatesRemoved(bool success);
// Invoked by the certificate download scheduler when the public certificates
// from trusted contacts need to be downloaded from Nearby Share server via
// the ListPublicCertificates RPC.
void OnDownloadPublicCertificatesRequest( void OnDownloadPublicCertificatesRequest(
base::Optional<std::string> page_token, base::Optional<std::string> page_token,
size_t page_number, size_t page_number,
size_t certificate_count); size_t certificate_count);
void OnRpcSuccess(
void OnListPublicCertificatesSuccess(
size_t page_number, size_t page_number,
size_t certificate_count, size_t certificate_count,
const nearbyshare::proto::ListPublicCertificatesResponse& response); const nearbyshare::proto::ListPublicCertificatesResponse& response);
void OnRpcFailure(size_t page_number, void OnListPublicCertificatesFailure(size_t page_number,
size_t certificate_count, size_t certificate_count,
NearbyShareHttpError error); NearbyShareHttpError error);
void OnPublicCertificatesAdded(base::Optional<std::string> page_token, void OnPublicCertificatesAddedToStorage(
size_t page_number, base::Optional<std::string> page_token,
size_t certificate_count, size_t page_number,
bool success); size_t certificate_count,
bool success);
void FinishDownloadPublicCertificates(bool success, void FinishDownloadPublicCertificates(bool success,
NearbyShareHttpResult http_result, NearbyShareHttpResult http_result,
size_t page_number, size_t page_number,
...@@ -142,12 +168,14 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager { ...@@ -142,12 +168,14 @@ class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager {
PrefService* pref_service_ = nullptr; PrefService* pref_service_ = nullptr;
NearbyShareClientFactory* client_factory_ = nullptr; NearbyShareClientFactory* client_factory_ = nullptr;
base::Clock* clock_ = nullptr; base::Clock* clock_ = nullptr;
std::unique_ptr<NearbyShareCertificateStorage> certificate_storage_;
std::unique_ptr<NearbyShareScheduler> std::unique_ptr<NearbyShareScheduler>
private_certificate_expiration_scheduler_; private_certificate_expiration_scheduler_;
std::unique_ptr<NearbyShareScheduler>
public_certificate_expiration_scheduler_;
std::unique_ptr<NearbyShareScheduler> std::unique_ptr<NearbyShareScheduler>
upload_local_device_certificates_scheduler_; upload_local_device_certificates_scheduler_;
std::unique_ptr<NearbyShareScheduler> download_public_certificates_scheduler_; std::unique_ptr<NearbyShareScheduler> download_public_certificates_scheduler_;
std::unique_ptr<NearbyShareCertificateStorage> cert_store_;
std::unique_ptr<NearbyShareClient> client_; std::unique_ptr<NearbyShareClient> client_;
base::WeakPtrFactory<NearbyShareCertificateManagerImpl> weak_ptr_factory_{ base::WeakPtrFactory<NearbyShareCertificateManagerImpl> weak_ptr_factory_{
this}; this};
......
...@@ -63,12 +63,20 @@ class NearbyShareCertificateManagerImplTest ...@@ -63,12 +63,20 @@ class NearbyShareCertificateManagerImplTest
&clock_); &clock_);
cert_man_->AddObserver(this); cert_man_->AddObserver(this);
cert_store_ = cert_store_factory_.instances().back();
private_cert_exp_scheduler_ = private_cert_exp_scheduler_ =
scheduler_factory_.pref_name_to_expiration_instance() scheduler_factory_.pref_name_to_expiration_instance()
.find( .find(
prefs:: prefs::
kNearbySharingSchedulerPrivateCertificateExpirationPrefName) kNearbySharingSchedulerPrivateCertificateExpirationPrefName)
->second.fake_scheduler; ->second.fake_scheduler;
public_cert_exp_scheduler_ =
scheduler_factory_.pref_name_to_expiration_instance()
.find(
prefs::
kNearbySharingSchedulerPublicCertificateExpirationPrefName)
->second.fake_scheduler;
upload_scheduler_ = upload_scheduler_ =
scheduler_factory_.pref_name_to_on_demand_instance() scheduler_factory_.pref_name_to_on_demand_instance()
.find( .find(
...@@ -80,7 +88,6 @@ class NearbyShareCertificateManagerImplTest ...@@ -80,7 +88,6 @@ class NearbyShareCertificateManagerImplTest
.find(prefs:: .find(prefs::
kNearbySharingSchedulerDownloadPublicCertificatesPrefName) kNearbySharingSchedulerDownloadPublicCertificatesPrefName)
->second.fake_scheduler; ->second.fake_scheduler;
cert_store_ = cert_store_factory_.instances().back();
PopulatePrivateCertificates(); PopulatePrivateCertificates();
PopulatePublicCertificates(); PopulatePublicCertificates();
...@@ -230,6 +237,8 @@ class NearbyShareCertificateManagerImplTest ...@@ -230,6 +237,8 @@ class NearbyShareCertificateManagerImplTest
size_t initial_num_notifications = size_t initial_num_notifications =
num_public_certs_downloaded_notifications_; num_public_certs_downloaded_notifications_;
size_t initial_num_public_cert_exp_reschedules =
public_cert_exp_scheduler_->num_reschedule_calls();
std::string page_token; std::string page_token;
for (size_t page_number = 0; page_number < num_pages; ++page_number) { for (size_t page_number = 0; page_number < num_pages; ++page_number) {
bool last_page = page_number == num_pages - 1; bool last_page = page_number == num_pages - 1;
...@@ -258,10 +267,13 @@ class NearbyShareCertificateManagerImplTest ...@@ -258,10 +267,13 @@ class NearbyShareCertificateManagerImplTest
} }
ASSERT_EQ(download_scheduler_->handled_results().size(), ASSERT_EQ(download_scheduler_->handled_results().size(),
prev_num_results + 1); prev_num_results + 1);
bool success = !rpc_fail && !store_fail; bool success = !rpc_fail && !store_fail;
EXPECT_EQ(download_scheduler_->handled_results().back(), success); EXPECT_EQ(download_scheduler_->handled_results().back(), success);
EXPECT_EQ(initial_num_notifications + (success ? 1u : 0u), EXPECT_EQ(initial_num_notifications + (success ? 1u : 0u),
num_public_certs_downloaded_notifications_); num_public_certs_downloaded_notifications_);
EXPECT_EQ(initial_num_public_cert_exp_reschedules + (success ? 1u : 0u),
public_cert_exp_scheduler_->num_reschedule_calls());
} }
void CheckRpcRequest( void CheckRpcRequest(
...@@ -334,6 +346,7 @@ class NearbyShareCertificateManagerImplTest ...@@ -334,6 +346,7 @@ class NearbyShareCertificateManagerImplTest
FakeNearbyShareCertificateStorage* cert_store_; FakeNearbyShareCertificateStorage* cert_store_;
FakeNearbyShareScheduler* private_cert_exp_scheduler_; FakeNearbyShareScheduler* private_cert_exp_scheduler_;
FakeNearbyShareScheduler* public_cert_exp_scheduler_;
FakeNearbyShareScheduler* upload_scheduler_; FakeNearbyShareScheduler* upload_scheduler_;
FakeNearbyShareScheduler* download_scheduler_; FakeNearbyShareScheduler* download_scheduler_;
std::string bluetooth_mac_address_ = kTestUnparsedBluetoothMacAddress; std::string bluetooth_mac_address_ = kTestUnparsedBluetoothMacAddress;
...@@ -592,3 +605,45 @@ TEST_F(NearbyShareCertificateManagerImplTest, ...@@ -592,3 +605,45 @@ TEST_F(NearbyShareCertificateManagerImplTest,
VerifyPrivateCertificates(/*expected_metadata=*/metadata); VerifyPrivateCertificates(/*expected_metadata=*/metadata);
} }
TEST_F(NearbyShareCertificateManagerImplTest,
RemoveExpiredPublicCertificates_Success) {
clock_.SetNow(t0);
cert_man_->Start();
// The public certificate expiration scheduler notifies the certificate
// manager that a public certificate has expired.
EXPECT_EQ(0u, cert_store_->remove_expired_public_certificates_calls().size());
public_cert_exp_scheduler_->InvokeRequestCallback();
EXPECT_EQ(1u, cert_store_->remove_expired_public_certificates_calls().size());
EXPECT_EQ(t0,
cert_store_->remove_expired_public_certificates_calls().back().now);
EXPECT_EQ(0u, public_cert_exp_scheduler_->handled_results().size());
std::move(
cert_store_->remove_expired_public_certificates_calls().back().callback)
.Run(/*success=*/true);
EXPECT_EQ(1u, public_cert_exp_scheduler_->handled_results().size());
EXPECT_TRUE(public_cert_exp_scheduler_->handled_results().back());
}
TEST_F(NearbyShareCertificateManagerImplTest,
RemoveExpiredPublicCertificates_Failue) {
clock_.SetNow(t0);
cert_man_->Start();
// The public certificate expiration scheduler notifies the certificate
// manager that a public certificate has expired.
EXPECT_EQ(0u, cert_store_->remove_expired_public_certificates_calls().size());
public_cert_exp_scheduler_->InvokeRequestCallback();
EXPECT_EQ(1u, cert_store_->remove_expired_public_certificates_calls().size());
EXPECT_EQ(t0,
cert_store_->remove_expired_public_certificates_calls().back().now);
EXPECT_EQ(0u, public_cert_exp_scheduler_->handled_results().size());
std::move(
cert_store_->remove_expired_public_certificates_calls().back().callback)
.Run(/*success=*/false);
EXPECT_EQ(1u, public_cert_exp_scheduler_->handled_results().size());
EXPECT_FALSE(public_cert_exp_scheduler_->handled_results().back());
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
#include "base/util/values/values_util.h" #include "base/util/values/values_util.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/nearby_sharing/certificates/common.h"
#include "chrome/browser/nearby_sharing/certificates/constants.h" #include "chrome/browser/nearby_sharing/certificates/constants.h"
#include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h" #include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
#include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
...@@ -575,8 +576,16 @@ void NearbyShareCertificateStorageImpl::RemoveExpiredPublicCertificates( ...@@ -575,8 +576,16 @@ void NearbyShareCertificateStorageImpl::RemoveExpiredPublicCertificates(
auto ids_to_remove = std::make_unique<std::vector<std::string>>(); auto ids_to_remove = std::make_unique<std::vector<std::string>>();
for (const auto& pair : public_certificate_expirations_) { for (const auto& pair : public_certificate_expirations_) {
if (pair.second > now) // Because the list is sorted by expiration time, break as soon as we
// encounter an unexpired certificate. Apply a tolerance when evaluating
// whether the certificate is expired to account for clock skew between
// devices. This conforms this the GmsCore implementation.
if (!IsNearbyShareCertificateExpired(
now,
/*not_after=*/pair.second,
/*use_public_certificate_tolerance=*/true)) {
break; break;
}
ids_to_remove->emplace_back(pair.first); ids_to_remove->emplace_back(pair.first);
} }
......
...@@ -438,7 +438,12 @@ TEST_F(NearbyShareCertificateStorageImplTest, RemoveExpiredPublicCertificates) { ...@@ -438,7 +438,12 @@ TEST_F(NearbyShareCertificateStorageImplTest, RemoveExpiredPublicCertificates) {
expiration_times.emplace_back(TimestampToTime(pair.second.end_time())); expiration_times.emplace_back(TimestampToTime(pair.second.end_time()));
} }
std::sort(expiration_times.begin(), expiration_times.end()); std::sort(expiration_times.begin(), expiration_times.end());
base::Time now = expiration_times[1];
// The current time exceeds the expiration times of the first two certificates
// even accounting for the expiration time tolerance applied to public
// certificates to account for clock skew.
base::Time now = expiration_times[1] +
kNearbySharePublicCertificateValidityBoundOffsetTolerance;
bool succeeded = false; bool succeeded = false;
cert_store_->RemoveExpiredPublicCertificates( cert_store_->RemoveExpiredPublicCertificates(
...@@ -450,7 +455,8 @@ TEST_F(NearbyShareCertificateStorageImplTest, RemoveExpiredPublicCertificates) { ...@@ -450,7 +455,8 @@ TEST_F(NearbyShareCertificateStorageImplTest, RemoveExpiredPublicCertificates) {
ASSERT_TRUE(succeeded); ASSERT_TRUE(succeeded);
ASSERT_EQ(1u, db_entries_.size()); ASSERT_EQ(1u, db_entries_.size());
for (const auto& pair : db_entries_) { for (const auto& pair : db_entries_) {
EXPECT_LE(now, TimestampToTime(pair.second.end_time())); EXPECT_LE(now - kNearbySharePublicCertificateValidityBoundOffsetTolerance,
TimestampToTime(pair.second.end_time()));
} }
} }
......
...@@ -42,6 +42,8 @@ const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[] = ...@@ -42,6 +42,8 @@ const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[] =
"nearby_sharing.scheduler.download_public_certificates"; "nearby_sharing.scheduler.download_public_certificates";
const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[] = const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[] =
"nearby_sharing.scheduler.private_certificate_expiration"; "nearby_sharing.scheduler.private_certificate_expiration";
const char kNearbySharingSchedulerPublicCertificateExpirationPrefName[] =
"nearby_sharing.scheduler.public_certificate_expiration";
const char kNearbySharingSchedulerUploadDeviceNamePrefName[] = const char kNearbySharingSchedulerUploadDeviceNamePrefName[] =
"nearby_sharing.scheduler.upload_device_name"; "nearby_sharing.scheduler.upload_device_name";
const char kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[] = const char kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[] =
...@@ -88,6 +90,8 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) { ...@@ -88,6 +90,8 @@ void RegisterNearbySharingPrefs(PrefRegistrySimple* registry) {
prefs::kNearbySharingSchedulerDownloadPublicCertificatesPrefName); prefs::kNearbySharingSchedulerDownloadPublicCertificatesPrefName);
registry->RegisterDictionaryPref( registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerPrivateCertificateExpirationPrefName); prefs::kNearbySharingSchedulerPrivateCertificateExpirationPrefName);
registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerPublicCertificateExpirationPrefName);
registry->RegisterDictionaryPref( registry->RegisterDictionaryPref(
prefs::kNearbySharingSchedulerUploadDeviceNamePrefName); prefs::kNearbySharingSchedulerUploadDeviceNamePrefName);
registry->RegisterDictionaryPref( registry->RegisterDictionaryPref(
......
...@@ -26,6 +26,7 @@ extern const char kNearbySharingSchedulerContactUploadPrefName[]; ...@@ -26,6 +26,7 @@ extern const char kNearbySharingSchedulerContactUploadPrefName[];
extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[]; extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[];
extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[]; extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[];
extern const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[]; extern const char kNearbySharingSchedulerPrivateCertificateExpirationPrefName[];
extern const char kNearbySharingSchedulerPublicCertificateExpirationPrefName[];
extern const char kNearbySharingSchedulerUploadDeviceNamePrefName[]; extern const char kNearbySharingSchedulerUploadDeviceNamePrefName[];
extern const char extern const char
kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[]; kNearbySharingSchedulerUploadLocalDeviceCertificatesPrefName[];
......
...@@ -19,6 +19,10 @@ void FakeNearbyShareScheduler::HandleResult(bool success) { ...@@ -19,6 +19,10 @@ void FakeNearbyShareScheduler::HandleResult(bool success) {
handled_results_.push_back(success); handled_results_.push_back(success);
} }
void FakeNearbyShareScheduler::Reschedule() {
++num_reschedule_calls_;
}
base::Optional<base::Time> FakeNearbyShareScheduler::GetLastSuccessTime() base::Optional<base::Time> FakeNearbyShareScheduler::GetLastSuccessTime()
const { const {
return last_success_time_; return last_success_time_;
......
...@@ -23,6 +23,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler { ...@@ -23,6 +23,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler {
// NearbyShareScheduler: // NearbyShareScheduler:
void MakeImmediateRequest() override; void MakeImmediateRequest() override;
void HandleResult(bool success) override; void HandleResult(bool success) override;
void Reschedule() override;
base::Optional<base::Time> GetLastSuccessTime() const override; base::Optional<base::Time> GetLastSuccessTime() const override;
base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const override; base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const override;
bool IsWaitingForResult() const override; bool IsWaitingForResult() const override;
...@@ -36,6 +37,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler { ...@@ -36,6 +37,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler {
void InvokeRequestCallback(); void InvokeRequestCallback();
size_t num_immediate_requests() const { return num_immediate_requests_; } size_t num_immediate_requests() const { return num_immediate_requests_; }
size_t num_reschedule_calls() const { return num_reschedule_calls_; }
const std::vector<bool>& handled_results() const { return handled_results_; } const std::vector<bool>& handled_results() const { return handled_results_; }
private: private:
...@@ -45,6 +47,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler { ...@@ -45,6 +47,7 @@ class FakeNearbyShareScheduler : public NearbyShareScheduler {
bool can_invoke_request_callback_ = false; bool can_invoke_request_callback_ = false;
size_t num_immediate_requests_ = 0; size_t num_immediate_requests_ = 0;
size_t num_reschedule_calls_ = 0;
std::vector<bool> handled_results_; std::vector<bool> handled_results_;
base::Optional<base::Time> last_success_time_; base::Optional<base::Time> last_success_time_;
base::Optional<base::TimeDelta> time_until_next_request_; base::Optional<base::TimeDelta> time_until_next_request_;
......
...@@ -21,8 +21,8 @@ FakeNearbyShareSchedulerFactory::~FakeNearbyShareSchedulerFactory() = default; ...@@ -21,8 +21,8 @@ FakeNearbyShareSchedulerFactory::~FakeNearbyShareSchedulerFactory() = default;
std::unique_ptr<NearbyShareScheduler> std::unique_ptr<NearbyShareScheduler>
FakeNearbyShareSchedulerFactory::CreateExpirationSchedulerInstance( FakeNearbyShareSchedulerFactory::CreateExpirationSchedulerInstance(
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback, expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
...@@ -30,7 +30,7 @@ FakeNearbyShareSchedulerFactory::CreateExpirationSchedulerInstance( ...@@ -30,7 +30,7 @@ FakeNearbyShareSchedulerFactory::CreateExpirationSchedulerInstance(
NearbyShareScheduler::OnRequestCallback on_request_callback, NearbyShareScheduler::OnRequestCallback on_request_callback,
const base::Clock* clock) { const base::Clock* clock) {
ExpirationInstance instance; ExpirationInstance instance;
instance.expiration_time_callback = std::move(expiration_time_callback); instance.expiration_time_functor = std::move(expiration_time_functor);
instance.retry_failures = retry_failures; instance.retry_failures = retry_failures;
instance.require_connectivity = require_connectivity; instance.require_connectivity = require_connectivity;
instance.pref_service = pref_service; instance.pref_service = pref_service;
......
...@@ -31,8 +31,8 @@ class FakeNearbyShareSchedulerFactory : public NearbyShareSchedulerFactory { ...@@ -31,8 +31,8 @@ class FakeNearbyShareSchedulerFactory : public NearbyShareSchedulerFactory {
~ExpirationInstance(); ~ExpirationInstance();
FakeNearbyShareScheduler* fake_scheduler = nullptr; FakeNearbyShareScheduler* fake_scheduler = nullptr;
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback; expiration_time_functor;
bool retry_failures; bool retry_failures;
bool require_connectivity; bool require_connectivity;
PrefService* pref_service = nullptr; PrefService* pref_service = nullptr;
...@@ -77,8 +77,8 @@ class FakeNearbyShareSchedulerFactory : public NearbyShareSchedulerFactory { ...@@ -77,8 +77,8 @@ class FakeNearbyShareSchedulerFactory : public NearbyShareSchedulerFactory {
private: private:
// NearbyShareSchedulerFactory: // NearbyShareSchedulerFactory:
std::unique_ptr<NearbyShareScheduler> CreateExpirationSchedulerInstance( std::unique_ptr<NearbyShareScheduler> CreateExpirationSchedulerInstance(
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback, expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <utility> #include <utility>
NearbyShareExpirationScheduler::NearbyShareExpirationScheduler( NearbyShareExpirationScheduler::NearbyShareExpirationScheduler(
ExpirationTimeCallback expiration_time_callback, ExpirationTimeFunctor expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
...@@ -21,13 +21,16 @@ NearbyShareExpirationScheduler::NearbyShareExpirationScheduler( ...@@ -21,13 +21,16 @@ NearbyShareExpirationScheduler::NearbyShareExpirationScheduler(
pref_service, pref_service,
std::move(on_request_callback), std::move(on_request_callback),
clock), clock),
expiration_time_callback_(std::move(expiration_time_callback)) {} expiration_time_functor_(std::move(expiration_time_functor)) {}
NearbyShareExpirationScheduler::~NearbyShareExpirationScheduler() = default; NearbyShareExpirationScheduler::~NearbyShareExpirationScheduler() = default;
base::Optional<base::TimeDelta> base::Optional<base::TimeDelta>
NearbyShareExpirationScheduler::TimeUntilRecurringRequest( NearbyShareExpirationScheduler::TimeUntilRecurringRequest(
base::Time now) const { base::Time now) const {
return std::max(base::TimeDelta::FromSeconds(0), base::Optional<base::Time> expiration_time = expiration_time_functor_.Run();
expiration_time_callback_.Run() - now); if (!expiration_time)
return base::nullopt;
return std::max(base::TimeDelta::FromSeconds(0), *expiration_time - now);
} }
...@@ -16,19 +16,19 @@ ...@@ -16,19 +16,19 @@
// expiration time provided by the owner. // expiration time provided by the owner.
class NearbyShareExpirationScheduler : public NearbyShareSchedulerBase { class NearbyShareExpirationScheduler : public NearbyShareSchedulerBase {
public: public:
using ExpirationTimeCallback = base::RepeatingCallback<base::Time()>; using ExpirationTimeFunctor =
base::RepeatingCallback<base::Optional<base::Time>()>;
// |expiration_time_callback|: A function provided by the owner that returns // |expiration_time_functor|: A function provided by the owner that returns
// the next expiration time. // the next expiration time.
// See NearbyShareSchedulerBase for a description of other inputs. // See NearbyShareSchedulerBase for a description of other inputs.
NearbyShareExpirationScheduler( NearbyShareExpirationScheduler(ExpirationTimeFunctor expiration_time_functor,
ExpirationTimeCallback expiration_time_callback, bool retry_failures,
bool retry_failures, bool require_connectivity,
bool require_connectivity, const std::string& pref_name,
const std::string& pref_name, PrefService* pref_service,
PrefService* pref_service, OnRequestCallback on_request_callback,
OnRequestCallback on_request_callback, const base::Clock* clock);
const base::Clock* clock);
~NearbyShareExpirationScheduler() override; ~NearbyShareExpirationScheduler() override;
...@@ -36,7 +36,7 @@ class NearbyShareExpirationScheduler : public NearbyShareSchedulerBase { ...@@ -36,7 +36,7 @@ class NearbyShareExpirationScheduler : public NearbyShareSchedulerBase {
base::Optional<base::TimeDelta> TimeUntilRecurringRequest( base::Optional<base::TimeDelta> TimeUntilRecurringRequest(
base::Time now) const override; base::Time now) const override;
ExpirationTimeCallback expiration_time_callback_; ExpirationTimeFunctor expiration_time_functor_;
}; };
#endif // CHROME_BROWSER_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_EXPIRATION_SCHEDULER_H_ #endif // CHROME_BROWSER_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_EXPIRATION_SCHEDULER_H_
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include "base/bind.h" #include "base/bind.h"
#include "base/optional.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "base/time/time.h" #include "base/time/time.h"
...@@ -39,13 +40,15 @@ class NearbyShareExpirationSchedulerTest : public ::testing::Test { ...@@ -39,13 +40,15 @@ class NearbyShareExpirationSchedulerTest : public ::testing::Test {
scheduler_ = std::make_unique<NearbyShareExpirationScheduler>( scheduler_ = std::make_unique<NearbyShareExpirationScheduler>(
base::BindRepeating( base::BindRepeating(
&NearbyShareExpirationSchedulerTest::TestExpirationTimeCallback, &NearbyShareExpirationSchedulerTest::TestExpirationTimeFunctor,
base::Unretained(this)), base::Unretained(this)),
/*retry_failures=*/true, /*require_connectivity=*/true, kTestPrefName, /*retry_failures=*/true, /*require_connectivity=*/true, kTestPrefName,
&pref_service_, base::DoNothing(), task_environment_.GetMockClock()); &pref_service_, base::DoNothing(), task_environment_.GetMockClock());
} }
base::Time TestExpirationTimeCallback() { return expiration_time_; } base::Optional<base::Time> TestExpirationTimeFunctor() {
return expiration_time_;
}
base::Time Now() const { return task_environment_.GetMockClock()->Now(); } base::Time Now() const { return task_environment_.GetMockClock()->Now(); }
...@@ -54,13 +57,12 @@ class NearbyShareExpirationSchedulerTest : public ::testing::Test { ...@@ -54,13 +57,12 @@ class NearbyShareExpirationSchedulerTest : public ::testing::Test {
task_environment_.FastForwardBy(delta); task_environment_.FastForwardBy(delta);
} }
base::Time expiration_time() const { return expiration_time_; } base::Optional<base::Time> expiration_time_;
NearbyShareScheduler* scheduler() { return scheduler_.get(); } NearbyShareScheduler* scheduler() { return scheduler_.get(); }
private: private:
base::test::SingleThreadTaskEnvironment task_environment_{ base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::Time expiration_time_;
TestingPrefServiceSimple pref_service_; TestingPrefServiceSimple pref_service_;
std::unique_ptr<NearbyShareScheduler> scheduler_; std::unique_ptr<NearbyShareScheduler> scheduler_;
}; };
...@@ -69,8 +71,31 @@ TEST_F(NearbyShareExpirationSchedulerTest, ExpirationRequest) { ...@@ -69,8 +71,31 @@ TEST_F(NearbyShareExpirationSchedulerTest, ExpirationRequest) {
scheduler()->Start(); scheduler()->Start();
// Let 5 minutes elapse since the start time just to make sure the time to the // Let 5 minutes elapse since the start time just to make sure the time to the
// next request only depend on the expiration time and the current time. // next request only depends on the expiration time and the current time.
FastForward(base::TimeDelta::FromMinutes(5)); FastForward(base::TimeDelta::FromMinutes(5));
EXPECT_EQ(expiration_time() - Now(), scheduler()->GetTimeUntilNextRequest()); EXPECT_EQ(*expiration_time_ - Now(), scheduler()->GetTimeUntilNextRequest());
}
TEST_F(NearbyShareExpirationSchedulerTest, Reschedule) {
scheduler()->Start();
FastForward(base::TimeDelta::FromMinutes(5));
base::TimeDelta initial_expected_time_until_next_request =
*expiration_time_ - Now();
EXPECT_EQ(initial_expected_time_until_next_request,
scheduler()->GetTimeUntilNextRequest());
// The expiration time suddenly changes.
expiration_time_ = *expiration_time_ + base::TimeDelta::FromDays(2);
scheduler()->Reschedule();
EXPECT_EQ(
initial_expected_time_until_next_request + base::TimeDelta::FromDays(2),
scheduler()->GetTimeUntilNextRequest());
}
TEST_F(NearbyShareExpirationSchedulerTest, NullExpirationTime) {
expiration_time_.reset();
scheduler()->Start();
EXPECT_EQ(base::nullopt, scheduler()->GetTimeUntilNextRequest());
} }
...@@ -30,10 +30,16 @@ class NearbyShareScheduler { ...@@ -30,10 +30,16 @@ class NearbyShareScheduler {
// Makes a request that runs as soon as possible. // Makes a request that runs as soon as possible.
virtual void MakeImmediateRequest() = 0; virtual void MakeImmediateRequest() = 0;
// Processes the result of the previous request. Method to be called by // Processes the result of the previous request. Method to be called by the
// the owner with the request is finished. // owner when the request is finished. The timer for the next request is
// automatically scheduled.
virtual void HandleResult(bool success) = 0; virtual void HandleResult(bool success) = 0;
// Recomputes the time until the next request, using GetTimeUntilNextRequest()
// as the source of truth. This method is essentially idempotent. NOTE: This
// method should rarely need to be called.
virtual void Reschedule() = 0;
// Returns the time of the last known successful request. If no request has // Returns the time of the last known successful request. If no request has
// succeeded, base::nullopt is returned. // succeeded, base::nullopt is returned.
virtual base::Optional<base::Time> GetLastSuccessTime() const = 0; virtual base::Optional<base::Time> GetLastSuccessTime() const = 0;
...@@ -42,10 +48,8 @@ class NearbyShareScheduler { ...@@ -42,10 +48,8 @@ class NearbyShareScheduler {
// there is no request scheduled. // there is no request scheduled.
virtual base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const = 0; virtual base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const = 0;
// Returns true after the relevant delegate has been alerted of a request // Returns true after the |callback_| has been alerted of a request but before
// |type| but before the delegate has returned the result to the scheduler. // HandleResult() is invoked.
// In other words, between ...Delegate::On...Requested() and
// HandleResult().
virtual bool IsWaitingForResult() const = 0; virtual bool IsWaitingForResult() const = 0;
// The number of times the current request type has failed. // The number of times the current request type has failed.
......
...@@ -60,7 +60,7 @@ NearbyShareSchedulerBase::~NearbyShareSchedulerBase() { ...@@ -60,7 +60,7 @@ NearbyShareSchedulerBase::~NearbyShareSchedulerBase() {
void NearbyShareSchedulerBase::MakeImmediateRequest() { void NearbyShareSchedulerBase::MakeImmediateRequest() {
timer_.Stop(); timer_.Stop();
SetHasPendingImmediateRequest(true); SetHasPendingImmediateRequest(true);
SetTimer(); Reschedule();
} }
void NearbyShareSchedulerBase::HandleResult(bool success) { void NearbyShareSchedulerBase::HandleResult(bool success) {
...@@ -75,7 +75,22 @@ void NearbyShareSchedulerBase::HandleResult(bool success) { ...@@ -75,7 +75,22 @@ void NearbyShareSchedulerBase::HandleResult(bool success) {
} }
SetIsWaitingForResult(false); SetIsWaitingForResult(false);
SetTimer(); Reschedule();
}
void NearbyShareSchedulerBase::Reschedule() {
if (!is_running())
return;
timer_.Stop();
base::Optional<base::TimeDelta> delay = GetTimeUntilNextRequest();
if (!delay)
return;
timer_.Start(FROM_HERE, *delay,
base::BindOnce(&NearbyShareSchedulerBase::OnTimerFired,
base::Unretained(this)));
} }
base::Optional<base::Time> NearbyShareSchedulerBase::GetLastSuccessTime() base::Optional<base::Time> NearbyShareSchedulerBase::GetLastSuccessTime()
...@@ -123,7 +138,7 @@ size_t NearbyShareSchedulerBase::GetNumConsecutiveFailures() const { ...@@ -123,7 +138,7 @@ size_t NearbyShareSchedulerBase::GetNumConsecutiveFailures() const {
} }
void NearbyShareSchedulerBase::OnStart() { void NearbyShareSchedulerBase::OnStart() {
SetTimer(); Reschedule();
} }
void NearbyShareSchedulerBase::OnStop() { void NearbyShareSchedulerBase::OnStop() {
...@@ -135,7 +150,7 @@ void NearbyShareSchedulerBase::OnConnectionChanged( ...@@ -135,7 +150,7 @@ void NearbyShareSchedulerBase::OnConnectionChanged(
if (content::GetNetworkConnectionTracker()->IsOffline()) if (content::GetNetworkConnectionTracker()->IsOffline())
return; return;
SetTimer(); Reschedule();
} }
base::Optional<base::Time> NearbyShareSchedulerBase::GetLastAttemptTime() base::Optional<base::Time> NearbyShareSchedulerBase::GetLastAttemptTime()
...@@ -215,21 +230,6 @@ base::Optional<base::TimeDelta> NearbyShareSchedulerBase::TimeUntilRetry( ...@@ -215,21 +230,6 @@ base::Optional<base::TimeDelta> NearbyShareSchedulerBase::TimeUntilRetry(
return std::max(kZeroTimeDelta, delay - time_elapsed_since_last_attempt); return std::max(kZeroTimeDelta, delay - time_elapsed_since_last_attempt);
} }
void NearbyShareSchedulerBase::SetTimer() {
if (!is_running())
return;
timer_.Stop();
base::Optional<base::TimeDelta> delay = GetTimeUntilNextRequest();
if (!delay)
return;
timer_.Start(FROM_HERE, *delay,
base::BindOnce(&NearbyShareSchedulerBase::OnTimerFired,
base::Unretained(this)));
}
void NearbyShareSchedulerBase::OnTimerFired() { void NearbyShareSchedulerBase::OnTimerFired() {
DCHECK(is_running()); DCHECK(is_running());
if (require_connectivity_ && if (require_connectivity_ &&
......
...@@ -65,6 +65,7 @@ class NearbyShareSchedulerBase ...@@ -65,6 +65,7 @@ class NearbyShareSchedulerBase
// NearbyShareScheduler: // NearbyShareScheduler:
void MakeImmediateRequest() override; void MakeImmediateRequest() override;
void HandleResult(bool success) override; void HandleResult(bool success) override;
void Reschedule() override;
base::Optional<base::Time> GetLastSuccessTime() const override; base::Optional<base::Time> GetLastSuccessTime() const override;
base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const override; base::Optional<base::TimeDelta> GetTimeUntilNextRequest() const override;
bool IsWaitingForResult() const override; bool IsWaitingForResult() const override;
...@@ -95,10 +96,6 @@ class NearbyShareSchedulerBase ...@@ -95,10 +96,6 @@ class NearbyShareSchedulerBase
// enabled for the scheduler. // enabled for the scheduler.
base::Optional<base::TimeDelta> TimeUntilRetry(base::Time now) const; base::Optional<base::TimeDelta> TimeUntilRetry(base::Time now) const;
// Schedules/Reschedules request, using GetTimeUntilNextRequest() as the
// source of truth. This method is essentially idempotent.
void SetTimer();
// Notifies the owner that a request is ready. Early returns if not online and // Notifies the owner that a request is ready. Early returns if not online and
// the scheduler requires connectivity; the attempt is rescheduled when // the scheduler requires connectivity; the attempt is rescheduled when
// connectivity is restored. // connectivity is restored.
......
...@@ -16,8 +16,8 @@ NearbyShareSchedulerFactory* NearbyShareSchedulerFactory::test_factory_ = ...@@ -16,8 +16,8 @@ NearbyShareSchedulerFactory* NearbyShareSchedulerFactory::test_factory_ =
// static // static
std::unique_ptr<NearbyShareScheduler> std::unique_ptr<NearbyShareScheduler>
NearbyShareSchedulerFactory::CreateExpirationScheduler( NearbyShareSchedulerFactory::CreateExpirationScheduler(
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback, expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
...@@ -26,13 +26,13 @@ NearbyShareSchedulerFactory::CreateExpirationScheduler( ...@@ -26,13 +26,13 @@ NearbyShareSchedulerFactory::CreateExpirationScheduler(
const base::Clock* clock) { const base::Clock* clock) {
if (test_factory_) { if (test_factory_) {
return test_factory_->CreateExpirationSchedulerInstance( return test_factory_->CreateExpirationSchedulerInstance(
std::move(expiration_time_callback), retry_failures, std::move(expiration_time_functor), retry_failures,
require_connectivity, pref_name, pref_service, require_connectivity, pref_name, pref_service,
std::move(on_request_callback), clock); std::move(on_request_callback), clock);
} }
return std::make_unique<NearbyShareExpirationScheduler>( return std::make_unique<NearbyShareExpirationScheduler>(
std::move(expiration_time_callback), retry_failures, require_connectivity, std::move(expiration_time_functor), retry_failures, require_connectivity,
pref_name, pref_service, std::move(on_request_callback), clock); pref_name, pref_service, std::move(on_request_callback), clock);
} }
......
...@@ -21,8 +21,8 @@ class PrefService; ...@@ -21,8 +21,8 @@ class PrefService;
class NearbyShareSchedulerFactory { class NearbyShareSchedulerFactory {
public: public:
static std::unique_ptr<NearbyShareScheduler> CreateExpirationScheduler( static std::unique_ptr<NearbyShareScheduler> CreateExpirationScheduler(
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback, expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
...@@ -54,8 +54,8 @@ class NearbyShareSchedulerFactory { ...@@ -54,8 +54,8 @@ class NearbyShareSchedulerFactory {
virtual std::unique_ptr<NearbyShareScheduler> virtual std::unique_ptr<NearbyShareScheduler>
CreateExpirationSchedulerInstance( CreateExpirationSchedulerInstance(
NearbyShareExpirationScheduler::ExpirationTimeCallback NearbyShareExpirationScheduler::ExpirationTimeFunctor
expiration_time_callback, expiration_time_functor,
bool retry_failures, bool retry_failures,
bool require_connectivity, bool require_connectivity,
const std::string& pref_name, const std::string& pref_name,
......
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