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 @@
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "base/util/values/values_util.h"
#include "base/values.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
......@@ -44,6 +45,9 @@ constexpr char kLast[] = "last";
constexpr char kBlockedUiReboot[] = "blocked_ui_reboot";
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.
bool IsRestoredSession() {
auto* command_line = base::CommandLine::ForCurrentProcess();
......@@ -89,8 +93,7 @@ static ArcDataSnapshotdManager* g_arc_data_snapshotd_manager = nullptr;
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(bool last)
: is_last_(last) {
os_version_ = base::SysInfo::OperatingSystemVersion();
creation_date_ =
base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(base::Time::Now()));
UpdateCreationDate(base::Time::Now());
}
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value,
......@@ -105,9 +108,11 @@ ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value,
os_version_ = *found;
}
{
auto* found = dict->FindStringPath(kCreationDate);
if (found)
creation_date_ = *found;
auto* found = dict->FindPath(kCreationDate);
if (found && util::ValueToTime(found).has_value()) {
auto parsed_time = util::ValueToTime(found).value();
UpdateCreationDate(parsed_time);
}
}
{
auto found = dict->FindBoolPath(kVerified);
......@@ -128,7 +133,7 @@ ArcDataSnapshotdManager::SnapshotInfo::~SnapshotInfo() = default;
std::unique_ptr<ArcDataSnapshotdManager::SnapshotInfo>
ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
const std::string& os_version,
const std::string& creation_date,
const base::Time& creation_date,
bool verified,
bool updated,
bool last) {
......@@ -142,7 +147,7 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) {
base::DictionaryValue value;
value.SetStringKey(kOsVersion, os_version_);
value.SetStringKey(kCreationDate, creation_date_);
value.SetKey(kCreationDate, util::TimeToValue(creation_date_));
value.SetBoolKey(kVerified, verified_);
value.SetBoolKey(kUpdated, updated_);
......@@ -150,7 +155,12 @@ void ArcDataSnapshotdManager::SnapshotInfo::Sync(base::Value* dict) {
}
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;
}
......@@ -160,20 +170,45 @@ bool ArcDataSnapshotdManager::SnapshotInfo::IsOsVersionUpdated() const {
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(
const std::string& os_version,
const std::string& creation_date,
const base::Time& creation_date,
bool verified,
bool updated,
bool last)
: is_last_(last),
os_version_(os_version),
creation_date_(creation_date),
verified_(verified),
updated_(updated) {}
updated_(updated) {
UpdateCreationDate(creation_date);
}
std::string ArcDataSnapshotdManager::SnapshotInfo::GetDictPath() const {
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)
: local_state_(local_state) {
DCHECK(local_state_);
......@@ -280,11 +315,6 @@ ArcDataSnapshotdManager::Snapshot::Snapshot(
DCHECK(local_state_);
}
// static
ArcDataSnapshotdManager* ArcDataSnapshotdManager::Get() {
return g_arc_data_snapshotd_manager;
}
ArcDataSnapshotdManager::ArcDataSnapshotdManager(
PrefService* local_state,
std::unique_ptr<Delegate> delegate,
......@@ -330,6 +360,16 @@ ArcDataSnapshotdManager::~ArcDataSnapshotdManager() {
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) {
if (bridge_) {
std::move(callback).Run();
......@@ -617,6 +657,28 @@ void ArcDataSnapshotdManager::UpdateUi(int percent) {
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) {
switch (state_) {
case State::kBlockedUi:
......
......@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "components/arc/enterprise/arc_apps_tracker.h"
#include "components/arc/enterprise/snapshot_hours_policy_service.h"
#include "components/arc/enterprise/snapshot_reboot_controller.h"
......@@ -93,7 +94,7 @@ class ArcDataSnapshotdManager final
// dictionary.
static std::unique_ptr<SnapshotInfo> CreateForTesting(
const std::string& os_version,
const std::string& creation_date,
const base::Time& creation_date,
bool verified,
bool updated,
bool last);
......@@ -116,7 +117,7 @@ class ArcDataSnapshotdManager final
private:
SnapshotInfo(const std::string& os_version,
const std::string& creation_date,
const base::Time& creation_date,
bool verified,
bool updated,
bool last);
......@@ -124,14 +125,25 @@ class ArcDataSnapshotdManager final
// Returns dictionary path in arc.snapshot local state preference.
std::string GetDictPath() const;
void UpdateCreationDate(const base::Time& creation_date);
// Called once this snapshot is expired.
void OnSnapshotExpired();
bool is_last_;
// Values should be kept in sync with values stored in arc.snapshot.last or
// arc.snapshot.previous preferences.
std::string os_version_;
std::string creation_date_;
base::Time creation_date_;
bool verified_ = 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
......@@ -210,6 +222,8 @@ class ArcDataSnapshotdManager final
static ArcDataSnapshotdManager* Get();
static base::TimeDelta snapshot_max_lifetime_for_testing();
// Starts arc-data-snapshotd.
void EnsureDaemonStarted(base::OnceClosure callback);
// Stops arc-data-snapshotd.
......@@ -287,6 +301,8 @@ class ArcDataSnapshotdManager final
void LoadSnapshot(const std::string& account_id, base::OnceClosure callback);
void UpdateUi(int percent);
// Called once a snapshot is expired.
void OnSnapshotExpired();
// Called once the outdated snapshots were removed or ensured that there are
// no outdated snapshots.
void OnSnapshotsCleared(bool success);
......
......@@ -263,10 +263,10 @@ class ArcDataSnapshotdManagerBasicTest : public testing::Test {
// mode.
void SetupLocalState(bool blocked_ui_mode) {
auto last = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
base::SysInfo::OperatingSystemVersion(), "" /* creation_date */,
base::SysInfo::OperatingSystemVersion(), base::Time::Now(),
false /* verified */, false /* updated */, true /* last */);
auto previous = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
base::SysInfo::OperatingSystemVersion(), "" /* creation_date */,
base::SysInfo::OperatingSystemVersion(), base::Time::Now(),
false /* verified */, false /* updated */, false /* last */);
auto snapshot = ArcDataSnapshotdManager::Snapshot::CreateForTesting(
local_state(), blocked_ui_mode, false /* started */, std::move(last),
......@@ -340,6 +340,13 @@ class ArcDataSnapshotdManagerStateTest
public ::testing::WithParamInterface<ArcDataSnapshotdManager::State> {
public:
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:
......@@ -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(
ArcDataSnapshotdManagerTest,
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