Commit ffc6bf5a authored by Yusuf Sengul's avatar Yusuf Sengul Committed by Commit Bot

Add periodic execution support to gcpw extension

Bug: 1114381
Change-Id: Ia5b0ae4e408ae770cbed0086dc6ff269793ea876
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2343955Reviewed-by: default avatarRakesh Soma <rakeshsoma@google.com>
Commit-Queue: Yusuf Sengul <yusufsn@google.com>
Cr-Commit-Position: refs/heads/master@{#808988}
parent 7abc0598
...@@ -46,6 +46,11 @@ source_set("extension_lib") { ...@@ -46,6 +46,11 @@ source_set("extension_lib") {
sources = [ sources = [
"service.cc", "service.cc",
"service.h", "service.h",
"task.h",
"task_manager.cc",
"task_manager.h",
"user_device_context.cc",
"user_device_context.h",
] ]
deps = [ deps = [
":common", ":common",
......
...@@ -51,9 +51,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, ...@@ -51,9 +51,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
// Set the event logging source and category for GCPW Extension. // Set the event logging source and category for GCPW Extension.
logging::SetEventSource("GCPW", GCPW_EXTENSION_CATEGORY, MSG_LOG_MESSAGE); logging::SetEventSource("GCPW", GCPW_EXTENSION_CATEGORY, MSG_LOG_MESSAGE);
// This initializes and starts ThreadPoolInstance with default params.
base::ThreadPoolInstance::CreateAndStartWithDefaultParams("gcpw_extension");
credential_provider::extension::Service::Get()->Run(); credential_provider::extension::Service::Get()->Run();
return 0; return 0;
......
...@@ -13,5 +13,7 @@ const wchar_t kGCPWExtensionServiceDescription[] = L"GCPW extension service"; ...@@ -13,5 +13,7 @@ const wchar_t kGCPWExtensionServiceDescription[] = L"GCPW extension service";
const wchar_t kEnableGCPWExtension[] = L"enable_gcpw_extension"; const wchar_t kEnableGCPWExtension[] = L"enable_gcpw_extension";
const wchar_t kLastPeriodicSyncTimeRegKey[] = L"last_periodic_sync";
} // namespace extension } // namespace extension
} // namespace credential_provider } // namespace credential_provider
...@@ -17,6 +17,9 @@ extern const wchar_t kGCPWExtensionServiceDescription[]; ...@@ -17,6 +17,9 @@ extern const wchar_t kGCPWExtensionServiceDescription[];
// Registry which controls whether to install GCPW Extension. // Registry which controls whether to install GCPW Extension.
extern const wchar_t kEnableGCPWExtension[]; extern const wchar_t kEnableGCPWExtension[];
// Registry which keeps track of last time periodic sync was performed.
extern const wchar_t kLastPeriodicSyncTimeRegKey[];
} // namespace extension } // namespace extension
} // namespace credential_provider } // namespace credential_provider
......
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
#include "chrome/credential_provider/extension/service.h" #include "chrome/credential_provider/extension/service.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
#include "chrome/credential_provider/extension/os_service_manager.h" #include "chrome/credential_provider/extension/os_service_manager.h"
#include "chrome/credential_provider/extension/task_manager.h"
#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/logging.h"
namespace credential_provider { namespace credential_provider {
...@@ -30,9 +33,7 @@ DWORD Service::Run() { ...@@ -30,9 +33,7 @@ DWORD Service::Run() {
Service::Service() Service::Service()
: run_routine_(&Service::RunAsService), : run_routine_(&Service::RunAsService),
service_status_(), service_status_(),
service_status_handle_(nullptr), service_status_handle_(nullptr) {
stop_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
service_status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
service_status_.dwCurrentState = SERVICE_STOPPED; service_status_.dwCurrentState = SERVICE_STOPPED;
service_status_.dwControlsAccepted = service_status_.dwControlsAccepted =
...@@ -42,7 +43,7 @@ Service::Service() ...@@ -42,7 +43,7 @@ Service::Service()
Service::~Service() {} Service::~Service() {}
DWORD Service::RunAsService() { DWORD Service::RunAsService() {
LOGFN(INFO); LOGFN(VERBOSE);
DWORD error_code = DWORD error_code =
extension::OSServiceManager::Get()->StartServiceCtrlDispatcher( extension::OSServiceManager::Get()->StartServiceCtrlDispatcher(
...@@ -58,6 +59,14 @@ DWORD Service::RunAsService() { ...@@ -58,6 +59,14 @@ DWORD Service::RunAsService() {
} }
void Service::StartMain() { void Service::StartMain() {
base::SingleThreadTaskExecutor main_task_executor;
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner =
main_task_executor.task_runner();
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
DWORD error_code = extension::OSServiceManager::Get()->RegisterCtrlHandler( DWORD error_code = extension::OSServiceManager::Get()->RegisterCtrlHandler(
&Service::ServiceControlHandler, &service_status_handle_); &Service::ServiceControlHandler, &service_status_handle_);
if (error_code != ERROR_SUCCESS) { if (error_code != ERROR_SUCCESS) {
...@@ -76,7 +85,11 @@ void Service::StartMain() { ...@@ -76,7 +85,11 @@ void Service::StartMain() {
return; return;
} }
stop_event_.Wait(); TaskManager::Get()->RunTasks(main_task_runner);
run_loop.Run();
TaskManager::Get()->Quit();
service_status_.dwCurrentState = SERVICE_STOPPED; service_status_.dwCurrentState = SERVICE_STOPPED;
service_status_.dwControlsAccepted = 0; service_status_.dwControlsAccepted = 0;
...@@ -91,7 +104,7 @@ void Service::StartMain() { ...@@ -91,7 +104,7 @@ void Service::StartMain() {
// static // static
VOID WINAPI Service::ServiceMain(DWORD argc /*unused*/, VOID WINAPI Service::ServiceMain(DWORD argc /*unused*/,
WCHAR* argv[] /*unused*/) { WCHAR* argv[] /*unused*/) {
LOGFN(INFO); LOGFN(VERBOSE);
Service* self = Service::Get(); Service* self = Service::Get();
...@@ -101,7 +114,7 @@ VOID WINAPI Service::ServiceMain(DWORD argc /*unused*/, ...@@ -101,7 +114,7 @@ VOID WINAPI Service::ServiceMain(DWORD argc /*unused*/,
// static // static
VOID WINAPI Service::ServiceControlHandler(DWORD control) { VOID WINAPI Service::ServiceControlHandler(DWORD control) {
LOGFN(INFO); LOGFN(VERBOSE);
Service* self = Service::Get(); Service* self = Service::Get();
switch (control) { switch (control) {
...@@ -111,7 +124,7 @@ VOID WINAPI Service::ServiceControlHandler(DWORD control) { ...@@ -111,7 +124,7 @@ VOID WINAPI Service::ServiceControlHandler(DWORD control) {
extension::OSServiceManager::Get()->SetServiceStatus( extension::OSServiceManager::Get()->SetServiceStatus(
self->service_status_handle_, self->service_status_); self->service_status_handle_, self->service_status_);
self->stop_event_.Signal(); std::move(self->quit_closure_).Run();
break; break;
default: default:
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
#include <windows.h> #include <windows.h>
#include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/synchronization/waitable_event.h"
namespace credential_provider { namespace credential_provider {
namespace extension { namespace extension {
...@@ -59,8 +59,8 @@ class Service { ...@@ -59,8 +59,8 @@ class Service {
// The service status handle which is used with SetServiceStatus API. // The service status handle which is used with SetServiceStatus API.
SERVICE_STATUS_HANDLE service_status_handle_; SERVICE_STATUS_HANDLE service_status_handle_;
// Primitive that controls when to finish running service main. // Callback to end running periodic tasks.
base::WaitableEvent stop_event_; base::OnceClosure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(Service); DISALLOW_COPY_AND_ASSIGN(Service);
}; };
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_H_
#define CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_H_
#include <windows.h>
#include "chrome/credential_provider/extension/user_device_context.h"
namespace credential_provider {
namespace extension {
// An interface that can be implemented by individual GCPW tasks to be executed
// during periodic polling by GCPW extension service. Methods are called in the
// order they are defined. So, initially task runner gets the configuration of
// the task. Then it sets the context task will be running in. Lastly task is
// executed.
class Task {
public:
virtual ~Task();
// ESA calls this function to get the execution config for the task. This
// contains information about whether task is device level or
// user level, failure action and etc.
virtual Config GetConfig() = 0;
// Based on the config of the task, UserDeviceContext contains identifiers for
// the user and device. So the task can identify the users it is running on
// behalf of.
virtual HRESULT SetContext(const std::vector<UserDeviceContext>& c) = 0;
// ESA calls execute function to perform the actual task.
virtual HRESULT Execute() = 0;
};
} // namespace extension
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/credential_provider/extension/task_manager.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/timer/timer.h"
#include "chrome/credential_provider/extension/extension_strings.h"
#include "chrome/credential_provider/extension/task.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
namespace credential_provider {
namespace extension {
namespace {
// Specifies the period of executing tasks.
constexpr auto kPollingInterval = base::TimeDelta::FromHours(3);
} // namespace
// static
TaskManager** TaskManager::GetInstanceStorage() {
static TaskManager* instance = new TaskManager();
return &instance;
}
// static
TaskManager* TaskManager::Get() {
return *GetInstanceStorage();
}
TaskManager::TaskManager() {}
TaskManager::~TaskManager() {}
void TaskManager::ScheduleTasks() {
timer_.Start(FROM_HERE, kPollingInterval, this,
&TaskManager::RunTasksInternal);
}
void TaskManager::RunTasksInternal() {
LOGFN(VERBOSE) << base::Time::Now();
// TODO(yusufsn): Perform periodic tasks for each GCPW user on the device.
}
void TaskManager::UpdateLastRunTimestamp() {
const base::Time sync_time = base::Time::Now();
const base::string16 sync_time_millis = base::NumberToString16(
sync_time.ToDeltaSinceWindowsEpoch().InMilliseconds());
SetGlobalFlag(kLastPeriodicSyncTimeRegKey, sync_time_millis);
}
void TaskManager::RunTasks(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
LOGFN(VERBOSE);
// Calculate the next run so that periodic polling happens within
// proper time intervals. When the tasks are scheduled, we don't want to
// immediately start executing periodic tasks to allow some warm-up.
base::TimeDelta next_run = base::TimeDelta::FromSeconds(10);
const base::TimeDelta time_since_last_run =
GetTimeDeltaSinceLastPeriodicSync();
if (time_since_last_run < kPollingInterval)
next_run = kPollingInterval - time_since_last_run;
// Post an individual task that runs after completing a polling period.
task_runner->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TaskManager::RunTasksInternal, base::Unretained(this)),
next_run);
// Schedule a repeating task to run after running the task above.
task_runner->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TaskManager::ScheduleTasks, base::Unretained(this)),
next_run);
}
base::TimeDelta TaskManager::GetTimeDeltaSinceLastPeriodicSync() {
wchar_t last_sync_millis[512];
ULONG last_sync_size = base::size(last_sync_millis);
HRESULT hr = GetGlobalFlag(kLastPeriodicSyncTimeRegKey, last_sync_millis,
&last_sync_size);
if (FAILED(hr)) {
// The periodic sync has never happened before.
return base::TimeDelta::Max();
}
int64_t last_sync_millis_int64;
base::StringToInt64(last_sync_millis, &last_sync_millis_int64);
const auto last_sync = base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMilliseconds(last_sync_millis_int64));
return base::Time::Now() - last_sync;
}
void TaskManager::RegisterTask(const std::string& task_name,
TaskCreator task_creator) {
LOGFN(VERBOSE);
task_list_.emplace(task_name, std::move(task_creator));
}
void TaskManager::Quit() {
LOGFN(VERBOSE);
timer_.AbandonAndStop();
}
} // namespace extension
} // namespace credential_provider
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_MANAGER_H_
#define CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_MANAGER_H_
#include "chrome/credential_provider/extension/task.h"
#include <map>
#include <string>
#include "base/callback.h"
#include "base/single_thread_task_runner.h"
#include "base/timer/timer.h"
namespace credential_provider {
namespace extension {
using TaskCreator = base::OnceCallback<HRESULT(Task* task)>;
class TaskManager {
public:
// Used to retrieve singleton instance of the TaskManager.
static TaskManager* Get();
TaskManager();
virtual ~TaskManager();
// Returns the storage used for the instance pointer.
static TaskManager** GetInstanceStorage();
// This function schedules periodic tasks using PostTask interface. It
// schedules the tasks on the provided |task_runner|.
virtual void RunTasks(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Each implementation needs to register the task with the task manager so
// that they can be executed at runtime.
virtual void RegisterTask(const std::string& task_name,
TaskCreator task_creator);
// Can be called to end the periodically running tasks.
virtual void Quit();
protected:
// Update the registry with the last time the periodic tasks are executed.
virtual void UpdateLastRunTimestamp();
private:
// Actual method which goes through registered tasks and runs them.
virtual void RunTasksInternal();
// Schedules a RepeatingTimer with the period specified in TaskManagerConfig.
virtual void ScheduleTasks();
// Returns the elapsed time delta since the last time the periodic sync were
// successfully performed.
base::TimeDelta GetTimeDeltaSinceLastPeriodicSync();
// List of tasks registered to be executed at every periodic run.
std::map<std::string, TaskCreator> task_list_;
// The timer that controls posting task to be executed every time the period
// elapses.
base::RepeatingTimer timer_;
};
} // namespace extension
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_EXTENSION_TASK_MANAGER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <windows.h>
#include "base/run_loop.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread.h"
#include "chrome/credential_provider/extension/extension_strings.h"
#include "chrome/credential_provider/extension/task_manager.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/test/gcp_fakes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace credential_provider {
namespace testing {
class TaskManagerTest : public ::testing::Test {
public:
TaskManagerTest() {}
void RunTasks() {
fake_task_manager_.RunTasks(task_environment_.GetMainThreadTaskRunner());
}
void SetUp() override {
registry_override.OverrideRegistry(HKEY_LOCAL_MACHINE);
}
void TearDown() override { fake_task_manager_.Quit(); }
FakeTaskManager* fake_task_manager() { return &fake_task_manager_; }
base::test::SingleThreadTaskEnvironment* task_environment() {
return &task_environment_;
}
private:
FakeTaskManager fake_task_manager_;
registry_util::RegistryOverrideManager registry_override;
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
};
TEST_F(TaskManagerTest, PeriodicExecution) {
ASSERT_EQ(
GetGlobalFlagOrDefault(
credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""),
L"");
RunTasks();
task_environment()->FastForwardBy(base::TimeDelta::FromHours(5));
ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(), 2);
ASSERT_NE(
GetGlobalFlagOrDefault(
credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""),
L"");
task_environment()->FastForwardBy(base::TimeDelta::FromHours(2));
ASSERT_EQ(fake_task_manager()->NumOfTimesExecuted(), 3);
}
} // namespace testing
} // namespace credential_provider
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/credential_provider/extension/user_device_context.h"
namespace credential_provider {
namespace extension {
UserDeviceContext::UserDeviceContext(base::string16 serial_number,
base::string16 machine_guid,
base::string16 gaia_profile_id,
base::string16 dm_token)
: serial_number_(serial_number),
machine_guid_(machine_guid),
gaia_profile_id_(gaia_profile_id),
dm_token_(dm_token) {}
UserDeviceContext::~UserDeviceContext() {}
} // namespace extension
} // namespace credential_provider
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_CREDENTIAL_PROVIDER_EXTENSION_USER_DEVICE_CONTEXT_H_
#define CHROME_CREDENTIAL_PROVIDER_EXTENSION_USER_DEVICE_CONTEXT_H_
#include <string>
#include "base/strings/string16.h"
namespace credential_provider {
namespace extension {
// The configuration the task needs to run on. A way to tell task manager on how
// to run the task.
struct Config {};
// The user, device and authentication details for task to be able to perform
// its action.
struct UserDeviceContext {
UserDeviceContext(base::string16 serial_number,
base::string16 machine_guid,
base::string16 gaia_profile_id,
base::string16 dm_token);
~UserDeviceContext();
base::string16 serial_number_;
base::string16 machine_guid_;
base::string16 gaia_profile_id_;
// The dm_token is unique to device. It is uploaded into user device details
// as part of GCPW login. The agent sends it along with identifiers to
// authenticate the user.
base::string16 dm_token_;
};
} // namespace extension
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_EXTENSION_USER_DEVICE_CONTEXT_H_
...@@ -279,6 +279,10 @@ HRESULT SetGlobalFlag(const base::string16& name, DWORD value) { ...@@ -279,6 +279,10 @@ HRESULT SetGlobalFlag(const base::string16& name, DWORD value) {
return SetMachineRegDWORD(kGcpRootKeyName, name, value); return SetMachineRegDWORD(kGcpRootKeyName, name, value);
} }
HRESULT SetGlobalFlag(const base::string16& name, const base::string16& value) {
return SetMachineRegString(kGcpRootKeyName, name, value);
}
HRESULT SetGlobalFlagForTesting(const base::string16& name, HRESULT SetGlobalFlagForTesting(const base::string16& name,
const base::string16& value) { const base::string16& value) {
return SetMachineRegString(kGcpRootKeyName, name, value); return SetMachineRegString(kGcpRootKeyName, name, value);
......
...@@ -59,6 +59,9 @@ DWORD GetGlobalFlagOrDefault(const base::string16& reg_key, ...@@ -59,6 +59,9 @@ DWORD GetGlobalFlagOrDefault(const base::string16& reg_key,
// Sets global DWORD flag. // Sets global DWORD flag.
HRESULT SetGlobalFlag(const base::string16& name, DWORD value); HRESULT SetGlobalFlag(const base::string16& name, DWORD value);
// Sets global base::string16 flag.
HRESULT SetGlobalFlag(const base::string16& name, const base::string16& value);
// Sets global flag. Used for testing purposes only. // Sets global flag. Used for testing purposes only.
HRESULT SetGlobalFlagForTesting(const base::string16& name, HRESULT SetGlobalFlagForTesting(const base::string16& name,
const base::string16& value); const base::string16& value);
......
...@@ -8,6 +8,7 @@ import("//testing/test.gni") ...@@ -8,6 +8,7 @@ import("//testing/test.gni")
test("gcp_unittests") { test("gcp_unittests") {
sources = [ sources = [
"../extension/service_unittests.cc", "../extension/service_unittests.cc",
"../extension/task_manager_unittests.cc",
"../gaiacp/associated_user_validator_unittests.cc", "../gaiacp/associated_user_validator_unittests.cc",
"../gaiacp/device_policies_manager_unittests.cc", "../gaiacp/device_policies_manager_unittests.cc",
"../gaiacp/gaia_credential_base_unittests.cc", "../gaiacp/gaia_credential_base_unittests.cc",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <windows.h> #include <windows.h>
#include <lm.h> #include <lm.h>
#include <process.h>
#include <sddl.h> #include <sddl.h>
#include <atlcomcli.h> #include <atlcomcli.h>
...@@ -1268,6 +1269,13 @@ FakeOSServiceManager::~FakeOSServiceManager() { ...@@ -1268,6 +1269,13 @@ FakeOSServiceManager::~FakeOSServiceManager() {
*GetInstanceStorage() = os_service_manager_; *GetInstanceStorage() = os_service_manager_;
} }
unsigned __stdcall ServiceLauncher(void* service_main) {
LPSERVICE_MAIN_FUNCTION sm = (LPSERVICE_MAIN_FUNCTION)service_main;
DWORD flags = 0;
(*sm)(flags, nullptr);
return 0;
}
DWORD FakeOSServiceManager::StartServiceCtrlDispatcher( DWORD FakeOSServiceManager::StartServiceCtrlDispatcher(
LPSERVICE_MAIN_FUNCTION service_main) { LPSERVICE_MAIN_FUNCTION service_main) {
if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) == if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) ==
...@@ -1275,12 +1283,9 @@ DWORD FakeOSServiceManager::StartServiceCtrlDispatcher( ...@@ -1275,12 +1283,9 @@ DWORD FakeOSServiceManager::StartServiceCtrlDispatcher(
return ERROR_INVALID_DATA; return ERROR_INVALID_DATA;
} }
LOGFN(INFO); LOGFN(INFO);
// Windows calls the service main by creating a new thread. This is simulated
// in the test by creating a new thread. uintptr_t wait_thread =
base::Thread t("ServiceMain Thread"); _beginthreadex(0, 0, ServiceLauncher, (void*)service_main, 0, 0);
t.Start();
t.task_runner()->PostTask(FROM_HERE,
base::BindOnce(service_main, 0, nullptr));
while (true) { while (true) {
// Service looks for control requests so that it calls the service's control // Service looks for control requests so that it calls the service's control
...@@ -1296,6 +1301,7 @@ DWORD FakeOSServiceManager::StartServiceCtrlDispatcher( ...@@ -1296,6 +1301,7 @@ DWORD FakeOSServiceManager::StartServiceCtrlDispatcher(
service_lookup_from_name_[extension::kGCPWExtensionServiceName] service_lookup_from_name_[extension::kGCPWExtensionServiceName]
.control_handler_cb_(control_request); .control_handler_cb_(control_request);
} }
::CloseHandle(reinterpret_cast<HANDLE>(wait_thread));
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
...@@ -1359,4 +1365,31 @@ DWORD FakeOSServiceManager::DeleteService() { ...@@ -1359,4 +1365,31 @@ DWORD FakeOSServiceManager::DeleteService() {
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
///////////////////////////////////////////////////////////////////////////////
FakeTaskManager::FakeTaskManager()
: task_manager_(*GetInstanceStorage()), num_of_times_executed_(0) {
*GetInstanceStorage() = this;
}
FakeTaskManager::~FakeTaskManager() {
*GetInstanceStorage() = task_manager_;
}
void FakeTaskManager::RunTasksInternal() {
if (start_time_.is_null()) {
start_time_ = base::Time::Now();
}
int64_t start_hour = start_time_.ToDeltaSinceWindowsEpoch().InHours();
num_of_times_executed_++;
int64_t current = base::Time::Now().ToDeltaSinceWindowsEpoch().InHours();
ASSERT_EQ(current - start_hour, (num_of_times_executed_ - 1) * 3)
<< (current - start_hour) << " hours since first run";
UpdateLastRunTimestamp();
}
} // namespace credential_provider } // namespace credential_provider
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/test/test_reg_util_win.h" #include "base/test/test_reg_util_win.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "chrome/credential_provider/extension/os_service_manager.h" #include "chrome/credential_provider/extension/os_service_manager.h"
#include "chrome/credential_provider/extension/task_manager.h"
#include "chrome/credential_provider/gaiacp/associated_user_validator.h" #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
#include "chrome/credential_provider/gaiacp/chrome_availability_checker.h" #include "chrome/credential_provider/gaiacp/chrome_availability_checker.h"
#include "chrome/credential_provider/gaiacp/device_policies_manager.h" #include "chrome/credential_provider/gaiacp/device_policies_manager.h"
...@@ -708,6 +709,25 @@ class FakeOSServiceManager : public extension::OSServiceManager { ...@@ -708,6 +709,25 @@ class FakeOSServiceManager : public extension::OSServiceManager {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class FakeTaskManager : public extension::TaskManager {
public:
FakeTaskManager();
~FakeTaskManager() override;
int NumOfTimesExecuted() { return num_of_times_executed_; }
private:
void RunTasksInternal() override;
// Original instance of TaskManager.
extension::TaskManager* task_manager_ = nullptr;
int num_of_times_executed_;
base::Time start_time_;
};
///////////////////////////////////////////////////////////////////////////////
} // namespace credential_provider } // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_ #endif // CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_
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