First cut at minibind classes.
[minibind.git] / jni / minibind / minibind.cc
1 // Copyright 2015 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 "minibind.h"
6
7 #include <fcntl.h>
8 #include <linux/binder.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <sys/mman.h>
12
13 #include <vector>
14
15 #include "channel.h"
16 #include "command.h"
17 #include "common.h"
18 #include "parcel.h"
19
20 namespace minibind {
21
22 int ConnectDriver() {
23 int fd = open("/dev/binder", O_RDONLY);
24 if (fd < 0) {
25 AERR("open driver");
26 abort();
27 }
28
29 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
30 AERR("fcntl FD_CLOEXEC");
31 }
32
33 struct binder_version version;
34 int rv = ioctl(fd, BINDER_VERSION, &version);
35 if (rv) {
36 AERR("ioctl BINDER_VERSION");
37 abort();
38 }
39 ALOG("Binder version: %d", version.protocol_version);
40 if (version.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION) {
41 ALOG("Version is not compatible with current protocol: %d", BINDER_CURRENT_PROTOCOL_VERSION);
42 abort();
43 }
44
45 void* vm = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
46 if (vm == MAP_FAILED) {
47 AERR("mmap BINDER_VM_SIZE");
48 abort();
49 }
50
51 return fd;
52 }
53
54 class Transaction {
55 public:
56 Transaction() : sealed_(false),
57 read_buffer_(),
58 write_buffer_(),
59 command_(),
60 write_tx_(),
61 read_tx_() {
62 read_buffer_.resize(64);
63 }
64 ~Transaction() {}
65
66 void WriteString8(const std::string& str) {
67 CHECK(!sealed_);
68 for (size_t i = 0; i < str.length(); ++i) {
69 write_buffer_.push_back(str[i]);
70 }
71 write_buffer_.push_back('\0');
72 }
73
74 void WriteInt32(uint32_t i) {
75 CHECK(!sealed_);
76 write_buffer_.push_back((i >> 24) & 0xFF);
77 write_buffer_.push_back((i >> 16) & 0xFF);
78 write_buffer_.push_back((i >> 8) & 0xFF);
79 write_buffer_.push_back((i >> 0) & 0xFF);
80 }
81
82 const struct binder_transaction_data* read_data() const { return &read_tx_.data; }
83
84 private:
85 friend class Channel2;
86
87 struct TransactionBuffer {
88 TransactionBuffer() : command(BC_TRANSACTION), data() {}
89
90 uint32_t command;
91 struct binder_transaction_data data;
92 };
93
94 void Seal() {
95 CHECK(!sealed_);
96
97 write_tx_.data.data_size = write_buffer_.size();
98 write_tx_.data.data.ptr.buffer = reinterpret_cast<binder_uintptr_t>(&write_buffer_[0]);
99
100 read_tx_.command = BC_REPLY;
101 read_tx_.data.data_size = read_buffer_.size();
102 read_tx_.data.data.ptr.buffer = reinterpret_cast<binder_uintptr_t>(&read_buffer_[0]);
103
104 command_.write_size = sizeof(write_tx_);
105 command_.write_buffer = reinterpret_cast<binder_uintptr_t>(&write_tx_);
106 command_.read_size = sizeof(read_tx_);
107 command_.read_buffer = reinterpret_cast<binder_uintptr_t>(&read_tx_);
108
109 sealed_ = true;
110 }
111
112 bool sealed_;
113
114 std::vector<uint8_t> write_buffer_;
115 std::vector<uint8_t> read_buffer_;
116
117 struct binder_write_read command_;
118 TransactionBuffer write_tx_;
119 TransactionBuffer read_tx_;
120 };
121
122 class Channel2 {
123 public:
124 Channel2(const std::string& interface)
125 : interface_(interface),
126 fd_(ConnectDriver()) {
127 }
128 ~Channel2() {}
129
130 Transaction* NewTransaction(uint32_t code) const {
131 Transaction* t = new Transaction();
132 t->write_tx_.data.code = code;
133 t->WriteString8(interface());
134 return t;
135 }
136
137 int ExecuteTransaction(Transaction* tx) {
138 tx->Seal();
139 int rv = ioctl(fd_, BINDER_WRITE_READ, &tx->command_);
140 ALOG("BINDER_WRITE_READ: %d", rv);
141 if (rv) {
142 AERR("BINDER_WRITE_READ");
143 }
144
145 for (size_t i = 0; i < tx->read_buffer_.size(); i += 4) {
146 ALOG("%0x %0x %0x %0x", tx->read_buffer_[i], tx->read_buffer_[i+1], tx->read_buffer_[i+2], tx->read_buffer_[i+3]);
147 }
148 }
149
150 const std::string& interface() const { return interface_; }
151
152 private:
153 const std::string interface_;
154 int fd_;
155 };
156
157 Channel* LookupService(const std::string& name) {
158 Parcel data;
159 data.WriteInterfaceToken("android.os.IServiceManager");
160 data.WriteUTF8(name);
161
162 Channel channel(0);
163
164 TransactionCommand command(TransactionCommand::TWO_WAY);
165 command.SetHandle(channel.handle());
166 command.SetCode(2 /*CHECK_SERVICE_TRANSACTION*/);
167 command.SetParcel(data);
168
169 channel.QueueCommand(&command);
170 channel.TransactCommands();
171 channel.reader()->Print();
172
173 #if 0
174 Channel2* ch = new Channel2("android.os.IServiceManager");
175 Transaction* tx = ch->NewTransaction(2 /*CHECK_SERVICE_TRANSACTION*/);
176 tx->WriteString8(name);
177 ch->ExecuteTransaction(tx);
178 #endif
179 }
180
181 } // namespace minibind