| // Copyright 2015 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 "chromeos/binder/ipc_thread.h" |
| |
| #include "chromeos/binder/command_broker.h" |
| #include "chromeos/binder/driver.h" |
| |
| namespace binder { |
| |
| // IpcThreadPoller |
| IpcThreadPoller::IpcThreadPoller(ThreadType type, Driver* driver) |
| : type_(type), driver_(driver), command_broker_(driver) {} |
| |
| IpcThreadPoller::~IpcThreadPoller() { |
| if (!command_broker_.ExitLooper()) { |
| LOG(ERROR) << "Failed to exit looper."; |
| } |
| if (!driver_->NotifyCurrentThreadExiting()) { |
| LOG(ERROR) << "Failed to send thread exit."; |
| } |
| } |
| |
| bool IpcThreadPoller::Initialize() { |
| if (type_ == THREAD_TYPE_MAIN) { |
| if (!command_broker_.EnterLooper()) { |
| LOG(ERROR) << "Failed to enter looper."; |
| return false; |
| } |
| } else { |
| if (!command_broker_.RegisterLooper()) { |
| LOG(ERROR) << "Failed to register looper."; |
| return false; |
| } |
| } |
| if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |
| driver_->GetFD(), true, base::MessageLoopForIO::WATCH_READ, &watcher_, |
| this)) { |
| LOG(ERROR) << "Failed to initialize watcher."; |
| return false; |
| } |
| return true; |
| } |
| |
| void IpcThreadPoller::OnFileCanReadWithoutBlocking(int fd) { |
| bool success = command_broker_.PollCommands(); |
| LOG_IF(ERROR, !success) << "PollCommands() failed."; |
| } |
| |
| void IpcThreadPoller::OnFileCanWriteWithoutBlocking(int fd) { |
| NOTREACHED(); |
| } |
| |
| // MainIpcThread |
| MainIpcThread::MainIpcThread() : base::Thread("BinderMainThread") {} |
| |
| MainIpcThread::~MainIpcThread() { |
| Stop(); |
| } |
| |
| bool MainIpcThread::Start() { |
| base::Thread::Options options; |
| options.message_loop_type = base::MessageLoop::TYPE_IO; |
| return StartWithOptions(options); |
| } |
| |
| void MainIpcThread::Init() { |
| driver_.reset(new Driver()); |
| if (!driver_->Initialize()) { |
| LOG(ERROR) << "Failed to initialize driver."; |
| return; |
| } |
| poller_.reset( |
| new IpcThreadPoller(IpcThreadPoller::THREAD_TYPE_MAIN, driver_.get())); |
| if (!poller_->Initialize()) { |
| LOG(ERROR) << "Failed to initialize poller."; |
| return; |
| } |
| initialized_ = true; |
| } |
| |
| void MainIpcThread::CleanUp() { |
| poller_.reset(); |
| driver_.reset(); |
| } |
| |
| // SubIpcThread |
| SubIpcThread::SubIpcThread(MainIpcThread* main_thread) |
| : base::Thread("BinderSubThread"), main_thread_(main_thread) {} |
| |
| SubIpcThread::~SubIpcThread() { |
| Stop(); |
| } |
| |
| bool SubIpcThread::Start() { |
| base::Thread::Options options; |
| options.message_loop_type = base::MessageLoop::TYPE_IO; |
| return StartWithOptions(options); |
| } |
| |
| void SubIpcThread::Init() { |
| // Wait for the main thread to finish initialization. |
| if (!main_thread_->WaitUntilThreadStarted()) { |
| LOG(ERROR) << "Failed to wait for the main thread."; |
| return; |
| } |
| poller_.reset(new IpcThreadPoller(IpcThreadPoller::THREAD_TYPE_SUB, |
| main_thread_->driver())); |
| if (!poller_->Initialize()) { |
| LOG(ERROR) << "Failed to initialize poller."; |
| return; |
| } |
| initialized_ = true; |
| } |
| |
| void SubIpcThread::CleanUp() { |
| poller_.reset(); |
| } |
| |
| } // namespace binder |