aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Deymo <deymo@google.com>2016-01-19 23:42:07 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-01-19 23:42:07 +0000
commit96b56e5786f8f026c6294d06570d8d4d153021d6 (patch)
tree6e86a87909732122850f65473055c8b75dbe6344
parent7872d3c8bc6cea07f9f66d538d77bb32471073ba (diff)
parentd671746a66d87edf9598cfbe077b3430e50a09d3 (diff)
downloadplatform_external_libbrillo-96b56e5786f8f026c6294d06570d8d4d153021d6.tar.gz
platform_external_libbrillo-96b56e5786f8f026c6294d06570d8d4d153021d6.tar.bz2
platform_external_libbrillo-96b56e5786f8f026c6294d06570d8d4d153021d6.zip
Don\'t delete and add the binder fd in BaseMessageLoop.
am: d671746a66 * commit 'd671746a66d87edf9598cfbe077b3430e50a09d3': Don't delete and add the binder fd in BaseMessageLoop.
-rw-r--r--Android.mk1
-rw-r--r--brillo/message_loops/base_message_loop.cc85
-rw-r--r--brillo/message_loops/base_message_loop.h30
-rw-r--r--brillo/message_loops/base_message_loop_unittest.cc24
-rw-r--r--libbrillo.gypi1
5 files changed, 138 insertions, 3 deletions
diff --git a/Android.mk b/Android.mk
index 2181a3a..89cbc73 100644
--- a/Android.mk
+++ b/Android.mk
@@ -107,6 +107,7 @@ libbrillo_test_sources := \
brillo/http/http_utils_unittest.cc \
brillo/key_value_store_unittest.cc \
brillo/map_utils_unittest.cc \
+ brillo/message_loops/base_message_loop_unittest.cc \
brillo/message_loops/fake_message_loop_unittest.cc \
brillo/mime_utils_unittest.cc \
brillo/osrelease_reader_unittest.cc \
diff --git a/brillo/message_loops/base_message_loop.cc b/brillo/message_loops/base_message_loop.cc
index a24c64b..49dba40 100644
--- a/brillo/message_loops/base_message_loop.cc
+++ b/brillo/message_loops/base_message_loop.cc
@@ -5,17 +5,37 @@
#include <brillo/message_loops/base_message_loop.h>
#include <fcntl.h>
+#include <linux/major.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
+#include <vector>
+
#include <base/bind.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
#include <base/run_loop.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
#include <brillo/location_logging.h>
+#include <brillo/strings/string_utils.h>
using base::Closure;
+namespace {
+
+const char kMiscMinorPath[] = "/proc/misc";
+const char kBinderDriverName[] = "binder";
+
+} // namespace
+
namespace brillo {
+const int BaseMessageLoop::kInvalidMinor = -1;
+const int BaseMessageLoop::kUninitializedMinor = -2;
+
BaseMessageLoop::BaseMessageLoop(base::MessageLoopForIO* base_loop)
: base_loop_(base_loop),
weak_ptr_factory_(this) {}
@@ -107,6 +127,23 @@ MessageLoop::TaskId BaseMessageLoop::WatchFileDescriptor(
io_tasks_.erase(task_id);
return MessageLoop::kTaskIdNull;
}
+
+ // Determine if the passed fd is the binder file descriptor. For that, we need
+ // to check that is a special char device and that the major and minor device
+ // numbers match. The binder file descriptor can't be removed and added back
+ // to an epoll group when there's work available to be done by the file
+ // descriptor due to bugs in the binder driver (b/26524111) when used with
+ // epoll. Therefore, we flag the binder fd and never attempt to remove it.
+ // This may cause the binder file descriptor to be attended with higher
+ // priority and cause starvation of other events.
+ struct stat buf;
+ if (fstat(fd, &buf) == 0 &&
+ S_ISCHR(buf.st_mode) &&
+ major(buf.st_rdev) == MISC_MAJOR &&
+ minor(buf.st_rdev) == GetBinderMinor()) {
+ it_bool.first->second.RunImmediately();
+ }
+
return task_id;
}
@@ -219,6 +256,38 @@ void BaseMessageLoop::OnFileReadyPostedTask(MessageLoop::TaskId task_id) {
task_it->second.OnFileReadyPostedTask();
}
+int BaseMessageLoop::ParseBinderMinor(
+ const std::string& file_contents) {
+ int result = kInvalidMinor;
+ // Split along '\n', then along the ' '. Note that base::SplitString trims all
+ // white spaces at the beginning and end after splitting.
+ std::vector<std::string> lines;
+ base::SplitString(file_contents, '\n', &lines);
+ for (const std::string& line : lines) {
+ if (line.empty())
+ continue;
+ std::string number;
+ std::string name;
+ if (!string_utils::SplitAtFirst(line, " ", &number, &name, false))
+ continue;
+
+ if (name == kBinderDriverName && base::StringToInt(number, &result))
+ break;
+ }
+ return result;
+}
+
+unsigned int BaseMessageLoop::GetBinderMinor() {
+ if (binder_minor_ != kUninitializedMinor)
+ return binder_minor_;
+
+ std::string proc_misc;
+ if (!base::ReadFileToString(base::FilePath(kMiscMinorPath), &proc_misc))
+ return binder_minor_;
+ binder_minor_ = ParseBinderMinor(proc_misc);
+ return binder_minor_;
+}
+
BaseMessageLoop::IOTask::IOTask(const tracked_objects::Location& location,
BaseMessageLoop* loop,
MessageLoop::TaskId task_id,
@@ -248,9 +317,17 @@ void BaseMessageLoop::IOTask::OnFileCanWriteWithoutBlocking(int /* fd */) {
}
void BaseMessageLoop::IOTask::OnFileReady() {
+ // For file descriptors marked with the immediate_run flag, we don't call
+ // StopWatching() and wait, instead we dispatch the callback immediately.
+ if (immediate_run_) {
+ posted_task_pending_ = true;
+ OnFileReadyPostedTask();
+ return;
+ }
+
// When the file descriptor becomes available we stop watching for it and
// schedule a task to run the callback from the main loop. The callback will
- // run using the same scheduler use to run other delayed tasks, avoiding
+ // run using the same scheduler used to run other delayed tasks, avoiding
// starvation of the available posted tasks if there are file descriptors
// always available. The new posted task will use the same TaskId as the
// current file descriptor watching task an could be canceled in either state,
@@ -300,8 +377,10 @@ void BaseMessageLoop::IOTask::OnFileReadyPostedTask() {
if (persistent_) {
// In the persistent case we just run the callback. If this callback cancels
// the task id, we can't access |this| anymore, so we re-start watching the
- // file descriptor before running the callback.
- StartWatching();
+ // file descriptor before running the callback, unless this is a fd where
+ // we didn't stop watching the file descriptor when it became available.
+ if (!immediate_run_)
+ StartWatching();
closure_.Run();
} else {
// This will destroy |this|, the fd_watcher and therefore stop watching this
diff --git a/brillo/message_loops/base_message_loop.h b/brillo/message_loops/base_message_loop.h
index 529d476..eb5de54 100644
--- a/brillo/message_loops/base_message_loop.h
+++ b/brillo/message_loops/base_message_loop.h
@@ -14,11 +14,13 @@
#include <map>
#include <memory>
+#include <string>
#include <base/location.h>
#include <base/memory/weak_ptr.h>
#include <base/message_loop/message_loop.h>
#include <base/time/time.h>
+#include <gtest/gtest_prod.h>
#include <brillo/brillo_export.h>
#include <brillo/message_loops/message_loop.h>
@@ -51,6 +53,16 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
base::Closure QuitClosure() const;
private:
+ FRIEND_TEST(BaseMessageLoopTest, ParseBinderMinor);
+
+ static const int kInvalidMinor;
+ static const int kUninitializedMinor;
+
+ // Parses the contents of the file /proc/misc passed in |file_contents| and
+ // returns the minor device number reported for binder. On error or if not
+ // found, returns kInvalidMinor.
+ static int ParseBinderMinor(const std::string& file_contents);
+
// Called by base::MessageLoopForIO when is time to call the callback
// scheduled with Post*Task() of id |task_id|, even if it was canceled.
void OnRanPostedTask(MessageLoop::TaskId task_id);
@@ -64,6 +76,9 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// Return a new unused task_id.
TaskId NextTaskId();
+ // Returns binder minor device number.
+ unsigned int GetBinderMinor();
+
struct DelayedTask {
tracked_objects::Location location;
@@ -98,6 +113,10 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// same semantics as MessageLoop::CancelTask().
bool CancelTask();
+ // Sets the closure to be run immediately whenever the file descriptor
+ // becomes ready.
+ void RunImmediately() { immediate_run_= true; }
+
private:
tracked_objects::Location location_;
BaseMessageLoop* loop_;
@@ -116,6 +135,11 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// Tells whether there is a pending call to OnFileReadPostedTask().
bool posted_task_pending_{false};
+ // Whether the registered callback should be running immediately when the
+ // file descriptor is ready, as opposed to posting a task to the main loop
+ // to prevent starvation.
+ bool immediate_run_{false};
+
// base::MessageLoopForIO::Watcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
@@ -143,6 +167,12 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// The RunLoop instance used to run the main loop from Run().
base::RunLoop* base_run_loop_{nullptr};
+ // The binder minor device number. Binder is a "misc" char device with a
+ // dynamically allocated minor number. When uninitialized, this value will
+ // be negative, otherwise, it will hold the minor part of the binder device
+ // number. This is populated by GetBinderMinor().
+ int binder_minor_{kUninitializedMinor};
+
// We use a WeakPtrFactory to schedule tasks with the base::MessageLoopForIO
// since we can't cancel the callbacks we have scheduled there once this
// instance is destroyed.
diff --git a/brillo/message_loops/base_message_loop_unittest.cc b/brillo/message_loops/base_message_loop_unittest.cc
new file mode 100644
index 0000000..9e052a8
--- /dev/null
+++ b/brillo/message_loops/base_message_loop_unittest.cc
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium OS 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 <brillo/message_loops/base_message_loop.h>
+
+#include <gtest/gtest.h>
+
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+class BaseMessageLoopTest : public ::testing::Test {};
+
+TEST(BaseMessageLoopTest, ParseBinderMinor) {
+ EXPECT_EQ(57, BaseMessageLoop::ParseBinderMinor(
+ "227 mcelog\n 58 sw_sync\n 59 ashmem\n 57 binder\n239 uhid\n"));
+ EXPECT_EQ(123, BaseMessageLoop::ParseBinderMinor("123 binder\n"));
+
+ EXPECT_EQ(BaseMessageLoop::kInvalidMinor,
+ BaseMessageLoop::ParseBinderMinor("227 foo\n239 bar\n"));
+}
+
+} // namespace brillo
diff --git a/libbrillo.gypi b/libbrillo.gypi
index 03eb2d9..6c317d7 100644
--- a/libbrillo.gypi
+++ b/libbrillo.gypi
@@ -337,6 +337,7 @@
'brillo/http/http_utils_unittest.cc',
'brillo/key_value_store_unittest.cc',
'brillo/map_utils_unittest.cc',
+ 'brillo/message_loops/base_message_loop_unittest.cc',
'brillo/message_loops/fake_message_loop_unittest.cc',
'brillo/message_loops/glib_message_loop_unittest.cc',
'brillo/message_loops/message_loop_unittest.cc',