1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
// 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 <errno.h>
#include <fcntl.h>
#include <linux/android/binder.h>
#include <stddef.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/user.h>
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.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)));
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<const uintptr_t>(write_buf);
params.write_size = write_buf_size;
params.read_buffer = reinterpret_cast<uintptr_t>(read_buf);
params.read_size = read_buf_size;
if (HANDLE_EINTR(ioctl(fd_.get(), BINDER_WRITE_READ, ¶ms)) < 0) {
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::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
|