Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(281)

Side by Side Diff: chrome/browser/chromeos/memory/low_memory_observer.cc

Issue 1188823002: [MemoryPressure] Move chrome/browser/chromeos/* to chrome/browser/memory/*. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed sky@ comments. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/memory/low_memory_observer.h"
6
7 #include <fcntl.h>
8
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/sys_info.h"
13 #include "base/time/time.h"
14 #include "base/timer/timer.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/browser_process_platform_part_chromeos.h"
17 #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
18 #include "content/public/browser/browser_thread.h"
19
20 using content::BrowserThread;
21
22 namespace chromeos {
23
24 namespace {
25 // This is the file that will exist if low memory notification is available
26 // on the device. Whenever it becomes readable, it signals a low memory
27 // condition.
28 const char kLowMemFile[] = "/dev/chromeos-low-mem";
29
30 // This is the minimum amount of time in milliseconds between checks for
31 // low memory.
32 const int kLowMemoryCheckTimeoutMs = 750;
33 } // namespace
34
35 ////////////////////////////////////////////////////////////////////////////////
36 // LowMemoryObserverImpl
37 //
38 // Does the actual work of observing. The observation work happens on the FILE
39 // thread, and the discarding of tabs happens on the UI thread.
40 // If low memory is detected, then we discard a tab, wait
41 // kLowMemoryCheckTimeoutMs milliseconds and then start watching again to see
42 // if we're still in a low memory state. This is to keep from discarding all
43 // tabs the first time we enter the state, because it takes time for the
44 // tabs to deallocate their memory. A timer isn't the perfect solution, but
45 // without any reliable indicator that a tab has had all its parts deallocated,
46 // it's the next best thing.
47 class LowMemoryObserverImpl
48 : public base::RefCountedThreadSafe<LowMemoryObserverImpl> {
49 public:
50 LowMemoryObserverImpl() : watcher_delegate_(this), file_descriptor_(-1) {}
51
52 // Start watching the low memory file for readability.
53 // Calls to StartObserving should always be matched with calls to
54 // StopObserving. This method should only be called from the FILE thread.
55 void StartObservingOnFileThread();
56
57 // Stop watching the low memory file for readability.
58 // May be safely called if StartObserving has not been called.
59 // This method should only be called from the FILE thread.
60 void StopObservingOnFileThread();
61
62 private:
63 friend class base::RefCountedThreadSafe<LowMemoryObserverImpl>;
64
65 ~LowMemoryObserverImpl() {
66 StopObservingOnFileThread();
67 }
68
69 // Start a timer to resume watching the low memory file descriptor.
70 void ScheduleNextObservation();
71
72 // Actually start watching the file descriptor.
73 void StartWatchingDescriptor();
74
75 // Delegate to receive events from WatchFileDescriptor.
76 class FileWatcherDelegate : public base::MessageLoopForIO::Watcher {
77 public:
78 explicit FileWatcherDelegate(LowMemoryObserverImpl* owner)
79 : owner_(owner) {}
80 ~FileWatcherDelegate() override {}
81
82 // Overrides for base::MessageLoopForIO::Watcher
83 void OnFileCanWriteWithoutBlocking(int fd) override {}
84 void OnFileCanReadWithoutBlocking(int fd) override {
85 LOG(WARNING) << "Low memory condition detected. Discarding a tab.";
86 // We can only discard tabs on the UI thread.
87 base::Callback<void(void)> callback = base::Bind(&DiscardTab);
88 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
89 owner_->ScheduleNextObservation();
90 }
91
92 // Sends off a discard request to the OomPriorityManager. Must be run on
93 // the UI thread.
94 static void DiscardTab() {
95 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
96 if (g_browser_process &&
97 g_browser_process->platform_part()->oom_priority_manager()) {
98 g_browser_process->platform_part()->
99 oom_priority_manager()->LogMemoryAndDiscardTab();
100 }
101 }
102
103 private:
104 LowMemoryObserverImpl* owner_;
105 DISALLOW_COPY_AND_ASSIGN(FileWatcherDelegate);
106 };
107
108 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> watcher_;
109 FileWatcherDelegate watcher_delegate_;
110 int file_descriptor_;
111 base::OneShotTimer<LowMemoryObserverImpl> timer_;
112
113 DISALLOW_COPY_AND_ASSIGN(LowMemoryObserverImpl);
114 };
115
116 void LowMemoryObserverImpl::StartObservingOnFileThread() {
117 DCHECK_LE(file_descriptor_, 0)
118 << "Attempted to start observation when it was already started.";
119 DCHECK(watcher_.get() == NULL);
120 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
121 DCHECK(base::MessageLoopForIO::current());
122
123 file_descriptor_ = ::open(kLowMemFile, O_RDONLY);
124 // Don't report this error unless we're really running on ChromeOS
125 // to avoid testing spam.
126 if (file_descriptor_ < 0 && base::SysInfo::IsRunningOnChromeOS()) {
127 PLOG(ERROR) << "Unable to open " << kLowMemFile;
128 return;
129 }
130 watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
131 StartWatchingDescriptor();
132 }
133
134 void LowMemoryObserverImpl::StopObservingOnFileThread() {
135 // If StartObserving failed, StopObserving will still get called.
136 timer_.Stop();
137 if (file_descriptor_ >= 0) {
138 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
139 watcher_.reset(NULL);
140 ::close(file_descriptor_);
141 file_descriptor_ = -1;
142 }
143 }
144
145 void LowMemoryObserverImpl::ScheduleNextObservation() {
146 timer_.Start(FROM_HERE,
147 base::TimeDelta::FromMilliseconds(kLowMemoryCheckTimeoutMs),
148 this,
149 &LowMemoryObserverImpl::StartWatchingDescriptor);
150 }
151
152 void LowMemoryObserverImpl::StartWatchingDescriptor() {
153 DCHECK(watcher_.get());
154 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
155 DCHECK(base::MessageLoopForIO::current());
156 if (file_descriptor_ < 0)
157 return;
158 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
159 file_descriptor_,
160 false, // persistent=false: We want it to fire once and reschedule.
161 base::MessageLoopForIO::WATCH_READ,
162 watcher_.get(),
163 &watcher_delegate_)) {
164 LOG(ERROR) << "Unable to watch " << kLowMemFile;
165 }
166 }
167
168 ////////////////////////////////////////////////////////////////////////////////
169 // LowMemoryObserver
170
171 LowMemoryObserver::LowMemoryObserver() : observer_(new LowMemoryObserverImpl) {}
172
173 LowMemoryObserver::~LowMemoryObserver() { Stop(); }
174
175 void LowMemoryObserver::Start() {
176 BrowserThread::PostTask(
177 BrowserThread::FILE,
178 FROM_HERE,
179 base::Bind(&LowMemoryObserverImpl::StartObservingOnFileThread,
180 observer_.get()));
181 }
182
183 void LowMemoryObserver::Stop() {
184 BrowserThread::PostTask(
185 BrowserThread::FILE,
186 FROM_HERE,
187 base::Bind(&LowMemoryObserverImpl::StopObservingOnFileThread,
188 observer_.get()));
189 }
190
191 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/memory/low_memory_observer.h ('k') | chrome/browser/chromeos/memory/oom_memory_details.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698