+// 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 "minibind.h"
+
+#include <fcntl.h>
+#include <linux/binder.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+#include <vector>
+
+#include "channel.h"
+#include "command.h"
+#include "common.h"
+#include "parcel.h"
+
+namespace minibind {
+
+int ConnectDriver() {
+ int fd = open("/dev/binder", O_RDONLY);
+ if (fd < 0) {
+ AERR("open driver");
+ abort();
+ }
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
+ AERR("fcntl FD_CLOEXEC");
+ }
+
+ struct binder_version version;
+ int rv = ioctl(fd, BINDER_VERSION, &version);
+ if (rv) {
+ AERR("ioctl BINDER_VERSION");
+ abort();
+ }
+ ALOG("Binder version: %d", version.protocol_version);
+ if (version.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION) {
+ ALOG("Version is not compatible with current protocol: %d", BINDER_CURRENT_PROTOCOL_VERSION);
+ abort();
+ }
+
+ void* vm = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
+ if (vm == MAP_FAILED) {
+ AERR("mmap BINDER_VM_SIZE");
+ abort();
+ }
+
+ return fd;
+}
+
+class Transaction {
+ public:
+ Transaction() : sealed_(false),
+ read_buffer_(),
+ write_buffer_(),
+ command_(),
+ write_tx_(),
+ read_tx_() {
+ read_buffer_.resize(64);
+ }
+ ~Transaction() {}
+
+ void WriteString8(const std::string& str) {
+ CHECK(!sealed_);
+ for (size_t i = 0; i < str.length(); ++i) {
+ write_buffer_.push_back(str[i]);
+ }
+ write_buffer_.push_back('\0');
+ }
+
+ void WriteInt32(uint32_t i) {
+ CHECK(!sealed_);
+ write_buffer_.push_back((i >> 24) & 0xFF);
+ write_buffer_.push_back((i >> 16) & 0xFF);
+ write_buffer_.push_back((i >> 8) & 0xFF);
+ write_buffer_.push_back((i >> 0) & 0xFF);
+ }
+
+ const struct binder_transaction_data* read_data() const { return &read_tx_.data; }
+
+ private:
+ friend class Channel2;
+
+ struct TransactionBuffer {
+ TransactionBuffer() : command(BC_TRANSACTION), data() {}
+
+ uint32_t command;
+ struct binder_transaction_data data;
+ };
+
+ void Seal() {
+ CHECK(!sealed_);
+
+ write_tx_.data.data_size = write_buffer_.size();
+ write_tx_.data.data.ptr.buffer = reinterpret_cast<binder_uintptr_t>(&write_buffer_[0]);
+
+ read_tx_.command = BC_REPLY;
+ read_tx_.data.data_size = read_buffer_.size();
+ read_tx_.data.data.ptr.buffer = reinterpret_cast<binder_uintptr_t>(&read_buffer_[0]);
+
+ command_.write_size = sizeof(write_tx_);
+ command_.write_buffer = reinterpret_cast<binder_uintptr_t>(&write_tx_);
+ command_.read_size = sizeof(read_tx_);
+ command_.read_buffer = reinterpret_cast<binder_uintptr_t>(&read_tx_);
+
+ sealed_ = true;
+ }
+
+ bool sealed_;
+
+ std::vector<uint8_t> write_buffer_;
+ std::vector<uint8_t> read_buffer_;
+
+ struct binder_write_read command_;
+ TransactionBuffer write_tx_;
+ TransactionBuffer read_tx_;
+};
+
+class Channel2 {
+ public:
+ Channel2(const std::string& interface)
+ : interface_(interface),
+ fd_(ConnectDriver()) {
+ }
+ ~Channel2() {}
+
+ Transaction* NewTransaction(uint32_t code) const {
+ Transaction* t = new Transaction();
+ t->write_tx_.data.code = code;
+ t->WriteString8(interface());
+ return t;
+ }
+
+ int ExecuteTransaction(Transaction* tx) {
+ tx->Seal();
+ int rv = ioctl(fd_, BINDER_WRITE_READ, &tx->command_);
+ ALOG("BINDER_WRITE_READ: %d", rv);
+ if (rv) {
+ AERR("BINDER_WRITE_READ");
+ }
+
+ for (size_t i = 0; i < tx->read_buffer_.size(); i += 4) {
+ ALOG("%0x %0x %0x %0x", tx->read_buffer_[i], tx->read_buffer_[i+1], tx->read_buffer_[i+2], tx->read_buffer_[i+3]);
+ }
+ }
+
+ const std::string& interface() const { return interface_; }
+
+ private:
+ const std::string interface_;
+ int fd_;
+};
+
+Channel* LookupService(const std::string& name) {
+ Parcel data;
+ data.WriteInterfaceToken("android.os.IServiceManager");
+ data.WriteUTF8(name);
+
+ Channel channel(0);
+
+ TransactionCommand command(TransactionCommand::TWO_WAY);
+ command.SetHandle(channel.handle());
+ command.SetCode(2 /*CHECK_SERVICE_TRANSACTION*/);
+ command.SetParcel(data);
+
+ channel.QueueCommand(&command);
+ channel.TransactCommands();
+ channel.reader()->Print();
+
+#if 0
+ Channel2* ch = new Channel2("android.os.IServiceManager");
+ Transaction* tx = ch->NewTransaction(2 /*CHECK_SERVICE_TRANSACTION*/);
+ tx->WriteString8(name);
+ ch->ExecuteTransaction(tx);
+#endif
+}
+
+} // namespace minibind