This source file includes following definitions.
- file_descriptor_
- OnFileCanWriteWithoutBlocking
- OnFileCanReadWithoutBlocking
- DiscardTab
- StartObservingOnFileThread
- StopObservingOnFileThread
- ScheduleNextObservation
- StartWatchingDescriptor
- Start
- Stop
#include "chrome/browser/chromeos/memory/low_memory_observer.h"
#include <fcntl.h>
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/sys_info.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part_chromeos.h"
#include "chrome/browser/chromeos/memory/oom_priority_manager.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace chromeos {
namespace {
const char kLowMemFile[] = "/dev/chromeos-low-mem";
const int kLowMemoryCheckTimeoutMs = 750;
}
class LowMemoryObserverImpl
: public base::RefCountedThreadSafe<LowMemoryObserverImpl> {
public:
LowMemoryObserverImpl() : watcher_delegate_(this), file_descriptor_(-1) {}
void StartObservingOnFileThread();
void StopObservingOnFileThread();
private:
friend class base::RefCountedThreadSafe<LowMemoryObserverImpl>;
~LowMemoryObserverImpl() {
StopObservingOnFileThread();
}
void ScheduleNextObservation();
void StartWatchingDescriptor();
class FileWatcherDelegate : public base::MessageLoopForIO::Watcher {
public:
explicit FileWatcherDelegate(LowMemoryObserverImpl* owner)
: owner_(owner) {}
virtual ~FileWatcherDelegate() {}
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
LOG(WARNING) << "Low memory condition detected. Discarding a tab.";
base::Callback<void(void)> callback = base::Bind(&DiscardTab);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
owner_->ScheduleNextObservation();
}
static void DiscardTab() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (g_browser_process &&
g_browser_process->platform_part()->oom_priority_manager()) {
g_browser_process->platform_part()->
oom_priority_manager()->LogMemoryAndDiscardTab();
}
}
private:
LowMemoryObserverImpl* owner_;
DISALLOW_COPY_AND_ASSIGN(FileWatcherDelegate);
};
scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> watcher_;
FileWatcherDelegate watcher_delegate_;
int file_descriptor_;
base::OneShotTimer<LowMemoryObserverImpl> timer_;
DISALLOW_COPY_AND_ASSIGN(LowMemoryObserverImpl);
};
void LowMemoryObserverImpl::StartObservingOnFileThread() {
DCHECK_LE(file_descriptor_, 0)
<< "Attempted to start observation when it was already started.";
DCHECK(watcher_.get() == NULL);
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(base::MessageLoopForIO::current());
file_descriptor_ = ::open(kLowMemFile, O_RDONLY);
if (file_descriptor_ < 0 && base::SysInfo::IsRunningOnChromeOS()) {
PLOG(ERROR) << "Unable to open " << kLowMemFile;
return;
}
watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
StartWatchingDescriptor();
}
void LowMemoryObserverImpl::StopObservingOnFileThread() {
timer_.Stop();
if (file_descriptor_ >= 0) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
watcher_.reset(NULL);
::close(file_descriptor_);
file_descriptor_ = -1;
}
}
void LowMemoryObserverImpl::ScheduleNextObservation() {
timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kLowMemoryCheckTimeoutMs),
this,
&LowMemoryObserverImpl::StartWatchingDescriptor);
}
void LowMemoryObserverImpl::StartWatchingDescriptor() {
DCHECK(watcher_.get());
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(base::MessageLoopForIO::current());
if (file_descriptor_ < 0)
return;
if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
file_descriptor_,
false,
base::MessageLoopForIO::WATCH_READ,
watcher_.get(),
&watcher_delegate_)) {
LOG(ERROR) << "Unable to watch " << kLowMemFile;
}
}
LowMemoryObserver::LowMemoryObserver() : observer_(new LowMemoryObserverImpl) {}
LowMemoryObserver::~LowMemoryObserver() { Stop(); }
void LowMemoryObserver::Start() {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&LowMemoryObserverImpl::StartObservingOnFileThread,
observer_.get()));
}
void LowMemoryObserver::Stop() {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&LowMemoryObserverImpl::StopObservingOnFileThread,
observer_.get()));
}
}