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()));
}
}