First cut at minibind classes.
authorRobert Sesek <rsesek@chromium.org>
Thu, 22 Jan 2015 01:15:01 +0000 (20:15 -0500)
committerRobert Sesek <rsesek@chromium.org>
Thu, 22 Jan 2015 01:15:01 +0000 (20:15 -0500)
This does not yet receive transactions correctly.

13 files changed:
.gitignore
jni/Android.mk [new file with mode: 0644]
jni/Application.mk [new file with mode: 0644]
jni/minibind/Android.mk [new file with mode: 0644]
jni/minibind/channel.cc [new file with mode: 0644]
jni/minibind/channel.h [new file with mode: 0644]
jni/minibind/command.cc [new file with mode: 0644]
jni/minibind/command.h [new file with mode: 0644]
jni/minibind/common.h [new file with mode: 0644]
jni/minibind/minibind.cc [new file with mode: 0644]
jni/minibind/minibind.h [new file with mode: 0644]
jni/minibind/parcel.cc [new file with mode: 0644]
jni/minibind/parcel.h [new file with mode: 0644]

index 639cdd514dfe53459746aa0ffc6ebea3e7e39714..15cd4ea9be20a5520c770d2b8c87360a585bdaf3 100644 (file)
@@ -1 +1,2 @@
 local.properties
+obj/
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644 (file)
index 0000000..9494502
--- /dev/null
@@ -0,0 +1,3 @@
+TOP_DIR := $(call my-dir)
+
+include $(TOP_DIR)/minibind/Android.mk
diff --git a/jni/Application.mk b/jni/Application.mk
new file mode 100644 (file)
index 0000000..637619b
--- /dev/null
@@ -0,0 +1,2 @@
+APP_STL := stlport_static
+APP_CPPFLAGS := -std=gnu++11
diff --git a/jni/minibind/Android.mk b/jni/minibind/Android.mk
new file mode 100644 (file)
index 0000000..83ab355
--- /dev/null
@@ -0,0 +1,9 @@
+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)
diff --git a/jni/minibind/channel.cc b/jni/minibind/channel.cc
new file mode 100644 (file)
index 0000000..97f7b67
--- /dev/null
@@ -0,0 +1,96 @@
+// 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
diff --git a/jni/minibind/channel.h b/jni/minibind/channel.h
new file mode 100644 (file)
index 0000000..bbd8004
--- /dev/null
@@ -0,0 +1,44 @@
+// 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_
diff --git a/jni/minibind/command.cc b/jni/minibind/command.cc
new file mode 100644 (file)
index 0000000..d6f060d
--- /dev/null
@@ -0,0 +1,39 @@
+// 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
diff --git a/jni/minibind/command.h b/jni/minibind/command.h
new file mode 100644 (file)
index 0000000..1f2019f
--- /dev/null
@@ -0,0 +1,55 @@
+// 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_
diff --git a/jni/minibind/common.h b/jni/minibind/common.h
new file mode 100644 (file)
index 0000000..2384af9
--- /dev/null
@@ -0,0 +1,20 @@
+// 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_
diff --git a/jni/minibind/minibind.cc b/jni/minibind/minibind.cc
new file mode 100644 (file)
index 0000000..0feb8e8
--- /dev/null
@@ -0,0 +1,181 @@
+// 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
diff --git a/jni/minibind/minibind.h b/jni/minibind/minibind.h
new file mode 100644 (file)
index 0000000..019159f
--- /dev/null
@@ -0,0 +1,18 @@
+// 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_
diff --git a/jni/minibind/parcel.cc b/jni/minibind/parcel.cc
new file mode 100644 (file)
index 0000000..7cf419d
--- /dev/null
@@ -0,0 +1,50 @@
+// 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
diff --git a/jni/minibind/parcel.h b/jni/minibind/parcel.h
new file mode 100644 (file)
index 0000000..f7718f5
--- /dev/null
@@ -0,0 +1,40 @@
+// 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_