abort();
}
+#define BINDER_RP(br) ALOG("return_proto: %s: %d (0x%x)", #br, br, br)
+ BINDER_RP(BR_ERROR);
+ BINDER_RP(BR_OK);
+ BINDER_RP(BR_TRANSACTION);
+ BINDER_RP(BR_REPLY);
+ BINDER_RP(BR_ACQUIRE_RESULT);
+ BINDER_RP(BR_DEAD_REPLY);
+ BINDER_RP(BR_TRANSACTION_COMPLETE);
+ BINDER_RP(BR_INCREFS);
+ BINDER_RP(BR_ACQUIRE);
+ BINDER_RP(BR_RELEASE);
+ BINDER_RP(BR_DECREFS);
+ BINDER_RP(BR_ATTEMPT_ACQUIRE);
+ BINDER_RP(BR_NOOP);
+ BINDER_RP(BR_SPAWN_LOOPER);
+ BINDER_RP(BR_FINISHED);
+ BINDER_RP(BR_DEAD_BINDER);
+ BINDER_RP(BR_CLEAR_DEATH_NOTIFICATION_DONE);
+ BINDER_RP(BR_FAILED_REPLY);
+
return fd;
}
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::Call(uint32_t code, const Parcel& in, Parcel* out) {
+ reader_.SetDataPosition(0);
-int Channel::TransactCommands() {
struct binder_write_read bwr = {};
- std::vector<unsigned char> write_data(write_commands_size_, 0);
- CopyCommandsToBuffer(write_commands_, &write_data);
+ TransactionCommand command(TransactionCommand::TWO_WAY);
+ command.SetHandle(handle());
+ command.SetCode(code);
+ command.SetParcel(in);
- bwr.write_size = write_commands_size_;
- bwr.write_buffer = reinterpret_cast<binder_uintptr_t>(&write_data[0]);
+ bwr.write_size = command.GetSize();
+ bwr.write_buffer = command.GetData();
bwr.read_size = reader_.DataSize();
bwr.read_buffer = reader_.DataPointer();
int rv = ioctl(driver_, BINDER_WRITE_READ, &bwr);
- ALOG("BINDER_WRITE_READ %d", rv);
+ ALOG("BINDER_WRITE_READ %d (written %d/%d, read %d/%d)", rv, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);
return rv;
}
#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"
namespace minibind {
-int ConnectDriver() {
- int fd = open("/dev/binder", O_RDONLY);
- if (fd < 0) {
- AERR("open driver");
- abort();
- }
+namespace {
- if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
- AERR("fcntl FD_CLOEXEC");
- }
+Channel* GetServiceManager() {
+ static Channel* service_manager = nullptr;
+ if (!service_manager) {
+ service_manager = new Channel(0);
- 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();
+ Parcel in, out;
+ service_manager->Call(Channel::PING_TRANSACTION, in, &out);
+ service_manager->reader()->Print();
}
- 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;
+ return service_manager;
}
-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_;
-};
+} // namespace
Channel* LookupService(const std::string& name) {
Parcel data;
data.WriteInterfaceToken("android.os.IServiceManager");
data.WriteUTF8(name);
- Channel channel(0);
+ Parcel reply;
- TransactionCommand command(TransactionCommand::TWO_WAY);
- command.SetHandle(channel.handle());
- command.SetCode(2 /*CHECK_SERVICE_TRANSACTION*/);
- command.SetParcel(data);
+ Channel* channel = GetServiceManager();
+ channel->Call(2 /*CHECK_SERVICE_TRANSACTION*/, data, &reply);
- channel.QueueCommand(&command);
- channel.TransactCommands();
- channel.reader()->Print();
+ 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
+ uint32_t cmd = 0;
+ CHECK(channel->reader()->ReadUInt32(&cmd));
+ ALOG("Got command: %x (dec %d %u)", cmd, cmd, cmd);
+ CHECK(channel->reader()->ReadUInt32(&cmd));
+ ALOG("Got command: %x (dec %d %u)", cmd, cmd, cmd);
}
} // namespace minibind
namespace minibind {
-Parcel::Parcel() : data_(), objects_() {}
+Parcel::Parcel() : data_position_(0), data_(), objects_() {}
Parcel::~Parcel() {}
data_.push_back((ui32 >> 0) & 0xff);
}
+bool Parcel::ReadUInt32(uint32_t* ui32) {
+ return ReadBytes(sizeof(*ui32), ui32);
+}
+
+bool Parcel::ReadBytes(size_t count, void* buffer) {
+ // TODO: overflow
+ ALOG("count=%d, data_position_=%d, datasize=%d", count, data_position_, DataSize());
+ if (count + data_position_ >= DataSize())
+ return false;
+
+ memcpy(buffer, &data_[data_position_], count);
+ data_position_ += count;
+ return true;
+}
+
binder_uintptr_t Parcel::DataPointer() const {
return reinterpret_cast<binder_uintptr_t>(&data_[0]);
}
size_t Parcel::DataSize() const {
- return 0;
+ return data_.size();
}
void Parcel::SetDataSize(size_t size) {
data_.resize(size);
}
+void Parcel::SetDataPosition(size_t pos) {
+ CHECK(pos < DataSize());
+ data_position_ = pos;
+}
+
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]);