Reland "demomode: Delete user created files between shopper sessions"
This is a reland of commit 7166891c62
Fixed MSAN tests.
Original change's description:
> demomode: Delete user created files between shopper sessions
>
> Delete all files under 'MyFiles' and reset demo media data when device
> is idle, which is the end of one shopper session.
>
> Bug: 396731490
> Change-Id: Ic9a2f69f33261661dc771a980f036f14580cf1b0
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6292333
> Reviewed-by: Li Lin <llin@chromium.org>
> Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
> Commit-Queue: Xiqi Ruan <xiqiruan@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1433918}
Bug: 396731490
Change-Id: I4ffbb58603780b538a2f0b2e9db1083be623775a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6367236
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Commit-Queue: Xiqi Ruan <xiqiruan@chromium.org>
Reviewed-by: Li Lin <llin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1437951}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
ec228c06d4
commit
dcf0508732
ash/constants
chrome/browser
ash
login
chromeos
extensions
login_screen
login
@ -577,6 +577,12 @@ BASE_FEATURE(kDemoModeWallpaperUpdate,
|
||||
"DemoModeWallpaperUpdate",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// Controls whether clean up local files between shopper session when demo mode
|
||||
// sign in is enable. No-op if demo mode sign in is disabled.
|
||||
BASE_FEATURE(kDemoModeSignInFileCleanup,
|
||||
"DemoModeSignInFileCleanup",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// Toggle different display features based on user setting and power state
|
||||
BASE_FEATURE(kDisplayPerformanceMode,
|
||||
"DisplayPerformanceMode",
|
||||
@ -3517,6 +3523,10 @@ bool IsDemoModeWallpaperUpdateEnabled() {
|
||||
return base::FeatureList::IsEnabled(kDemoModeWallpaperUpdate);
|
||||
}
|
||||
|
||||
bool IsDemoModeSignInFileCleanupEnabled() {
|
||||
return base::FeatureList::IsEnabled(kDemoModeSignInFileCleanup);
|
||||
}
|
||||
|
||||
bool IsDeskTemplateSyncEnabled() {
|
||||
return base::FeatureList::IsEnabled(kDeskTemplateSync);
|
||||
}
|
||||
|
@ -178,6 +178,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
BASE_DECLARE_FEATURE(kDemoModeSignIn);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
BASE_DECLARE_FEATURE(kDemoModeWallpaperUpdate);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
BASE_DECLARE_FEATURE(kDemoModeSignInFileCleanup);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDeskTemplateSync);
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
BASE_DECLARE_FEATURE(kDeviceActiveClient28DayActiveCheckMembership);
|
||||
@ -1093,6 +1095,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDeepLinkingEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDemoModeAppLandscapeLockedEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDemoModeSignInEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDemoModeWallpaperUpdateEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDemoModeSignInFileCleanupEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDeskTemplateSyncEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDisplayPerformanceModeEnabled();
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsInputDeviceSettingsSplitEnabled();
|
||||
|
@ -50,6 +50,7 @@ static_library("demo_mode") {
|
||||
"//chrome/browser/ash/policy/core",
|
||||
"//chrome/browser/ash/policy/enrollment",
|
||||
"//chrome/browser/ash/profiles",
|
||||
"//chrome/browser/chromeos/extensions/login_screen/login/cleanup",
|
||||
"//chrome/browser/ui:browser_list",
|
||||
"//chrome/common",
|
||||
"//chromeos/ash/components/dbus",
|
||||
|
@ -29,6 +29,7 @@ include_rules = [
|
||||
"+chrome/browser/browser_process_platform_part.h",
|
||||
"+chrome/browser/chrome_browser_main_extra_parts.h",
|
||||
"+chrome/browser/chrome_browser_main.h",
|
||||
"+chrome/browser/chromeos/extensions/login_screen/login/cleanup",
|
||||
"+chrome/browser/component_updater",
|
||||
"+chrome/browser/extensions/external_loader.h",
|
||||
"+chrome/browser/extensions/external_provider_impl.h",
|
||||
|
@ -4,9 +4,15 @@
|
||||
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_mode_idle_handler.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "ash/metrics/demo_session_metrics_recorder.h"
|
||||
#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "chrome/browser/profiles/profile_manager.h"
|
||||
#include "chromeos/ash/experiences/idle_detector/idle_detector.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
@ -52,8 +58,10 @@ void ResetPrefs() {
|
||||
|
||||
} // namespace
|
||||
|
||||
DemoModeIdleHandler::DemoModeIdleHandler(DemoModeWindowCloser* window_closer)
|
||||
: window_closer_(window_closer) {
|
||||
DemoModeIdleHandler::DemoModeIdleHandler(
|
||||
DemoModeWindowCloser* window_closer,
|
||||
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
|
||||
: window_closer_(window_closer), file_cleaner_(blocking_task_runner) {
|
||||
user_activity_observer_.Observe(ui::UserActivityDetector::Get());
|
||||
}
|
||||
|
||||
@ -75,9 +83,26 @@ void DemoModeIdleHandler::OnUserActivity(const ui::Event* event) {
|
||||
base::BindRepeating(&DemoModeIdleHandler::OnIdle,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
/*tick_clock=*/nullptr);
|
||||
idle_detector_->Start(kReLuanchDemoAppIdleDuration);
|
||||
|
||||
idle_detector_->Start(
|
||||
idle_time_out_for_test_.value_or(kReLuanchDemoAppIdleDuration));
|
||||
}
|
||||
|
||||
void DemoModeIdleHandler::AddObserver(Observer* observer) {
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
void DemoModeIdleHandler::RemoveObserver(Observer* observer) {
|
||||
observers_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
void DemoModeIdleHandler::SetIdleTimeoutForTest(
|
||||
std::optional<base::TimeDelta> timeout) {
|
||||
idle_time_out_for_test_ = std::move(timeout);
|
||||
}
|
||||
|
||||
// This function is invoked on the task runner of timer. Post task properly on
|
||||
// different thread.
|
||||
void DemoModeIdleHandler::OnIdle() {
|
||||
// Report shopper session dwell time metrics.
|
||||
DemoSessionMetricsRecorder::Get()->ReportShopperSessionDwellTime();
|
||||
@ -86,6 +111,11 @@ void DemoModeIdleHandler::OnIdle() {
|
||||
idle_detector_.reset();
|
||||
is_user_active_ = false;
|
||||
|
||||
if (features::IsDemoModeSignInFileCleanupEnabled()) {
|
||||
// The IO tasks will be executed from non-UI thread by `file_cleaner_`.
|
||||
CleanupLocalFiles();
|
||||
}
|
||||
|
||||
window_closer_->StartClosingApps();
|
||||
ResetPrefs();
|
||||
|
||||
@ -96,4 +126,27 @@ void DemoModeIdleHandler::OnIdle() {
|
||||
// TODO(crbug.com/382360715): Restore network if changed by user.
|
||||
}
|
||||
|
||||
void DemoModeIdleHandler::CleanupLocalFiles() {
|
||||
// TODO(crbug.com/396731796): Maybe only do clean up when there's a change
|
||||
// under "MyFiles". Unmount the mounted archives before the cleanup. Restore
|
||||
// the default download location if user changed it.
|
||||
|
||||
// Note this won't work for emulator since "MyFiles" is not mounted from user
|
||||
// data directory.
|
||||
file_cleaner_.Cleanup(
|
||||
base::BindOnce(&DemoModeIdleHandler::OnLocalFilesCleanupCompleted,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void DemoModeIdleHandler::OnLocalFilesCleanupCompleted(
|
||||
const std::optional<std::string>& error_message) {
|
||||
if (error_message) {
|
||||
LOG(ERROR) << "Cleanup local files on device idle failed: "
|
||||
<< error_message.value();
|
||||
return;
|
||||
}
|
||||
|
||||
observers_.Notify(&Observer::OnLocalFilesCleanupCompleted);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -9,8 +9,11 @@
|
||||
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_mode_window_closer.h"
|
||||
#include "chrome/browser/chromeos/extensions/login_screen/login/cleanup/files_cleanup_handler.h"
|
||||
#include "ui/base/user_activity/user_activity_detector.h"
|
||||
#include "ui/base/user_activity/user_activity_observer.h"
|
||||
|
||||
@ -23,7 +26,15 @@ class IdleDetector;
|
||||
// and wait for next user.
|
||||
class DemoModeIdleHandler : public ui::UserActivityObserver {
|
||||
public:
|
||||
explicit DemoModeIdleHandler(DemoModeWindowCloser* window_closer);
|
||||
class Observer : public base::CheckedObserver {
|
||||
public:
|
||||
// Called on local files is cleaned up complete.
|
||||
virtual void OnLocalFilesCleanupCompleted() = 0;
|
||||
};
|
||||
|
||||
DemoModeIdleHandler(
|
||||
DemoModeWindowCloser* window_closer,
|
||||
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
|
||||
DemoModeIdleHandler(const DemoModeIdleHandler&) = delete;
|
||||
DemoModeIdleHandler& operator=(const DemoModeIdleHandler&) = delete;
|
||||
~DemoModeIdleHandler() override;
|
||||
@ -31,13 +42,29 @@ class DemoModeIdleHandler : public ui::UserActivityObserver {
|
||||
// ui::UserActivityObserver:
|
||||
void OnUserActivity(const ui::Event* event) override;
|
||||
|
||||
// Adds an observer to the observer list.
|
||||
void AddObserver(Observer* observer);
|
||||
|
||||
// Removes an observer from the observer list.
|
||||
void RemoveObserver(Observer* observer);
|
||||
|
||||
void SetIdleTimeoutForTest(std::optional<base::TimeDelta> timeout);
|
||||
|
||||
private:
|
||||
// Called on idle timeout reaches. Could be invoked on non-UI thread when
|
||||
// using `base::TestMockTimeTaskRunner` for test.
|
||||
void OnIdle();
|
||||
|
||||
// Cleans up everything under "MyFiles" and reset "Downloads" folder to
|
||||
// empty.
|
||||
void CleanupLocalFiles();
|
||||
// Populates demo files after cleanup.
|
||||
void OnLocalFilesCleanupCompleted(
|
||||
const std::optional<std::string>& error_message);
|
||||
|
||||
// True when the device is not idle.
|
||||
bool is_user_active_ = false;
|
||||
|
||||
|
||||
// Detect idle when attract loop is not playing. If the attract loop is well
|
||||
// function and it is not playing, it indicates that a user is actively engage
|
||||
// with device.
|
||||
@ -46,9 +73,16 @@ class DemoModeIdleHandler : public ui::UserActivityObserver {
|
||||
// Not owned:
|
||||
raw_ptr<DemoModeWindowCloser> window_closer_;
|
||||
|
||||
// Cleaner for `MyFiles` directory:
|
||||
chromeos::FilesCleanupHandler file_cleaner_;
|
||||
|
||||
std::optional<base::TimeDelta> idle_time_out_for_test_;
|
||||
|
||||
base::ScopedObservation<ui::UserActivityDetector, ui::UserActivityObserver>
|
||||
user_activity_observer_{this};
|
||||
|
||||
base::ObserverList<Observer> observers_;
|
||||
|
||||
base::WeakPtrFactory<DemoModeIdleHandler> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "ash/wallpaper/test_wallpaper_controller_client.h"
|
||||
#include "ash/wallpaper/wallpaper_controller_impl.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/time/time.h"
|
||||
@ -54,8 +56,9 @@ class DemoModeIdleHandlerTest : public ChromeAshTestBase {
|
||||
|
||||
// OK to unretained `this` since the life cycle of `demo_mode_idle_handler_`
|
||||
// is the same as the tests.
|
||||
demo_mode_idle_handler_ =
|
||||
std::make_unique<DemoModeIdleHandler>(window_closer_.get());
|
||||
demo_mode_idle_handler_ = std::make_unique<DemoModeIdleHandler>(
|
||||
window_closer_.get(),
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}));
|
||||
}
|
||||
~DemoModeIdleHandlerTest() override = default;
|
||||
|
||||
|
@ -125,8 +125,6 @@ std::vector<std::string> GetIgnorePinPolicyApps() {
|
||||
}
|
||||
|
||||
// Copies photos into the Downloads directory.
|
||||
// TODO(michaelpg): Test this behavior (requires overriding the Downloads
|
||||
// directory).
|
||||
void InstallDemoMedia(const base::FilePath& offline_resources_path,
|
||||
const base::FilePath& dest_path) {
|
||||
if (offline_resources_path.empty()) {
|
||||
@ -135,8 +133,10 @@ void InstallDemoMedia(const base::FilePath& offline_resources_path,
|
||||
}
|
||||
|
||||
base::FilePath src_path = offline_resources_path.Append(kPhotosPath);
|
||||
if (!base::CopyDirectory(src_path, dest_path, false /* recursive */))
|
||||
|
||||
if (!base::CopyDirectory(src_path, dest_path, false /* recursive */)) {
|
||||
LOG(ERROR) << "Failed to install demo mode media.";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetSwitchOrDefault(std::string_view switch_string,
|
||||
@ -536,7 +536,10 @@ void DemoSession::ActiveUserChanged(user_manager::User* active_user) {
|
||||
DemoSession::DemoSession()
|
||||
: ignore_pin_policy_offline_apps_(GetIgnorePinPolicyApps()),
|
||||
remove_splash_screen_fallback_timer_(
|
||||
std::make_unique<base::OneShotTimer>()) {
|
||||
std::make_unique<base::OneShotTimer>()),
|
||||
blocking_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
|
||||
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
|
||||
// SessionManager may be unset in unit tests.
|
||||
if (session_manager::SessionManager::Get()) {
|
||||
session_manager_observation_.Observe(
|
||||
@ -547,6 +550,9 @@ DemoSession::DemoSession()
|
||||
}
|
||||
|
||||
DemoSession::~DemoSession() {
|
||||
// Reset observation before destroying `idle_handler_`.
|
||||
idle_handler_observation_.Reset();
|
||||
|
||||
user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
|
||||
}
|
||||
|
||||
@ -579,10 +585,10 @@ void DemoSession::InstallDemoResources() {
|
||||
DCHECK(profile);
|
||||
const base::FilePath downloads =
|
||||
file_manager::util::GetDownloadsFolderForProfile(profile);
|
||||
base::ThreadPool::PostTask(
|
||||
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
|
||||
base::BindOnce(&InstallDemoMedia, components_->resources_component_path(),
|
||||
downloads));
|
||||
auto install_media = base::BindOnce(
|
||||
&InstallDemoMedia, components_->resources_component_path(), downloads);
|
||||
|
||||
blocking_task_runner_->PostTask(FROM_HERE, std::move(install_media));
|
||||
}
|
||||
|
||||
void DemoSession::SetKeyboardBrightnessToOneHundredPercentFromCurrentLevel(
|
||||
@ -721,6 +727,19 @@ base::FilePath DemoSession::GetDemoAppComponentPath() {
|
||||
components_->default_app_component_path().value()));
|
||||
}
|
||||
|
||||
DemoModeIdleHandler* DemoSession::GetIdleHandlerForTest() const {
|
||||
return idle_handler_.get();
|
||||
}
|
||||
|
||||
scoped_refptr<base::SequencedTaskRunner>
|
||||
DemoSession::GetBlockingTaskRunnerForTest() {
|
||||
return blocking_task_runner_;
|
||||
}
|
||||
|
||||
void DemoSession::OnLocalFilesCleanupCompleted() {
|
||||
InstallDemoResources();
|
||||
}
|
||||
|
||||
void DemoSession::OnDemoAppComponentLoaded() {
|
||||
const auto& app_component_version = components_->app_component_version();
|
||||
SYSLOG(INFO) << "Demo mode app component version: "
|
||||
@ -740,7 +759,9 @@ void DemoSession::OnDemoAppComponentLoaded() {
|
||||
|
||||
if (demo_mode::IsDemoAccountSignInEnabled()) {
|
||||
CHECK(window_closer_);
|
||||
idle_handler_ = std::make_unique<DemoModeIdleHandler>(window_closer_.get());
|
||||
idle_handler_ = std::make_unique<DemoModeIdleHandler>(
|
||||
window_closer_.get(), blocking_task_runner_);
|
||||
idle_handler_observation_.Observe(idle_handler_.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,8 @@ class DemoComponents;
|
||||
// started and the state of demo mode resources.
|
||||
class DemoSession : public session_manager::SessionManagerObserver,
|
||||
public user_manager::UserManager::UserSessionStateObserver,
|
||||
public chromeos::PowerManagerClient::Observer {
|
||||
public chromeos::PowerManagerClient::Observer,
|
||||
public DemoModeIdleHandler::Observer {
|
||||
public:
|
||||
// Type of demo mode configuration.
|
||||
// Warning: DemoModeConfig is stored in local state. Existing entries should
|
||||
@ -183,10 +184,18 @@ class DemoSession : public session_manager::SessionManagerObserver,
|
||||
// if the splash screen is already removed or never shown.
|
||||
void RemoveSplashScreen();
|
||||
|
||||
DemoModeIdleHandler* GetIdleHandlerForTest() const;
|
||||
|
||||
// Gets blocking task runner for test to ensure blocking tasks get flushed.
|
||||
scoped_refptr<base::SequencedTaskRunner> GetBlockingTaskRunnerForTest();
|
||||
|
||||
private:
|
||||
DemoSession();
|
||||
~DemoSession() override;
|
||||
|
||||
// DemoModeIdleHandler::Observer:
|
||||
void OnLocalFilesCleanupCompleted() override;
|
||||
|
||||
void OnDemoAppComponentLoaded();
|
||||
|
||||
// Get country code and full name in current language pair sorted by their
|
||||
@ -195,7 +204,7 @@ class DemoSession : public session_manager::SessionManagerObserver,
|
||||
GetSortedCountryCodeAndNamePairList();
|
||||
|
||||
// Installs resources for Demo Mode from the offline demo mode resources, such
|
||||
// as apps and media.
|
||||
// as photos and other media.
|
||||
void InstallDemoResources();
|
||||
|
||||
// Find image path then show the splash screen.
|
||||
@ -229,6 +238,9 @@ class DemoSession : public session_manager::SessionManagerObserver,
|
||||
session_manager::SessionManagerObserver>
|
||||
session_manager_observation_{this};
|
||||
|
||||
base::ScopedObservation<DemoModeIdleHandler, DemoModeIdleHandler::Observer>
|
||||
idle_handler_observation_{this};
|
||||
|
||||
// The fallback timer that ensures the splash screen is removed in case the
|
||||
// screensaver app takes an extra long time to be shown.
|
||||
std::unique_ptr<base::OneShotTimer> remove_splash_screen_fallback_timer_;
|
||||
@ -245,6 +257,10 @@ class DemoSession : public session_manager::SessionManagerObserver,
|
||||
// sessions. Constructed while demo app is available.
|
||||
std::unique_ptr<DemoModeIdleHandler> idle_handler_;
|
||||
|
||||
// Task runner for file cleanup and re-install demo mode resource at the end
|
||||
// of shopper sessions.
|
||||
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
|
||||
|
||||
base::WeakPtrFactory<DemoSession> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,11 @@
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/run_until.h"
|
||||
#include "chrome/browser/ash/file_manager/path_util.h"
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_components.h"
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h"
|
||||
#include "chrome/browser/ash/login/login_manager_test.h"
|
||||
#include "chrome/browser/ash/login/test/device_state_mixin.h"
|
||||
@ -28,6 +33,7 @@
|
||||
#include "chrome/browser/ui/browser_list_observer.h"
|
||||
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
|
||||
#include "chromeos/constants/chromeos_features.h"
|
||||
#include "chromeos/dbus/power/fake_power_manager_client.h"
|
||||
#include "components/component_updater/ash/fake_component_manager_ash.h"
|
||||
@ -37,6 +43,7 @@
|
||||
#include "components/variations/active_field_trials.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/test_utils.h"
|
||||
#include "net/base/url_util.h"
|
||||
|
||||
namespace ash {
|
||||
@ -48,7 +55,12 @@ inline constexpr char kDemoModeAppUrl[] =
|
||||
"chrome-untrusted://demo-mode-app/index.html";
|
||||
|
||||
inline constexpr char kGrowthCampaignsComponentName[] = "growth-campaigns";
|
||||
inline constexpr char kDemoResourceComponentName[] = "demo-mode-resources";
|
||||
inline constexpr char kCampaignsFileName[] = "campaigns.json";
|
||||
inline constexpr char kDemoMediaDirName[] = "media/photos";
|
||||
inline constexpr char kDemoPhotoName[] = "photo.jpg";
|
||||
|
||||
// inline constexpr base::TimeDelta kDemoIdleTimeout = base::Seconds(90);
|
||||
|
||||
void SetDemoConfigPref(DemoSession::DemoModeConfig demo_config) {
|
||||
PrefService* prefs = g_browser_process->local_state();
|
||||
@ -69,6 +81,8 @@ void CheckNoDemoMode() {
|
||||
EXPECT_EQ(DemoSession::DemoModeConfig::kNone, DemoSession::GetDemoConfig());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Tests locking device to policy::DEVICE_MODE_DEMO mode. It is an equivalent to
|
||||
// going through online demo mode setup or using offline setup.
|
||||
class DemoSessionDemoDeviceModeTest : public OobeBaseTest {
|
||||
@ -226,17 +240,29 @@ class DemoLoginTestMainExtraParts : public ChromeBrowserMainExtraParts {
|
||||
.AppendASCII(kGrowthCampaignsComponentName);
|
||||
}
|
||||
|
||||
base::FilePath GetDemoResourceComponentPath() {
|
||||
return components_temp_dir_.GetPath()
|
||||
.AppendASCII("cros-components")
|
||||
.AppendASCII(kDemoResourceComponentName);
|
||||
}
|
||||
|
||||
void PostEarlyInitialization() override {
|
||||
auto component_manager_ash =
|
||||
base::MakeRefCounted<component_updater::FakeComponentManagerAsh>();
|
||||
component_manager_ash->set_supported_components(
|
||||
{"demo-mode-app", kGrowthCampaignsComponentName});
|
||||
{"demo-mode-app", kGrowthCampaignsComponentName,
|
||||
kDemoResourceComponentName});
|
||||
component_manager_ash->ResetComponentState(
|
||||
"demo-mode-app",
|
||||
component_updater::FakeComponentManagerAsh::ComponentInfo(
|
||||
component_updater::ComponentManagerAsh::Error::NONE,
|
||||
base::FilePath("/dev/null"),
|
||||
base::FilePath("/run/imageloader/demo-mode-app")));
|
||||
component_manager_ash->ResetComponentState(
|
||||
"demo-mode-resources",
|
||||
component_updater::FakeComponentManagerAsh::ComponentInfo(
|
||||
component_updater::ComponentManagerAsh::Error::NONE,
|
||||
base::FilePath("/dev/null"), GetDemoResourceComponentPath()));
|
||||
component_manager_ash->ResetComponentState(
|
||||
"growth-campaigns",
|
||||
component_updater::FakeComponentManagerAsh::ComponentInfo(
|
||||
@ -281,6 +307,7 @@ class DemoSessionLoginTest : public LoginManagerTest,
|
||||
content::BrowserMainParts* browser_main_parts) override {
|
||||
auto extra_parts = std::make_unique<DemoLoginTestMainExtraParts>();
|
||||
growth_campaigns_mounted_path_ = extra_parts->GetGrowthCampaignsPath();
|
||||
demo_resource_mounted_path_ = extra_parts->GetDemoResourceComponentPath();
|
||||
static_cast<ChromeBrowserMainParts*>(browser_main_parts)
|
||||
->AddParts(std::move(extra_parts));
|
||||
LoginManagerTest::CreatedBrowserMainParts(browser_main_parts);
|
||||
@ -351,6 +378,10 @@ class DemoSessionLoginTest : public LoginManagerTest,
|
||||
return growth_campaigns_mounted_path_;
|
||||
}
|
||||
|
||||
base::FilePath& demo_resource_mounted_path() {
|
||||
return demo_resource_mounted_path_;
|
||||
}
|
||||
|
||||
LoginManagerMixin login_manager_mixin_{&mixin_host_};
|
||||
DeviceStateMixin device_state_mixin_{
|
||||
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE};
|
||||
@ -358,6 +389,7 @@ class DemoSessionLoginTest : public LoginManagerTest,
|
||||
base::OnceClosure on_browser_added_callback_;
|
||||
static constexpr double kInitialBrightness = 20.0;
|
||||
base::FilePath growth_campaigns_mounted_path_;
|
||||
base::FilePath demo_resource_mounted_path_;
|
||||
base::WeakPtrFactory<DemoSessionLoginTest> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
@ -586,5 +618,93 @@ IN_PROC_BROWSER_TEST_F(DemoSessionLoginWithGrowthCampaignTest,
|
||||
variations::IsInSyntheticTrialGroup("CrOSGrowthStudy", "CampaignId3"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
class DemoSessionLoginIdleHandlerTest : public DemoSessionLoginTest {
|
||||
public:
|
||||
DemoSessionLoginIdleHandlerTest() {
|
||||
scoped_feature_list_.InitWithFeatures(
|
||||
{features::kDemoModeSignInFileCleanup}, {});
|
||||
}
|
||||
|
||||
void SetUpOnMainThread() override {
|
||||
demo_mode::SetForceEnableDemoAccountSignIn(true);
|
||||
DemoSessionLoginTest::SetUpOnMainThread();
|
||||
CreateTestMediaFile();
|
||||
}
|
||||
|
||||
void CreateTestMediaFile() {
|
||||
const base::FilePath media_dir =
|
||||
demo_resource_mounted_path_.AppendASCII(kDemoMediaDirName);
|
||||
CHECK(base::CreateDirectory(media_dir));
|
||||
|
||||
const base::FilePath photo(media_dir.Append(kDemoPhotoName));
|
||||
CHECK(base::WriteFile(photo, "random text"));
|
||||
}
|
||||
|
||||
void FlushIOTasks() {
|
||||
base::RunLoop run_loop;
|
||||
DemoSession::Get()->GetBlockingTaskRunnerForTest()->PostTask(
|
||||
FROM_HERE, run_loop.QuitClosure());
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(DemoSessionLoginIdleHandlerTest, CleanUpLocalFiles) {
|
||||
// Setup initial demo mode resources and start a user session:
|
||||
OpenBrowserAndInstallSystemAppForActiveProfile();
|
||||
|
||||
// Ensure media of resource components gets installed.
|
||||
FlushIOTasks();
|
||||
|
||||
// Verify the photo was copied to download folder.
|
||||
auto* profile = ProfileManager::GetActiveUserProfile();
|
||||
base::FilePath downloads_path =
|
||||
file_manager::util::GetDownloadsFolderForProfile(profile);
|
||||
base::FilePath photo_file = downloads_path.AppendASCII(kDemoPhotoName);
|
||||
{
|
||||
base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
EXPECT_TRUE(base::PathExists(photo_file));
|
||||
}
|
||||
|
||||
// Shorten the timeout for testing.
|
||||
base::TimeDelta idle_timeout = base::Seconds(2);
|
||||
DemoSession::Get()->GetIdleHandlerForTest()->SetIdleTimeoutForTest(
|
||||
idle_timeout);
|
||||
|
||||
// Mock user activity:
|
||||
ui::UserActivityDetector::Get()->HandleExternalUserActivity();
|
||||
base::FilePath user_created_dir_path;
|
||||
{
|
||||
base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
// Mock user creates a new folder under "MyFiles" and deletes the photo
|
||||
// files.
|
||||
base::ScopedTempDir user_created_dir;
|
||||
base::FilePath my_files_path = profile->GetPath().AppendASCII("MyFiles");
|
||||
EXPECT_TRUE(user_created_dir.CreateUniqueTempDirUnderPath(my_files_path));
|
||||
EXPECT_TRUE(base::DirectoryExists(user_created_dir.GetPath()));
|
||||
EXPECT_TRUE(base::DeleteFile(photo_file));
|
||||
user_created_dir_path = user_created_dir.GetPath();
|
||||
}
|
||||
|
||||
// Wait idle timeout + 1s buffer for invoking the file clean up task.
|
||||
base::RunLoop run_loop{base::RunLoop::Type::kNestableTasksAllowed};
|
||||
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
|
||||
FROM_HERE, run_loop.QuitClosure(), idle_timeout + base::Seconds(1));
|
||||
run_loop.Run();
|
||||
|
||||
// Wait file clean up tasks to be finished.
|
||||
FlushIOTasks();
|
||||
{
|
||||
base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
// Verify `user_created_dir` was deleted and photo was reset.
|
||||
EXPECT_TRUE(base::test::RunUntil([&user_created_dir_path]() {
|
||||
return !base::DirectoryExists(user_created_dir_path);
|
||||
}));
|
||||
EXPECT_TRUE(base::test::RunUntil(
|
||||
[&photo_file]() { return base::PathExists(photo_file); }));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -65,11 +65,14 @@ bool EnsureDirectoryIsEmpty(const base::FilePath& directory_path,
|
||||
|
||||
} // namespace
|
||||
|
||||
FilesCleanupHandler::FilesCleanupHandler() {
|
||||
task_runner_ = base::ThreadPool::CreateTaskRunner(
|
||||
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
|
||||
}
|
||||
FilesCleanupHandler::FilesCleanupHandler()
|
||||
: FilesCleanupHandler(base::ThreadPool::CreateTaskRunner(
|
||||
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
|
||||
|
||||
FilesCleanupHandler::FilesCleanupHandler(
|
||||
scoped_refptr<base::TaskRunner> task_runner)
|
||||
: task_runner_(task_runner) {}
|
||||
|
||||
FilesCleanupHandler::~FilesCleanupHandler() = default;
|
||||
|
||||
|
@ -19,6 +19,7 @@ namespace chromeos {
|
||||
class FilesCleanupHandler : public CleanupHandler {
|
||||
public:
|
||||
FilesCleanupHandler();
|
||||
explicit FilesCleanupHandler(scoped_refptr<base::TaskRunner> task_runner);
|
||||
~FilesCleanupHandler() override;
|
||||
|
||||
// CleanupHandler:
|
||||
@ -34,4 +35,4 @@ class FilesCleanupHandler : public CleanupHandler {
|
||||
|
||||
} // namespace chromeos
|
||||
|
||||
#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_CLEANUP_FILES_CLEANUP_HANDLER_H_
|
||||
#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_LOGIN_SCREEN_LOGIN_CLEANUP_FILES_CLEANUP_HANDLER_H_
|
||||
|
Reference in New Issue
Block a user