// Copyright (c) 2010 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/browser/sync/notifier/chrome_system_resources.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "chrome/browser/sync/notifier/invalidation_util.h"
namespace sync_notifier {
ChromeSystemResources::ChromeSystemResources(StateWriter* state_writer)
: state_writer_(state_writer),
created_on_loop_(MessageLoop::current()) {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK(created_on_loop_);
DCHECK(state_writer_);
}
ChromeSystemResources::~ChromeSystemResources() {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
StopScheduler();
}
invalidation::Time ChromeSystemResources::current_time() {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
return base::Time::Now();
}
void ChromeSystemResources::StartScheduler() {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
scoped_runnable_method_factory_.reset(
new ScopedRunnableMethodFactory<ChromeSystemResources>(this));
}
void ChromeSystemResources::StopScheduler() {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
scoped_runnable_method_factory_.reset();
STLDeleteElements(&posted_tasks_);
}
void ChromeSystemResources::ScheduleWithDelay(
invalidation::TimeDelta delay,
invalidation::Closure* task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
Task* task_to_post = MakeTaskToPost(task);
if (!task_to_post) {
return;
}
MessageLoop::current()->PostDelayedTask(
FROM_HERE, task_to_post, delay.InMillisecondsRoundedUp());
}
void ChromeSystemResources::ScheduleImmediately(
invalidation::Closure* task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
Task* task_to_post = MakeTaskToPost(task);
if (!task_to_post) {
return;
}
MessageLoop::current()->PostTask(FROM_HERE, task_to_post);
}
// The listener thread is just our current thread (i.e., the
// notifications thread).
void ChromeSystemResources::ScheduleOnListenerThread(
invalidation::Closure* task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
ScheduleImmediately(task);
}
// 'Internal thread' means 'not the listener thread'. Since the
// listener thread is the notifications thread, always return false.
bool ChromeSystemResources::IsRunningOnInternalThread() {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
return false;
}
void ChromeSystemResources::Log(
LogLevel level, const char* file, int line,
const char* format, ...) {
DCHECK(non_thread_safe_.CalledOnValidThread());
logging::LogSeverity log_severity = logging::LOG_INFO;
switch (level) {
case INFO_LEVEL:
log_severity = logging::LOG_INFO;
break;
case WARNING_LEVEL:
log_severity = logging::LOG_WARNING;
break;
case SEVERE_LEVEL:
log_severity = logging::LOG_ERROR;
break;
}
// We treat LOG(INFO) as VLOG(1).
if ((log_severity >= logging::GetMinLogLevel()) &&
((log_severity != logging::LOG_INFO) ||
(1 <= logging::GetVlogLevelHelper(file, ::strlen(file))))) {
va_list ap;
va_start(ap, format);
std::string result;
base::StringAppendV(&result, format, ap);
logging::LogMessage(file, line, log_severity).stream() << result;
va_end(ap);
}
}
void ChromeSystemResources::RunAndDeleteStorageCallback(
invalidation::StorageCallback* callback) {
callback->Run(true);
delete callback;
}
void ChromeSystemResources::WriteState(
const invalidation::string& state,
invalidation::StorageCallback* callback) {
CHECK(state_writer_);
state_writer_->WriteState(state);
// According to the cache invalidation API folks, we can do this as
// long as we make sure to clear the persistent state that we start
// up the cache invalidation client with. However, we musn't do it
// right away, as we may be called under a lock that the callback
// uses.
ScheduleImmediately(
invalidation::NewPermanentCallback(
this, &ChromeSystemResources::RunAndDeleteStorageCallback,
callback));
}
Task* ChromeSystemResources::MakeTaskToPost(
invalidation::Closure* task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(task));
CHECK_EQ(created_on_loop_, MessageLoop::current());
if (!scoped_runnable_method_factory_.get()) {
delete task;
return NULL;
}
posted_tasks_.insert(task);
Task* task_to_post =
scoped_runnable_method_factory_->NewRunnableMethod(
&ChromeSystemResources::RunPostedTask, task);
return task_to_post;
}
void ChromeSystemResources::RunPostedTask(invalidation::Closure* task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
CHECK_EQ(created_on_loop_, MessageLoop::current());
RunAndDeleteClosure(task);
posted_tasks_.erase(task);
}
} // namespace sync_notifier