This does not yet receive transactions correctly.
--- /dev/null
+TOP_DIR := $(call my-dir)
+
+include $(TOP_DIR)/minibind/Android.mk
--- /dev/null
+APP_STL := stlport_static
+APP_CPPFLAGS := -std=gnu++11
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := minibind
+LOCAL_SRC_FILES := minibind.cc parcel.cc channel.cc command.cc
+LOCAL_CFLAGS := -DBINDER_IPC_32BIT=1
+
+include $(BUILD_STATIC_LIBRARY)
--- /dev/null
+// 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 "channel.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+#include <linux/binder.h>
+
+#include "command.h"
+#include "common.h"
+
+namespace minibind {
+
+namespace {
+
+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;
+}
+
+void CopyCommandsToBuffer(const std::vector<Command*>& commands,
+ std::vector<unsigned char>* buffer) {
+ size_t last_command_size = 0;
+ for (const Command* command : commands) {
+ memcpy(&(*buffer)[last_command_size], reinterpret_cast<void*>(command->GetData()), command->GetSize());
+ last_command_size += command->GetSize();
+ }
+}
+
+} // namespace
+
+Channel::Channel(uint32_t handle)
+ : handle_(handle),
+ driver_(ConnectDriver()),
+ write_commands_size_(0),
+ write_commands_(),
+ reader_() {
+ reader_.SetDataSize(256);
+}
+
+Channel::~Channel() {
+}
+
+void Channel::QueueCommand(Command* cmd) {
+ write_commands_size_ += cmd->GetSize();
+ write_commands_.push_back(cmd);
+}
+
+int Channel::TransactCommands() {
+ struct binder_write_read bwr = {};
+
+ std::vector<unsigned char> write_data(write_commands_size_, 0);
+ CopyCommandsToBuffer(write_commands_, &write_data);
+
+ bwr.write_size = write_commands_size_;
+ bwr.write_buffer = reinterpret_cast<binder_uintptr_t>(&write_data[0]);
+ bwr.read_size = reader_.DataSize();
+ bwr.read_buffer = reader_.DataPointer();
+
+ int rv = ioctl(driver_, BINDER_WRITE_READ, &bwr);
+ ALOG("BINDER_WRITE_READ %d", rv);
+ return rv;
+}
+
+} // namespace minibind
--- /dev/null
+// 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.
+
+#ifndef MINIBIND_CHANNEL_H_
+#define MINIBIND_CHANNEL_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "parcel.h"
+
+namespace minibind {
+
+class Command;
+
+class Channel {
+ public:
+ explicit Channel(uint32_t handle);
+ ~Channel();
+
+ void QueueCommand(Command* cmd);
+
+ int TransactCommands();
+
+ Parcel* reader() { return &reader_; }
+
+ uint32_t handle() const { return handle_; }
+ const std::vector<Command*>& write_commands() const { return write_commands_; }
+
+ private:
+ uint32_t handle_;
+ int driver_;
+
+ Parcel reader_;
+
+ size_t write_commands_size_;
+ std::vector<Command*> write_commands_;
+};
+
+} // namespace minibind
+
+#endif // MINIBIND_CHANNEL_H_
--- /dev/null
+// 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 "command.h"
+
+#include "common.h"
+#include "parcel.h"
+
+namespace minibind {
+
+TransactionCommand::TransactionCommand(TransactionCommand::Type type)
+ : command_(type == TWO_WAY ? BC_TRANSACTION : BC_REPLY) {
+}
+
+TransactionCommand::~TransactionCommand() {}
+
+void TransactionCommand::SetCode(uint32_t code) {
+ transaction_.code = code;
+}
+
+void TransactionCommand::SetHandle(uint32_t handle) {
+ transaction_.target.handle = handle;
+}
+
+void TransactionCommand::SetParcel(const Parcel& parcel) {
+ transaction_.data_size = parcel.DataSize();
+ transaction_.data.ptr.buffer = parcel.DataPointer();
+}
+
+size_t TransactionCommand::GetSize() const {
+ return sizeof(command_) + sizeof(transaction_);
+}
+
+binder_uintptr_t TransactionCommand::GetData() const {
+ return reinterpret_cast<binder_uintptr_t>(&command_);
+}
+
+} // namespace minibind
--- /dev/null
+// 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.
+
+#ifndef MINIBIND_COMMAND_H_
+#define MINIBIND_COMAMND_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <linux/binder.h>
+
+#include "common.h"
+
+namespace minibind {
+
+class Parcel;
+
+class Command {
+ public:
+ virtual size_t GetSize() const = 0;
+ virtual binder_uintptr_t GetData() const = 0;
+
+ protected:
+ ~Command() {}
+};
+
+class TransactionCommand : public Command {
+ public:
+ enum Type {
+ TWO_WAY,
+ REPLY_ASYNC,
+ };
+
+ TransactionCommand(Type type);
+ ~TransactionCommand();
+
+ void SetHandle(uint32_t handle);
+ void SetCode(uint32_t code);
+ void SetParcel(const Parcel& parcel);
+
+ // Command:
+ size_t GetSize() const override;
+ binder_uintptr_t GetData() const override;
+
+ private:
+ const binder_driver_command_protocol command_;
+ struct binder_transaction_data transaction_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransactionCommand);
+};
+
+} // namespace minibind
+
+#endif // MINIBIND_COMAMND_H_
--- /dev/null
+// 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.
+
+#ifndef MINIBIND_COMMON_H_
+
+#include <android/log.h>
+#include <errno.h>
+
+#define ALOG(...) __android_log_print(ANDROID_LOG_WARN, "minibind", __VA_ARGS__)
+
+#define AERR(msg) ALOG(msg ": %s", strerror(errno))
+
+#define CHECK(cond) if (!(cond)) { ALOG("ASSERTION FAILURE: %s @ %s:%d", #cond, __FILE__, __LINE__ ); abort(); }
+
+#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+
+#define DISALLOW_COPY_AND_ASSIGN(cls) cls(const cls&) = delete
+
+#endif // MINIBIND_COMMON_H_
--- /dev/null
+// 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
--- /dev/null
+// 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.
+
+#ifndef MINIBIND_MINIBIND_H_
+#define MINIBIND_MINIBIND_H_
+
+#include <string>
+
+namespace minibind {
+
+class Channel;
+
+Channel* LookupService(const std::string& name);
+
+} // namespace minibind
+
+#endif // MINIBIND_MINIBIND_H_
--- /dev/null
+// 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 "parcel.h"
+
+#include "common.h"
+
+namespace minibind {
+
+Parcel::Parcel() : data_(), objects_() {}
+
+Parcel::~Parcel() {}
+
+void Parcel::WriteInterfaceToken(const std::string& str) {
+ WriteUTF8(str);
+}
+
+void Parcel::WriteUTF8(const std::string& str) {
+ data_.insert(data_.end(), str.begin(), str.end());
+}
+
+void Parcel::WriteUInt32(uint32_t ui32) {
+ data_.push_back((ui32 >> 24) & 0xff);
+ data_.push_back((ui32 >> 16) & 0xff);
+ data_.push_back((ui32 >> 8) & 0xff);
+ data_.push_back((ui32 >> 0) & 0xff);
+}
+
+binder_uintptr_t Parcel::DataPointer() const {
+ return reinterpret_cast<binder_uintptr_t>(&data_[0]);
+}
+
+size_t Parcel::DataSize() const {
+ return 0;
+}
+
+void Parcel::SetDataSize(size_t size) {
+ // TODO: handle object lifetimes
+ CHECK(size % 4 == 0);
+ data_.resize(size);
+}
+
+void Parcel::Print() const {
+ for (size_t i = 0; i < data_.size(); i += 4) {
+ ALOG("%0x %0x %0x %0x", data_[i], data_[i+1], data_[i+2], data_[i+3]);
+ }
+}
+
+} // namespace minibind
--- /dev/null
+// 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.
+
+#ifndef MINIBIND_PARCEL_H_
+#define MINIBIND_PARCEL_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <linux/binder.h>
+
+#include <string>
+#include <vector>
+
+namespace minibind {
+
+class Parcel {
+ public:
+ Parcel();
+ ~Parcel();
+
+ void WriteInterfaceToken(const std::string& str);
+ void WriteUTF8(const std::string& str);
+ void WriteUInt32(uint32_t ui32);
+
+ binder_uintptr_t DataPointer() const;
+ size_t DataSize() const;
+ void SetDataSize(size_t size);
+
+ void Print() const;
+
+ private:
+ std::vector<uint8_t> data_;
+ std::vector<struct flat_binder_object> objects_;
+};
+
+} // namespace minibind
+
+#endif // MINIBIND_PARCEL_H_