Commit 76714f75 authored by Polina Bondarenko's avatar Polina Bondarenko Committed by Chromium LUCI CQ

arc: Add expiring of snapshots in 30 days

ARC data snapshots must be expired in 30 days if not updated.
Added timer to SnapshotInfo and tests.

BUG=b:161221001
TEST=components_unittests

Change-Id: If5cffeeba0957a0e5e9225c835241ec47a486c3e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2502690
Commit-Queue: Polina Bondarenko <pbond@chromium.org>
Auto-Submit: Polina Bondarenko <pbond@chromium.org>
Reviewed-by: default avatarOleksandr Peletskyi <peletskyi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845260}
parent 48b27c5c
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/util/values/values_util.h"
#include "base/values.h" #include "base/values.h"
#include "chromeos/constants/chromeos_switches.h" #include "chromeos/constants/chromeos_switches.h"
#include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/cryptohome/cryptohome_parameters.h"
...@@ -44,6 +45,9 @@ constexpr char kLast[] = "last"; ...@@ -44,6 +45,9 @@ constexpr char kLast[] = "last";
constexpr char kBlockedUiReboot[] = "blocked_ui_reboot"; constexpr char kBlockedUiReboot[] = "blocked_ui_reboot";
constexpr char kStarted[] = "started"; constexpr char kStarted[] = "started";
// Snapshot muss automatically expire in 30 days if not updated.
constexpr base::TimeDelta kSnapshotMaxLifetime = base::TimeDelta::FromDays(30);
// Returns true if the Chrome session is restored after crash. // Returns true if the Chrome session is restored after crash.
bool IsRestoredSession() { bool IsRestoredSession() {
auto* command_line = base::CommandLine::ForCurrentProcess(); auto* command_line = base::CommandLine::ForCurrentProcess();
...@@ -89,8 +93,7 @@ static ArcDataSnapshotdManager* g_arc_data_snapshotd_manager = nullptr; ...@@ -89,8 +93,7 @@ static ArcDataSnapshotdManager* g_arc_data_snapshotd_manager = nullptr;
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(bool last) ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(bool last)
: is_last_(last) { : is_last_(last) {
os_version_ = base::SysInfo::OperatingSystemVersion(); os_version_ = base::SysInfo::OperatingSystemVersion();
creation_date_ = UpdateCreationDate(base::Time::Now());
base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(base::Time::Now()));
} }
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value, ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value,
...@@ -105,9 +108,11 @@ ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value, ...@@ -105,9 +108,11 @@ ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value,
os_version_ = *found; os_version_ = *found;
} }
{ {
auto* found = dict->FindStringPath(kCreationDate); auto* found = dict->FindPath(kCreationDate);
if (found) if (found && util::ValueToTime(found).has_value()) {
creation_date_ = *found; auto parsed_time = util::ValueToTime(found).value();
UpdateCreationDate(parsed_time);
}
} }
{ {
auto found = dict->FindBoolPath(kVerified); auto found = dict->FindBoolPath(kVerified);
...@@ -128,7 +133,7 @@ ArcDataSnapshotdManager::SnapshotInfo::~SnapshotInfo() = default; ...@@ -128,7 +133,7 @@ ArcDataSnapshotdManager::SnapshotInfo::~SnapshotInfo() = default;
std::unique_ptr<ArcDataSnapshotdManager::SnapshotInfo> std::unique_ptr<ArcDataSnapshotdManager::SnapshotInfo>
ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting( ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
const std::string& os_version, const std::string& os_version,
const std::string& creation_date, const base::Time& creation_date,
bool verified, bool verified,
bool updated, bool updated,
bool last) { bool last) {
...@@ -142,7 +147,7 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) { ...@@ -142,7 +147,7 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) {
base::DictionaryValue value; base::DictionaryValue value;
value.SetStringKey(kOsVersion, os_version_); value.SetStringKey(kOsVersion, os_version_);
value.SetStringKey(kCreationDate, creation_date_); value.SetKey(kCreationDate, util::TimeToValue(creation_date_));
value.SetBoolKey(kVerified, verified_); value.SetBoolKey(kVerified, verified_);
value.SetBoolKey(kUpdated, updated_); value.SetBoolKey(kUpdated, updated_);
...@@ -150,7 +155,12 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) { ...@@ -150,7 +155,12 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) {
} }
bool ArcDataSnapshotdManager::SnapshotInfo::IsExpired() const { bool ArcDataSnapshotdManager::SnapshotInfo::IsExpired() const {
// TODO(pbond): implement; if (creation_date_ + kSnapshotMaxLifetime <= base::Time::Now()) {
VLOG(1) << GetDictPath() << " snapshot is expired. creation_date="
<< base::UTF16ToUTF8(
base::TimeFormatShortDateAndTime(creation_date_));
return true;
}
return false; return false;
} }
...@@ -160,20 +170,45 @@ bool ArcDataSnapshotdManager::SnapshotInfo::IsOsVersionUpdated() const { ...@@ -160,20 +170,45 @@ bool ArcDataSnapshotdManager::SnapshotInfo::IsOsVersionUpdated() const {
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo( ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(
const std::string& os_version, const std::string& os_version,
const std::string& creation_date, const base::Time& creation_date,
bool verified, bool verified,
bool updated, bool updated,
bool last) bool last)
: is_last_(last), : is_last_(last),
os_version_(os_version), os_version_(os_version),
creation_date_(creation_date),
verified_(verified), verified_(verified),
updated_(updated) {} updated_(updated) {
UpdateCreationDate(creation_date);
}
std::string ArcDataSnapshotdManager::SnapshotInfo::GetDictPath() const { std::string ArcDataSnapshotdManager::SnapshotInfo::GetDictPath() const {
return is_last_ ? kLast : kPrevious; return is_last_ ? kLast : kPrevious;
} }
void ArcDataSnapshotdManager::SnapshotInfo::UpdateCreationDate(
const base::Time& creation_date) {
creation_date_ = creation_date;
if (lifetime_timer_.IsRunning()) {
LOG(ERROR) << "Updating a snapshot lifetime timer.";
lifetime_timer_.Stop();
}
// If the snapshot is expired on initialization, it is expected to be cleared
// soon in the flow.
if (IsExpired())
return;
base::TimeDelta delay =
creation_date_ + kSnapshotMaxLifetime - base::Time::Now();
lifetime_timer_.Start(
FROM_HERE, delay,
base::BindOnce(&ArcDataSnapshotdManager::SnapshotInfo::OnSnapshotExpired,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcDataSnapshotdManager::SnapshotInfo::OnSnapshotExpired() {
DCHECK(ArcDataSnapshotdManager::Get());
ArcDataSnapshotdManager::Get()->OnSnapshotExpired();
}
ArcDataSnapshotdManager::Snapshot::Snapshot(PrefService* local_state) ArcDataSnapshotdManager::Snapshot::Snapshot(PrefService* local_state)
: local_state_(local_state) { : local_state_(local_state) {
DCHECK(local_state_); DCHECK(local_state_);
...@@ -280,11 +315,6 @@ ArcDataSnapshotdManager::Snapshot::Snapshot( ...@@ -280,11 +315,6 @@ ArcDataSnapshotdManager::Snapshot::Snapshot(
DCHECK(local_state_); DCHECK(local_state_);
} }
// static
ArcDataSnapshotdManager* ArcDataSnapshotdManager::Get() {
return g_arc_data_snapshotd_manager;
}
ArcDataSnapshotdManager::ArcDataSnapshotdManager( ArcDataSnapshotdManager::ArcDataSnapshotdManager(
PrefService* local_state, PrefService* local_state,
std::unique_ptr<Delegate> delegate, std::unique_ptr<Delegate> delegate,
...@@ -330,6 +360,16 @@ ArcDataSnapshotdManager::~ArcDataSnapshotdManager() { ...@@ -330,6 +360,16 @@ ArcDataSnapshotdManager::~ArcDataSnapshotdManager() {
EnsureDaemonStopped(base::DoNothing()); EnsureDaemonStopped(base::DoNothing());
} }
// static
ArcDataSnapshotdManager* ArcDataSnapshotdManager::Get() {
return g_arc_data_snapshotd_manager;
}
// static
base::TimeDelta ArcDataSnapshotdManager::snapshot_max_lifetime_for_testing() {
return kSnapshotMaxLifetime;
}
void ArcDataSnapshotdManager::EnsureDaemonStarted(base::OnceClosure callback) { void ArcDataSnapshotdManager::EnsureDaemonStarted(base::OnceClosure callback) {
if (bridge_) { if (bridge_) {
std::move(callback).Run(); std::move(callback).Run();
...@@ -617,6 +657,28 @@ void ArcDataSnapshotdManager::UpdateUi(int percent) { ...@@ -617,6 +657,28 @@ void ArcDataSnapshotdManager::UpdateUi(int percent) {
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
} }
void ArcDataSnapshotdManager::OnSnapshotExpired() {
switch (state_) {
case State::kBlockedUi:
case State::kMgsToLaunch:
case State::kMgsLaunched:
case State::kStopping:
LOG(WARNING) << "Expired snapshots are cleared in scope of this process.";
return;
case State::kLoading:
// The expired snapshot may be in the process of being loaded to the
// running MGS. Postpone the removal until the chrome session restart.
LOG(WARNING)
<< "The snapshot is expired while might be in use. Postpone exire.";
return;
case State::kNone:
case State::kRestored:
case State::kRunning:
DoClearSnapshots();
return;
}
}
void ArcDataSnapshotdManager::OnSnapshotsCleared(bool success) { void ArcDataSnapshotdManager::OnSnapshotsCleared(bool success) {
switch (state_) { switch (state_) {
case State::kBlockedUi: case State::kBlockedUi:
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "components/arc/enterprise/arc_apps_tracker.h" #include "components/arc/enterprise/arc_apps_tracker.h"
#include "components/arc/enterprise/snapshot_hours_policy_service.h" #include "components/arc/enterprise/snapshot_hours_policy_service.h"
#include "components/arc/enterprise/snapshot_reboot_controller.h" #include "components/arc/enterprise/snapshot_reboot_controller.h"
...@@ -93,7 +94,7 @@ class ArcDataSnapshotdManager final ...@@ -93,7 +94,7 @@ class ArcDataSnapshotdManager final
// dictionary. // dictionary.
static std::unique_ptr<SnapshotInfo> CreateForTesting( static std::unique_ptr<SnapshotInfo> CreateForTesting(
const std::string& os_version, const std::string& os_version,
const std::string& creation_date, const base::Time& creation_date,
bool verified, bool verified,
bool updated, bool updated,
bool last); bool last);
...@@ -116,7 +117,7 @@ class ArcDataSnapshotdManager final ...@@ -116,7 +117,7 @@ class ArcDataSnapshotdManager final
private: private:
SnapshotInfo(const std::string& os_version, SnapshotInfo(const std::string& os_version,
const std::string& creation_date, const base::Time& creation_date,
bool verified, bool verified,
bool updated, bool updated,
bool last); bool last);
...@@ -124,14 +125,25 @@ class ArcDataSnapshotdManager final ...@@ -124,14 +125,25 @@ class ArcDataSnapshotdManager final
// Returns dictionary path in arc.snapshot local state preference. // Returns dictionary path in arc.snapshot local state preference.
std::string GetDictPath() const; std::string GetDictPath() const;
void UpdateCreationDate(const base::Time& creation_date);
// Called once this snapshot is expired.
void OnSnapshotExpired();
bool is_last_; bool is_last_;
// Values should be kept in sync with values stored in arc.snapshot.last or // Values should be kept in sync with values stored in arc.snapshot.last or
// arc.snapshot.previous preferences. // arc.snapshot.previous preferences.
std::string os_version_; std::string os_version_;
std::string creation_date_; base::Time creation_date_;
bool verified_ = false; bool verified_ = false;
bool updated_ = false; bool updated_ = false;
// The snapshots' lifetime timer is fired when this snapshot must be
// cleared.
base::OneShotTimer lifetime_timer_;
base::WeakPtrFactory<SnapshotInfo> weak_ptr_factory_{this};
}; };
// This class operates with a snapshot related info including mode and // This class operates with a snapshot related info including mode and
...@@ -210,6 +222,8 @@ class ArcDataSnapshotdManager final ...@@ -210,6 +222,8 @@ class ArcDataSnapshotdManager final
static ArcDataSnapshotdManager* Get(); static ArcDataSnapshotdManager* Get();
static base::TimeDelta snapshot_max_lifetime_for_testing();
// Starts arc-data-snapshotd. // Starts arc-data-snapshotd.
void EnsureDaemonStarted(base::OnceClosure callback); void EnsureDaemonStarted(base::OnceClosure callback);
// Stops arc-data-snapshotd. // Stops arc-data-snapshotd.
...@@ -287,6 +301,8 @@ class ArcDataSnapshotdManager final ...@@ -287,6 +301,8 @@ class ArcDataSnapshotdManager final
void LoadSnapshot(const std::string& account_id, base::OnceClosure callback); void LoadSnapshot(const std::string& account_id, base::OnceClosure callback);
void UpdateUi(int percent); void UpdateUi(int percent);
// Called once a snapshot is expired.
void OnSnapshotExpired();
// Called once the outdated snapshots were removed or ensured that there are // Called once the outdated snapshots were removed or ensured that there are
// no outdated snapshots. // no outdated snapshots.
void OnSnapshotsCleared(bool success); void OnSnapshotsCleared(bool success);
......
...@@ -263,10 +263,10 @@ class ArcDataSnapshotdManagerBasicTest : public testing::Test { ...@@ -263,10 +263,10 @@ class ArcDataSnapshotdManagerBasicTest : public testing::Test {
// mode. // mode.
void SetupLocalState(bool blocked_ui_mode) { void SetupLocalState(bool blocked_ui_mode) {
auto last = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting( auto last = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
base::SysInfo::OperatingSystemVersion(), "" /* creation_date */, base::SysInfo::OperatingSystemVersion(), base::Time::Now(),
false /* verified */, false /* updated */, true /* last */); false /* verified */, false /* updated */, true /* last */);
auto previous = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting( auto previous = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
base::SysInfo::OperatingSystemVersion(), "" /* creation_date */, base::SysInfo::OperatingSystemVersion(), base::Time::Now(),
false /* verified */, false /* updated */, false /* last */); false /* verified */, false /* updated */, false /* last */);
auto snapshot = ArcDataSnapshotdManager::Snapshot::CreateForTesting( auto snapshot = ArcDataSnapshotdManager::Snapshot::CreateForTesting(
local_state(), blocked_ui_mode, false /* started */, std::move(last), local_state(), blocked_ui_mode, false /* started */, std::move(last),
...@@ -340,6 +340,13 @@ class ArcDataSnapshotdManagerStateTest ...@@ -340,6 +340,13 @@ class ArcDataSnapshotdManagerStateTest
public ::testing::WithParamInterface<ArcDataSnapshotdManager::State> { public ::testing::WithParamInterface<ArcDataSnapshotdManager::State> {
public: public:
ArcDataSnapshotdManager::State expected_state() { return GetParam(); } ArcDataSnapshotdManager::State expected_state() { return GetParam(); }
// Expire snapshots in max lifetime.
void ExpireSnapshots() {
task_environment_.FastForwardBy(
ArcDataSnapshotdManager::snapshot_max_lifetime_for_testing());
task_environment_.RunUntilIdle();
}
}; };
// Tests flows in ArcDataSnapshotdManager: // Tests flows in ArcDataSnapshotdManager:
...@@ -877,6 +884,43 @@ TEST_P(ArcDataSnapshotdManagerStateTest, OnSnapshotUpdateEndTimeChanged) { ...@@ -877,6 +884,43 @@ TEST_P(ArcDataSnapshotdManagerStateTest, OnSnapshotUpdateEndTimeChanged) {
} }
} }
TEST_P(ArcDataSnapshotdManagerStateTest, ExpireSnapshots) {
SetupLocalState(false /* blocked_ui_mode */);
ExpectStopDaemon(true /* success */);
ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */);
auto* manager = CreateManager();
manager->set_state_for_testing(expected_state());
EXPECT_EQ(manager->state(), expected_state());
EXPECT_FALSE(manager->bridge());
CheckSnapshots(2 /* expected_snapshots_number */,
false /* expected_blocked_ui_mode */);
int expected_snapshots_num;
switch (expected_state()) {
case ArcDataSnapshotdManager::State::kBlockedUi:
case ArcDataSnapshotdManager::State::kMgsToLaunch:
case ArcDataSnapshotdManager::State::kMgsLaunched:
case ArcDataSnapshotdManager::State::kLoading:
case ArcDataSnapshotdManager::State::kStopping:
// Do not expire snapshots if in these states. The expectation is that
// they are cleared during the flow or on the next session start up.
expected_snapshots_num = 2;
break;
case ArcDataSnapshotdManager::State::kNone:
case ArcDataSnapshotdManager::State::kRestored:
case ArcDataSnapshotdManager::State::kRunning:
// Expect snapshots to be cleared.
ExpectStartDaemon(true /* success */);
ExpectStopDaemon(true /* success */);
expected_snapshots_num = 0;
break;
}
ExpireSnapshots();
CheckSnapshots(expected_snapshots_num, false /* expected_blocked_ui_mode */);
}
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
ArcDataSnapshotdManagerTest, ArcDataSnapshotdManagerTest,
ArcDataSnapshotdManagerStateTest, ArcDataSnapshotdManagerStateTest,
......
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