// 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/driver.h" #include #include #include #include #include #include #include #include "base/posix/eintr_wrapper.h" #include "base/threading/thread_restrictions.h" #include "chromeos/binder/binder_driver_api.h" namespace binder { namespace { const char kDriverPath[] = "/dev/binder"; } // namespace Driver::Driver() : mmap_address_(MAP_FAILED) {} Driver::~Driver() { base::ThreadRestrictions::AssertIOAllowed(); if (mmap_address_ != MAP_FAILED) { if (munmap(mmap_address_, GetBinderMmapSize()) == -1) { PLOG(ERROR) << "Failed to munmap"; } } fd_.reset(); // Close FD. } bool Driver::Initialize() { base::ThreadRestrictions::AssertIOAllowed(); // Open binder driver. fd_.reset(HANDLE_EINTR(open(kDriverPath, O_RDWR | O_CLOEXEC | O_NONBLOCK))); if (!fd_.is_valid()) { PLOG(ERROR) << "Failed to open"; return false; } // Version check. int version = 0; if (HANDLE_EINTR(ioctl(fd_.get(), BINDER_VERSION, &version)) != 0 || version != BINDER_CURRENT_PROTOCOL_VERSION) { PLOG(ERROR) << "Version check failure: version = " << version; return false; } // Disable thread spawning. if (!SetMaxThreads(0)) { PLOG(ERROR) << "SetMaxThreads() failed"; return false; } // Allocate buffer for transaction data. mmap_address_ = mmap(0, GetBinderMmapSize(), PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd_.get(), 0); if (mmap_address_ == MAP_FAILED) { PLOG(ERROR) << "Failed to mmap"; return false; } return true; } int Driver::GetFD() { return fd_.get(); } bool Driver::SetMaxThreads(int max_threads) { base::ThreadRestrictions::AssertIOAllowed(); return HANDLE_EINTR(ioctl(fd_.get(), BINDER_SET_MAX_THREADS, &max_threads)) != -1; } bool Driver::WriteRead(const char* write_buf, size_t write_buf_size, char* read_buf, size_t read_buf_size, size_t* written_bytes, size_t* read_bytes) { base::ThreadRestrictions::AssertIOAllowed(); binder_write_read params = {}; params.write_buffer = reinterpret_cast(write_buf); params.write_size = write_buf_size; params.read_buffer = reinterpret_cast(read_buf); params.read_size = read_buf_size; if (HANDLE_EINTR(ioctl(fd_.get(), BINDER_WRITE_READ, ¶ms)) < 0 && errno != EAGAIN) { // EAGAIN means there is no data to read. PLOG(ERROR) << "BINDER_WRITE_READ failed: write_buf_size = " << write_buf_size << ", read_buf_size = " << read_buf_size; return false; } *written_bytes = params.write_consumed; *read_bytes = params.read_consumed; return true; } bool Driver::Poll() { pollfd params = {}; params.fd = fd_.get(); params.events = POLLIN; const int kNumFds = 1; const int kTimeout = -1; // No timeout. return HANDLE_EINTR(poll(¶ms, kNumFds, kTimeout)) == kNumFds; } bool Driver::NotifyCurrentThreadExiting() { base::ThreadRestrictions::AssertIOAllowed(); return HANDLE_EINTR(ioctl(fd_.get(), BINDER_THREAD_EXIT, 0)) != -1; } size_t Driver::GetBinderMmapSize() const { // Subtract PAGESIZE * 2 to make room for guard pages. https://goo.gl/4Q6sPe return 1024 * 1024 - sysconf(_SC_PAGESIZE) * 2; } } // namespace binder