Commit 41f33787 authored by Etienne Pierre-Doray's avatar Etienne Pierre-Doray Committed by Commit Bot

Remove chromeos/binder/ directory since it's unused.

Original CL intention was:
This CL uses ScopedBlockingCall to mark blocking calls in /chromeos/binder.

This CL was created by replacing calls to AssertBlockingAllowed()
with instantiations of ScopedBlockingCall(MAY_BLOCK).
I kindly ask the reviewer to make sure of the following:
  - ScopedBlockingCall is instantiated in a scope with minimal CPU usage.
    If this is not the case, ScopedBlockingCall should be instantiated
    closer to the blocking call. See scoped_blocking_call.h for more
    info. Please let me know when/where the blocking call happens if this needs
    to be changed.
  - Parameter |blocking_type| matches expectation (MAY_BLOCK/WILL_BLOCK). See
    BlockingType for more info. While I assumed MAY_BLOCK by default, that might
    not be the best fit if we know that this callsite is guaranteed to block.
  - The ScopedBlockingCall's scope covers the entirety of the blocking operation
    previously asserted against by the AssertBlockingAllowed().

This CL was uploaded by git cl split.

R=satorux@chromium.org

Bug: 874080
Change-Id: Ia8c04385530dbaefee972c8ebffc46c1ec627aa3
Reviewed-on: https://chromium-review.googlesource.com/1191246
Commit-Queue: Etienne Pierre-Doray <etiennep@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592786}
parent 03c1a559
...@@ -10,11 +10,6 @@ import("//third_party/protobuf/proto_library.gni") ...@@ -10,11 +10,6 @@ import("//third_party/protobuf/proto_library.gni")
assert(is_chromeos, "Non-ChromeOS builds must not depend on //chromeos") assert(is_chromeos, "Non-ChromeOS builds must not depend on //chromeos")
declare_args() {
# Use binder. Binder related code is compiled only when true.
use_binder = false
}
component("chromeos") { component("chromeos") {
configs += [ "//build/config/linux/nss:system_nss_no_ssl_config" ] configs += [ "//build/config/linux/nss:system_nss_no_ssl_config" ]
public_deps = [ public_deps = [
...@@ -84,36 +79,6 @@ component("chromeos") { ...@@ -84,36 +79,6 @@ component("chromeos") {
"audio/chromeos_sounds.h", "audio/chromeos_sounds.h",
"audio/cras_audio_handler.cc", "audio/cras_audio_handler.cc",
"audio/cras_audio_handler.h", "audio/cras_audio_handler.h",
"binder/buffer_reader.cc",
"binder/buffer_reader.h",
"binder/command_broker.cc",
"binder/command_broker.h",
"binder/command_stream.cc",
"binder/command_stream.h",
"binder/constants.h",
"binder/driver.cc",
"binder/driver.h",
"binder/ipc_thread.cc",
"binder/ipc_thread.h",
"binder/local_object.cc",
"binder/local_object.h",
"binder/object.h",
"binder/remote_object.cc",
"binder/remote_object.h",
"binder/service_manager_proxy.cc",
"binder/service_manager_proxy.h",
"binder/status.h",
"binder/transaction_data.h",
"binder/transaction_data_from_driver.cc",
"binder/transaction_data_from_driver.h",
"binder/transaction_data_reader.cc",
"binder/transaction_data_reader.h",
"binder/transaction_status.cc",
"binder/transaction_status.h",
"binder/util.cc",
"binder/util.h",
"binder/writable_transaction_data.cc",
"binder/writable_transaction_data.h",
"cert_loader.cc", "cert_loader.cc",
"cert_loader.h", "cert_loader.h",
"chromeos_constants.cc", "chromeos_constants.cc",
...@@ -779,22 +744,6 @@ test("chromeos_unittests") { ...@@ -779,22 +744,6 @@ test("chromeos_unittests") {
"tools/variable_expander_unittest.cc", "tools/variable_expander_unittest.cc",
"tpm/tpm_token_info_getter_unittest.cc", "tpm/tpm_token_info_getter_unittest.cc",
] ]
if (use_binder) {
if (current_cpu == "arm" || current_cpu == "x86") {
defines += [ "BINDER_IPC_32BIT" ]
}
sources += [
"binder/buffer_reader_unittest.cc",
"binder/command_broker_unittest.cc",
"binder/command_stream_unittest.cc",
"binder/driver_unittest.cc",
"binder/end_to_end_unittest.cc",
"binder/service_manager_proxy_unittest.cc",
"binder/test_service.cc",
"binder/test_service.h",
"binder/transaction_data_read_write_unittest.cc",
]
}
data = [ data = [
"test/data/", "test/data/",
......
include_rules = [
"+chromeos/third_party/android_bionic_libc",
]
hashimoto@chromium.org
satorux@chromium.org
// Copyright 2016 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 this header for types and constants used by the kernel binder driver.
#ifndef CHROMEOS_BINDER_BINDER_DRIVER_API_H_
#define CHROMEOS_BINDER_BINDER_DRIVER_API_H_
// binder.h needs __packed to be defined.
#define __packed __attribute__((__packed__))
#include <asm/types.h>
#include "chromeos/third_party/android_bionic_libc/kernel/uapi/linux/binder.h"
#endif // CHROMEOS_BINDER_BINDER_DRIVER_API_H_
// 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 "chromeos/binder/buffer_reader.h"
#include <string.h>
namespace binder {
BufferReader::BufferReader(const char* data, size_t size)
: data_(data), size_(size), current_(data) {}
BufferReader::~BufferReader() = default;
bool BufferReader::HasMoreData() const {
return current_ < data_ + size_;
}
bool BufferReader::Read(void* out, size_t num_bytes) {
if (current_ + num_bytes > data_ + size_)
return false;
memcpy(out, current_, num_bytes);
current_ += num_bytes;
return true;
}
bool BufferReader::Skip(size_t num_bytes) {
if (current_ + num_bytes > data_ + size_)
return false;
current_ += num_bytes;
return true;
}
} // namespace binder
// 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 CHROMEOS_BINDER_BUFFER_READER_H_
#define CHROMEOS_BINDER_BUFFER_READER_H_
#include <stddef.h>
#include "base/macros.h"
#include "chromeos/chromeos_export.h"
namespace binder {
// BufferReader reads data from the given buffer.
class CHROMEOS_EXPORT BufferReader {
public:
BufferReader(const char* data, size_t size);
~BufferReader();
const char* data() const { return data_; }
size_t size() const { return size_; }
const char* current() const { return current_; }
// Returns true when there is some data to read.
bool HasMoreData() const;
// Copies the specified number of bytes from the buffer to |out|.
// |out| shouldn't overlap with |data_|.
bool Read(void* out, size_t num_bytes);
// Moves the position |num_bytes| forward.
bool Skip(size_t num_bytes);
private:
const char* data_;
size_t size_;
const char* current_;
DISALLOW_COPY_AND_ASSIGN(BufferReader);
};
} // namespace binder
#endif // CHROMEOS_BINDER_BUFFER_READER_H_
// 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 <stddef.h>
#include "chromeos/binder/buffer_reader.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
TEST(BinderBufferReaderTest, Read) {
// Prepare data.
const size_t N = 4;
int data[N];
for (size_t i = 0; i < N; ++i) {
data[i] = i + 100;
}
// Read.
BufferReader reader(reinterpret_cast<char*>(data), sizeof(data));
for (size_t i = 0; i < N; ++i) {
SCOPED_TRACE(i);
EXPECT_TRUE(reader.HasMoreData());
int value = 0;
EXPECT_TRUE(reader.Read(&value, sizeof(value)));
EXPECT_EQ(data[i], value);
}
EXPECT_FALSE(reader.HasMoreData());
// No longer able to read.
int value = 0;
EXPECT_FALSE(reader.Read(&value, sizeof(value)));
}
TEST(BinderBufferReaderTest, Skip) {
// Prepare data.
const size_t N = 4;
int data[N];
for (size_t i = 0; i < N; ++i) {
data[i] = i + 100;
}
// Skip the first and read the rest.
BufferReader reader(reinterpret_cast<char*>(data), sizeof(data));
EXPECT_TRUE(reader.HasMoreData());
EXPECT_TRUE(reader.Skip(sizeof(data[0])));
for (size_t i = 1; i < N; ++i) {
SCOPED_TRACE(i);
EXPECT_TRUE(reader.HasMoreData());
int value = 0;
EXPECT_TRUE(reader.Read(&value, sizeof(value)));
EXPECT_EQ(data[i], value);
}
EXPECT_FALSE(reader.HasMoreData());
// No longer able to skip.
EXPECT_FALSE(reader.Skip(sizeof(data[0])));
}
} // namespace binder
// 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 "chromeos/binder/command_broker.h"
#include <stddef.h>
#include <stdint.h>
#include "base/bind.h"
#include "base/logging.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/transaction_status.h"
namespace binder {
namespace {
// Converts TransactionData to binder_transaction_data struct.
binder_transaction_data ConvertTransactionDataToStruct(
const TransactionData& data) {
binder_transaction_data result = {};
result.code = data.GetCode();
result.flags = TF_ACCEPT_FDS;
if (data.IsOneWay()) {
result.flags |= TF_ONE_WAY;
}
if (data.HasStatus()) {
result.flags |= TF_STATUS_CODE;
}
result.data_size = data.GetDataSize();
result.data.ptr.buffer = reinterpret_cast<binder_uintptr_t>(data.GetData());
result.offsets_size = data.GetNumObjectOffsets() * sizeof(binder_size_t);
result.data.ptr.offsets =
reinterpret_cast<binder_uintptr_t>(data.GetObjectOffsets());
return result;
}
} // namespace
CommandBroker::CommandBroker(Driver* driver)
: command_stream_(driver, this), weak_ptr_factory_(this) {}
CommandBroker::~CommandBroker() {
DCHECK(thread_checker_.CalledOnValidThread());
}
bool CommandBroker::EnterLooper() {
command_stream_.AppendOutgoingCommand(BC_ENTER_LOOPER, nullptr, 0);
return command_stream_.Flush();
}
bool CommandBroker::RegisterLooper() {
command_stream_.AppendOutgoingCommand(BC_REGISTER_LOOPER, nullptr, 0);
return command_stream_.Flush();
}
bool CommandBroker::ExitLooper() {
command_stream_.AppendOutgoingCommand(BC_EXIT_LOOPER, nullptr, 0);
return command_stream_.Flush();
}
bool CommandBroker::PollCommands() {
// Fetch and process commands.
if (!command_stream_.Fetch()) {
LOG(ERROR) << "Failed to fetch commands.";
return false;
}
while (command_stream_.CanProcessIncomingCommand()) {
if (!command_stream_.ProcessIncomingCommand()) {
LOG(ERROR) << "Failed to process command.";
return false;
}
}
// Flush outgoing commands.
if (!command_stream_.Flush()) {
LOG(ERROR) << "Failed to flush commands.";
return false;
}
return true;
}
bool CommandBroker::Transact(int32_t handle,
const TransactionData& request,
std::unique_ptr<TransactionData>* reply) {
DCHECK(thread_checker_.CalledOnValidThread());
// Send transaction.
binder_transaction_data tr = ConvertTransactionDataToStruct(request);
tr.target.handle = handle;
command_stream_.AppendOutgoingCommand(BC_TRANSACTION, &tr, sizeof(tr));
if (!command_stream_.Flush()) {
LOG(ERROR) << "Failed to write";
return false;
}
// Wait for response.
std::unique_ptr<TransactionData> response_data;
ResponseType response_type = WaitForResponse(&response_data);
if (response_type != RESPONSE_TYPE_TRANSACTION_COMPLETE) {
LOG(ERROR) << "Failed to wait for response: response_type = "
<< response_type;
return false;
}
if (!request.IsOneWay()) {
// Wait for reply.
std::unique_ptr<TransactionData> response_data;
ResponseType response_type = WaitForResponse(&response_data);
if (response_type != RESPONSE_TYPE_TRANSACTION_REPLY) {
LOG(ERROR) << "Failed to wait for response: response_type = "
<< response_type;
return false;
}
*reply = std::move(response_data);
}
return true;
}
void CommandBroker::AddReference(int32_t handle) {
// Increment weak reference count.
command_stream_.AppendOutgoingCommand(BC_INCREFS, &handle, sizeof(handle));
// Increment strong reference count.
command_stream_.AppendOutgoingCommand(BC_ACQUIRE, &handle, sizeof(handle));
}
void CommandBroker::ReleaseReference(int32_t handle) {
// Decrement strong reference count.
command_stream_.AppendOutgoingCommand(BC_RELEASE, &handle, sizeof(handle));
// Decrement weak reference count.
command_stream_.AppendOutgoingCommand(BC_DECREFS, &handle, sizeof(handle));
}
base::Closure CommandBroker::GetReleaseReferenceClosure(int32_t handle) {
return base::Bind(&CommandBroker::ReleaseReference,
weak_ptr_factory_.GetWeakPtr(), handle);
}
bool CommandBroker::OnTransaction(const TransactionData& data) {
LocalObject* object = reinterpret_cast<LocalObject*>(data.GetCookie());
std::unique_ptr<TransactionData> reply;
if (!object->Transact(this, data, &reply)) {
LOG(ERROR) << "Failed to transact.";
return false;
}
if (!data.IsOneWay()) {
// Send reply.
if (!reply) {
reply.reset(new TransactionStatus(Status::FAILED_TRANSACTION));
}
binder_transaction_data tr = ConvertTransactionDataToStruct(*reply);
tr.target.handle = -1; // This value will be ignored. Set invalid handle.
command_stream_.AppendOutgoingCommand(BC_REPLY, &tr, sizeof(tr));
if (!command_stream_.Flush()) {
LOG(ERROR) << "Failed to write";
return false;
}
std::unique_ptr<TransactionData> response_data;
ResponseType response_type = WaitForResponse(&response_data);
// Not returning false for errors here, as doing it can result in letting
// another process abort the loop in PollCommands() (e.g. any process can
// cause a "dead binder" error with crash). We should return false only for
// fundamental errors like binder protocol errors.
LOG_IF(ERROR, response_type != RESPONSE_TYPE_TRANSACTION_COMPLETE)
<< "Error on the other end when sending reply: " << response_type;
}
return true;
}
void CommandBroker::OnReply(std::unique_ptr<TransactionData> data) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE);
DCHECK(!response_data_);
response_type_ = RESPONSE_TYPE_TRANSACTION_REPLY;
response_data_ = std::move(data);
}
void CommandBroker::OnDeadReply() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE);
response_type_ = RESPONSE_TYPE_DEAD;
}
void CommandBroker::OnTransactionComplete() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE);
response_type_ = RESPONSE_TYPE_TRANSACTION_COMPLETE;
}
void CommandBroker::OnIncrementWeakReference(void* ptr, void* cookie) {
// Do nothing.
}
void CommandBroker::OnIncrementStrongReference(void* ptr, void* cookie) {
reinterpret_cast<LocalObject*>(cookie)->AddRef();
}
void CommandBroker::OnDecrementStrongReference(void* ptr, void* cookie) {
reinterpret_cast<LocalObject*>(cookie)->Release();
}
void CommandBroker::OnDecrementWeakReference(void* ptr, void* cookie) {
// Do nothing.
}
void CommandBroker::OnFailedReply() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE);
response_type_ = RESPONSE_TYPE_FAILED;
}
CommandBroker::ResponseType CommandBroker::WaitForResponse(
std::unique_ptr<TransactionData>* data) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE);
DCHECK(!response_data_);
while (response_type_ == RESPONSE_TYPE_NONE) {
if (command_stream_.CanProcessIncomingCommand()) {
if (!command_stream_.ProcessIncomingCommand()) {
LOG(ERROR) << "Failed to process command.";
return RESPONSE_TYPE_NONE;
}
} else {
// Block until response is received.
if (!command_stream_.FetchBlocking()) {
LOG(ERROR) << "Failed to fetch.";
return RESPONSE_TYPE_NONE;
}
}
}
ResponseType response_type = response_type_;
response_type_ = RESPONSE_TYPE_NONE;
*data = std::move(response_data_);
return response_type;
}
} // namespace binder
// 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 CHROMEOS_BINDER_COMMAND_BROKER_H_
#define CHROMEOS_BINDER_COMMAND_BROKER_H_
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "chromeos/binder/command_stream.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class Driver;
class TransactionData;
// Issues appropriate outgoing commands to perform required tasks, and
// dispatches incoming commands to appropriate objects.
// Usually this class lives as long as the corresponding thread.
// TODO(hashimoto): Add code to handle incoming commands (e.g. transactions).
class CHROMEOS_EXPORT CommandBroker
: public CommandStream::IncomingCommandHandler {
public:
explicit CommandBroker(Driver* driver);
~CommandBroker() override;
// Tells the driver that the current thread entered command handling loop.
// Returns true on success.
// This method must be used by the main thread which owns the Driver instance,
// sub threads should use RegisterLooper().
bool EnterLooper();
// Tells the driver that the current thread entered command handling loop.
// Returns true on success.
// This method must be used by sub threads, the main thread should use
// EnterLooper().
bool RegisterLooper();
// Tells the driver that the current thread exited command handling loop.
// Returns true on success.
bool ExitLooper();
// Fetches incoming commands and handles them.
// Returns true on success.
bool PollCommands();
// Performs transaction with the remote object specified by the handle.
// Returns true on success. If not one-way transaction, this method blocks
// until the target object sends a reply.
bool Transact(int32_t handle,
const TransactionData& request,
std::unique_ptr<TransactionData>* reply);
// Increments the ref-count of a remote object specified by |handle|.
void AddReference(int32_t handle);
// Decrements the ref-count of a remote object specified by |handle|.
void ReleaseReference(int32_t handle);
// Returns a closure which decrements the ref-count of a remote object.
// It's safe to run the returned closure even after the destruction of this
// object.
base::Closure GetReleaseReferenceClosure(int32_t handle);
// CommandStream::IncomingCommandHandler override:
bool OnTransaction(const TransactionData& data) override;
void OnReply(std::unique_ptr<TransactionData> data) override;
void OnDeadReply() override;
void OnTransactionComplete() override;
void OnIncrementWeakReference(void* ptr, void* cookie) override;
void OnIncrementStrongReference(void* ptr, void* cookie) override;
void OnDecrementStrongReference(void* ptr, void* cookie) override;
void OnDecrementWeakReference(void* ptr, void* cookie) override;
void OnFailedReply() override;
private:
enum ResponseType {
RESPONSE_TYPE_NONE,
RESPONSE_TYPE_TRANSACTION_COMPLETE,
RESPONSE_TYPE_TRANSACTION_REPLY,
RESPONSE_TYPE_FAILED,
RESPONSE_TYPE_DEAD,
};
// Waits for a response to the previous transaction.
ResponseType WaitForResponse(std::unique_ptr<TransactionData>* data);
base::ThreadChecker thread_checker_;
CommandStream command_stream_;
ResponseType response_type_ = RESPONSE_TYPE_NONE;
std::unique_ptr<TransactionData> response_data_;
base::WeakPtrFactory<CommandBroker> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CommandBroker);
};
} // namespace binder
#endif // CHROMEOS_BINDER_COMMAND_BROKER_H_
// 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 "base/message_loop/message_loop.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/binder/constants.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/writable_transaction_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
class BinderCommandBrokerTest : public ::testing::Test {
public:
BinderCommandBrokerTest() : command_broker_(&driver_) {}
~BinderCommandBrokerTest() override {}
void SetUp() override { ASSERT_TRUE(driver_.Initialize()); }
protected:
base::MessageLoop message_loop_;
Driver driver_;
CommandBroker command_broker_;
};
TEST_F(BinderCommandBrokerTest, Transact) {
WritableTransactionData data;
data.SetCode(kPingTransactionCode);
std::unique_ptr<TransactionData> reply;
EXPECT_TRUE(command_broker_.Transact(kContextManagerHandle, data, &reply));
ASSERT_TRUE(reply);
EXPECT_FALSE(reply->HasStatus()); // No error.
}
} // namespace binder
// 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 "chromeos/binder/command_stream.h"
#include <stddef.h>
#include <stdint.h>
#include "base/bind.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/buffer_reader.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/transaction_data_from_driver.h"
#include "chromeos/binder/util.h"
namespace binder {
CommandStream::CommandStream(Driver* driver,
IncomingCommandHandler* incoming_command_handler)
: driver_(driver),
incoming_command_handler_(incoming_command_handler),
weak_ptr_factory_(this) {}
CommandStream::~CommandStream() {
DCHECK(thread_checker_.CalledOnValidThread());
}
bool CommandStream::Fetch() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!CanProcessIncomingCommand());
// Use the same value as libbinder's IPCThreadState.
const size_t kIncomingDataSize = 256;
incoming_data_.resize(kIncomingDataSize);
size_t written_bytes = 0, read_bytes = 0;
if (!driver_->WriteRead(nullptr, 0, incoming_data_.data(),
incoming_data_.size(), &written_bytes, &read_bytes)) {
LOG(ERROR) << "WriteRead() failed.";
return false;
}
incoming_data_.resize(read_bytes);
incoming_data_reader_.reset(
new BufferReader(incoming_data_.data(), incoming_data_.size()));
return true;
}
bool CommandStream::FetchBlocking() {
DCHECK(thread_checker_.CalledOnValidThread());
return driver_->Poll() && Fetch();
}
bool CommandStream::CanProcessIncomingCommand() {
DCHECK(thread_checker_.CalledOnValidThread());
return incoming_data_reader_ && incoming_data_reader_->HasMoreData();
}
bool CommandStream::ProcessIncomingCommand() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(CanProcessIncomingCommand());
uint32_t command = 0;
if (!incoming_data_reader_->Read(&command, sizeof(command)) ||
!OnIncomingCommand(command, incoming_data_reader_.get())) {
LOG(ERROR) << "Error while handling command: " << command;
return false;
}
return true;
}
void CommandStream::AppendOutgoingCommand(uint32_t command,
const void* data,
size_t size) {
DCHECK(thread_checker_.CalledOnValidThread());
VLOG(1) << "Appending " << CommandToString(command) << ", this = " << this;
DCHECK_EQ(0u, size % 4); // Must be 4-byte aligned.
outgoing_data_.insert(
outgoing_data_.end(), reinterpret_cast<const char*>(&command),
reinterpret_cast<const char*>(&command) + sizeof(command));
outgoing_data_.insert(outgoing_data_.end(),
reinterpret_cast<const char*>(data),
reinterpret_cast<const char*>(data) + size);
}
bool CommandStream::Flush() {
DCHECK(thread_checker_.CalledOnValidThread());
for (size_t pos = 0; pos < outgoing_data_.size();) {
size_t written_bytes = 0, read_bytes = 0;
if (!driver_->WriteRead(outgoing_data_.data() + pos,
outgoing_data_.size() - pos, nullptr, 0,
&written_bytes, &read_bytes)) {
LOG(ERROR) << "WriteRead() failed: pos = " << pos
<< ", size = " << outgoing_data_.size();
return false;
}
pos += written_bytes;
}
outgoing_data_.clear();
return true;
}
bool CommandStream::OnIncomingCommand(uint32_t command, BufferReader* reader) {
DCHECK(thread_checker_.CalledOnValidThread());
// TODO(hashimoto): Replace all NOTIMPLEMENTED with logic to handle incoming
// commands.
VLOG(1) << "Processing " << CommandToString(command) << ", this = " << this;
switch (command) {
case BR_ERROR: {
int32_t error = 0;
if (!reader->Read(&error, sizeof(error))) {
LOG(ERROR) << "Failed to read error code.";
return false;
}
break;
}
case BR_OK:
break;
case BR_TRANSACTION: {
TransactionDataFromDriver data(
base::Bind(&CommandStream::FreeTransactionBuffer,
weak_ptr_factory_.GetWeakPtr()));
if (!reader->Read(data.mutable_data(), sizeof(*data.mutable_data()))) {
LOG(ERROR) << "Failed to read transaction data.";
return false;
}
if (!incoming_command_handler_->OnTransaction(data)) {
LOG(ERROR) << "Failed to handle transaction.";
return false;
}
break;
}
case BR_REPLY: {
std::unique_ptr<TransactionDataFromDriver> data(
new TransactionDataFromDriver(
base::Bind(&CommandStream::FreeTransactionBuffer,
weak_ptr_factory_.GetWeakPtr())));
binder_transaction_data* data_struct = data->mutable_data();
if (!reader->Read(data_struct, sizeof(*data_struct))) {
LOG(ERROR) << "Failed to read transaction data.";
return false;
}
incoming_command_handler_->OnReply(std::move(data));
break;
}
case BR_ACQUIRE_RESULT:
// Kernel's binder.h says this is not currently supported.
NOTREACHED();
break;
case BR_DEAD_REPLY:
incoming_command_handler_->OnDeadReply();
break;
case BR_TRANSACTION_COMPLETE:
incoming_command_handler_->OnTransactionComplete();
break;
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
case BR_ATTEMPT_ACQUIRE: {
binder_ptr_cookie data = {};
if (!reader->Read(&data, sizeof(data))) {
LOG(ERROR) << "Failed to read arguments.";
return false;
}
void* ptr = reinterpret_cast<void*>(data.ptr);
void* cookie = reinterpret_cast<void*>(data.cookie);
switch (command) {
case BR_INCREFS:
incoming_command_handler_->OnIncrementWeakReference(ptr, cookie);
AppendOutgoingCommand(BC_INCREFS_DONE, &data, sizeof(data));
break;
case BR_ACQUIRE:
incoming_command_handler_->OnIncrementStrongReference(ptr, cookie);
AppendOutgoingCommand(BC_ACQUIRE_DONE, &data, sizeof(data));
break;
case BR_RELEASE:
incoming_command_handler_->OnDecrementStrongReference(ptr, cookie);
break;
case BR_DECREFS:
incoming_command_handler_->OnDecrementWeakReference(ptr, cookie);
break;
case BR_ATTEMPT_ACQUIRE:
// Kernel's binder.h says this is not currently supported.
NOTREACHED();
break;
}
break;
}
case BR_NOOP:
break;
case BR_SPAWN_LOOPER:
NOTIMPLEMENTED();
break;
case BR_FINISHED:
// Kernel's binder.h says this is not currently supported.
NOTREACHED();
break;
case BR_DEAD_BINDER:
NOTIMPLEMENTED();
break;
case BR_CLEAR_DEATH_NOTIFICATION_DONE:
NOTIMPLEMENTED();
break;
case BR_FAILED_REPLY:
incoming_command_handler_->OnFailedReply();
break;
default:
LOG(ERROR) << "Unexpected command: " << command;
return false;
}
return true;
}
void CommandStream::FreeTransactionBuffer(const void* ptr) {
DCHECK(thread_checker_.CalledOnValidThread());
binder_uintptr_t p = reinterpret_cast<binder_uintptr_t>(ptr);
AppendOutgoingCommand(BC_FREE_BUFFER, &p, sizeof(p));
}
} // namespace binder
// 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 CHROMEOS_BINDER_COMMAND_STREAM_H_
#define CHROMEOS_BINDER_COMMAND_STREAM_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class BufferReader;
class Driver;
class TransactionData;
// Stream of incoming (binder driver to user process) BR_* commands and outgoing
// (user process to binder driver) BC_* commands.
class CHROMEOS_EXPORT CommandStream {
public:
// IncomingCommandHandler is responsible to handle incoming commands.
class IncomingCommandHandler {
public:
virtual ~IncomingCommandHandler() {}
// TODO(hashimoto): Add methods to handle incoming commands.
// Called to handle BR_TRANSACTION.
// |data| contains the parameters.
virtual bool OnTransaction(const TransactionData& data) = 0;
// Called to handle BR_REPLY.
// |data| is the reply for the previous transaction.
virtual void OnReply(std::unique_ptr<TransactionData> data) = 0;
// Called to handle BR_DEAD_REPLY.
virtual void OnDeadReply() = 0;
// Called to handle BR_TRANSACTION_COMPLETE.
virtual void OnTransactionComplete() = 0;
// Called to handle BR_INCREFS.
virtual void OnIncrementWeakReference(void* ptr, void* cookie) = 0;
// Called to handle BR_ACQUIRE.
virtual void OnIncrementStrongReference(void* ptr, void* cookie) = 0;
// Called to handle BR_RELEASE.
virtual void OnDecrementStrongReference(void* ptr, void* cookie) = 0;
// Called to handle BR_DECREFS.
virtual void OnDecrementWeakReference(void* ptr, void* cookie) = 0;
// Called to handle BR_FAILED_REPLY.
virtual void OnFailedReply() = 0;
};
CommandStream(Driver* driver,
IncomingCommandHandler* incoming_command_handler);
~CommandStream();
// Reads incoming commands from the driver to the buffer, and returns true on
// success. If there is no data to read, returns true immediately.
bool Fetch();
// Does the same thing as Fetch(), but it also blocks until some data becomes
// available for reading.
bool FetchBlocking();
// Returns true if any incoming commands are in the buffer.
bool CanProcessIncomingCommand();
// Processes an incoming command in the buffer, and returns true on success.
bool ProcessIncomingCommand();
// Appends a command to the outgoing command buffer.
void AppendOutgoingCommand(uint32_t command, const void* data, size_t size);
// Writes buffered outgoing commands to the driver, and returns true on
// success.
bool Flush();
private:
// Calls the appropriate delegate method to handle the incoming command.
bool OnIncomingCommand(uint32_t command, BufferReader* reader);
// Frees the buffer used by the driver to pass transaction data payload.
void FreeTransactionBuffer(const void* ptr);
base::ThreadChecker thread_checker_;
Driver* driver_;
IncomingCommandHandler* incoming_command_handler_;
std::vector<char> outgoing_data_; // Buffer for outgoing commands.
std::vector<char> incoming_data_; // Buffer for incoming commands.
std::unique_ptr<BufferReader> incoming_data_reader_;
base::WeakPtrFactory<CommandStream> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CommandStream);
};
} // namespace binder
#endif // CHROMEOS_BINDER_COMMAND_STREAM_H_
// 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 "base/message_loop/message_loop.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/command_stream.h"
#include "chromeos/binder/constants.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/transaction_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
namespace {
class BinderCommandStreamTest : public ::testing::Test,
public CommandStream::IncomingCommandHandler {
public:
BinderCommandStreamTest() : command_stream_(&driver_, this) {}
~BinderCommandStreamTest() override {}
void SetUp() override { ASSERT_TRUE(driver_.Initialize()); }
// CommandStream::IncomingCommandHandler override:
bool OnTransaction(const TransactionData& data) override { return false; }
void OnReply(std::unique_ptr<TransactionData> data) override {
received_response_ = RESPONSE_REPLY;
ASSERT_TRUE(data);
EXPECT_FALSE(data->HasStatus()); // No error.
}
void OnDeadReply() override { received_response_ = RESPONSE_DEAD; }
void OnTransactionComplete() override {
received_response_ = RESPONSE_COMPLETE;
}
void OnIncrementWeakReference(void* ptr, void* cookie) override {}
void OnIncrementStrongReference(void* ptr, void* cookie) override {}
void OnDecrementStrongReference(void* ptr, void* cookie) override {}
void OnDecrementWeakReference(void* ptr, void* cookie) override {}
void OnFailedReply() override { received_response_ = RESPONSE_FAILED; }
protected:
base::MessageLoop message_loop_;
Driver driver_;
CommandStream command_stream_;
enum ResponseType {
RESPONSE_NONE,
RESPONSE_REPLY,
RESPONSE_DEAD,
RESPONSE_COMPLETE,
RESPONSE_FAILED,
};
ResponseType received_response_ = RESPONSE_NONE;
};
} // namespace
TEST_F(BinderCommandStreamTest, EnterLooper) {
command_stream_.AppendOutgoingCommand(BC_ENTER_LOOPER, nullptr, 0);
EXPECT_TRUE(command_stream_.Flush());
command_stream_.AppendOutgoingCommand(BC_EXIT_LOOPER, nullptr, 0);
EXPECT_TRUE(command_stream_.Flush());
}
TEST_F(BinderCommandStreamTest, Error) {
// Kernel's binder.h says BC_ATTEMPT_ACQUIRE is not currently supported.
binder_pri_desc params = {};
command_stream_.AppendOutgoingCommand(BC_ATTEMPT_ACQUIRE, &params,
sizeof(params));
EXPECT_FALSE(command_stream_.Flush());
}
TEST_F(BinderCommandStreamTest, PingContextManager) {
// Perform ping transaction with the context manager.
binder_transaction_data data = {};
data.target.handle = kContextManagerHandle;
data.code = kPingTransactionCode;
command_stream_.AppendOutgoingCommand(BC_TRANSACTION, &data, sizeof(data));
ASSERT_TRUE(command_stream_.Flush());
// Wait for transaction complete.
while (received_response_ == RESPONSE_NONE) {
if (command_stream_.CanProcessIncomingCommand()) {
ASSERT_TRUE(command_stream_.ProcessIncomingCommand());
} else {
ASSERT_TRUE(command_stream_.Fetch());
}
}
ASSERT_EQ(RESPONSE_COMPLETE, received_response_);
// Wait for transaction reply.
received_response_ = RESPONSE_NONE;
while (received_response_ == RESPONSE_NONE) {
if (command_stream_.CanProcessIncomingCommand()) {
ASSERT_TRUE(command_stream_.ProcessIncomingCommand());
} else {
ASSERT_TRUE(command_stream_.Fetch());
}
}
ASSERT_EQ(RESPONSE_REPLY, received_response_);
}
} // namespace binder
// 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 CHROMEOS_BINDER_CONSTANTS_H_
#define CHROMEOS_BINDER_CONSTANTS_H_
#define BINDER_PACK_CHARS(c1, c2, c3, c4) \
(((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))
namespace binder {
// Context manager's handle is always 0.
const uint32_t kContextManagerHandle = 0;
// Transaction code constants.
const uint32_t kFirstTransactionCode = 0x00000001;
const uint32_t kLastTransactionCode = 0x00ffffff;
const uint32_t kPingTransactionCode = BINDER_PACK_CHARS('_', 'P', 'N', 'G');
// Note: must be kept in sync with PENALTY_GATHER in Android's StrictMode.java.
const int32_t kStrictModePenaltyGather = (0x40 << 16);
} // namespace binder
#endif // CHROMEOS_BINDER_CONSTANTS_H_
// 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 "chromeos/binder/driver.h"
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stddef.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/user.h>
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.h"
#include "chromeos/binder/binder_driver_api.h"
namespace binder {
namespace {
const char kDriverPath[] = "/dev/binder";
} // namespace
Driver::Driver() : mmap_address_(MAP_FAILED) {}
Driver::~Driver() {
base::AssertBlockingAllowed();
if (mmap_address_ != MAP_FAILED) {
if (munmap(mmap_address_, GetBinderMmapSize()) == -1) {
PLOG(ERROR) << "Failed to munmap";
}
}
fd_.reset(); // Close FD.
}
bool Driver::Initialize() {
base::AssertBlockingAllowed();
// Open binder driver.
fd_.reset(HANDLE_EINTR(open(kDriverPath, O_RDWR | O_CLOEXEC | O_NONBLOCK)));
if (!fd_.is_valid()) {
PLOG(ERROR) << "Failed to open";
return false;
}
// Version check.
int version = 0;
if (HANDLE_EINTR(ioctl(fd_.get(), BINDER_VERSION, &version)) != 0 ||
version != BINDER_CURRENT_PROTOCOL_VERSION) {
PLOG(ERROR) << "Version check failure: version = " << version;
return false;
}
// Disable thread spawning.
if (!SetMaxThreads(0)) {
PLOG(ERROR) << "SetMaxThreads() failed";
return false;
}
// Allocate buffer for transaction data.
mmap_address_ = mmap(0, GetBinderMmapSize(), PROT_READ,
MAP_PRIVATE | MAP_NORESERVE, fd_.get(), 0);
if (mmap_address_ == MAP_FAILED) {
PLOG(ERROR) << "Failed to mmap";
return false;
}
return true;
}
int Driver::GetFD() {
return fd_.get();
}
bool Driver::SetMaxThreads(int max_threads) {
base::AssertBlockingAllowed();
return HANDLE_EINTR(ioctl(fd_.get(), BINDER_SET_MAX_THREADS, &max_threads)) !=
-1;
}
bool Driver::WriteRead(const char* write_buf,
size_t write_buf_size,
char* read_buf,
size_t read_buf_size,
size_t* written_bytes,
size_t* read_bytes) {
base::AssertBlockingAllowed();
binder_write_read params = {};
params.write_buffer = reinterpret_cast<const uintptr_t>(write_buf);
params.write_size = write_buf_size;
params.read_buffer = reinterpret_cast<uintptr_t>(read_buf);
params.read_size = read_buf_size;
if (HANDLE_EINTR(ioctl(fd_.get(), BINDER_WRITE_READ, &params)) < 0 &&
errno != EAGAIN) { // EAGAIN means there is no data to read.
PLOG(ERROR) << "BINDER_WRITE_READ failed: write_buf_size = "
<< write_buf_size << ", read_buf_size = " << read_buf_size;
return false;
}
*written_bytes = params.write_consumed;
*read_bytes = params.read_consumed;
return true;
}
bool Driver::Poll() {
pollfd params = {};
params.fd = fd_.get();
params.events = POLLIN;
const int kNumFds = 1;
const int kTimeout = -1; // No timeout.
return HANDLE_EINTR(poll(&params, kNumFds, kTimeout)) == kNumFds;
}
bool Driver::NotifyCurrentThreadExiting() {
base::AssertBlockingAllowed();
return HANDLE_EINTR(ioctl(fd_.get(), BINDER_THREAD_EXIT, 0)) != -1;
}
size_t Driver::GetBinderMmapSize() const {
// Subtract PAGESIZE * 2 to make room for guard pages. https://goo.gl/4Q6sPe
return 1024 * 1024 - sysconf(_SC_PAGESIZE) * 2;
}
} // namespace binder
// 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 CHROMEOS_BINDER_DRIVER_H_
#define CHROMEOS_BINDER_DRIVER_H_
#include <stddef.h>
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "chromeos/chromeos_export.h"
namespace binder {
// Use this class to communicate with the binder driver provided by the kernel.
// This class is stateless and it's safe to access this class from multiple
// threads.
class CHROMEOS_EXPORT Driver {
public:
Driver();
~Driver();
// Opens the binder driver, performs necessary initialization, and returns
// true on success.
// This method must be called before calling any other method.
bool Initialize();
// Returns the file descriptor of the binder driver.
int GetFD();
// Sets the maximum number of additional service threads.
// By default the number is set to 0.
bool SetMaxThreads(int max_threads);
// Writes and reads data to/from the driver.
// The data in the buffer specified by write_buf and write_buf_size will be
// written, and the number of bytes written will be stored in
// num_written_bytes. The read data will be stored in the buffer specified by
// read_buf and read_buf_size, and the number of bytes read will be stored in
// num_read_bytes.
bool WriteRead(const char* write_buf,
size_t write_buf_size,
char* read_buf,
size_t read_buf_size,
size_t* num_written_bytes,
size_t* num_read_bytes);
// Waits for some data to be available for reading.
bool Poll();
// Lets the driver know the current thread is exiting.
bool NotifyCurrentThreadExiting();
private:
// Returns the size of the mmap region for transaction data.
size_t GetBinderMmapSize() const;
base::ScopedFD fd_;
void* mmap_address_;
DISALLOW_COPY_AND_ASSIGN(Driver);
};
} // namespace binder
#endif // CHROMEOS_BINDER_DRIVER_H_
// 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 "chromeos/binder/driver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
TEST(BinderDriverTest, Initialize) {
Driver driver;
EXPECT_TRUE(driver.Initialize());
}
} // namespace binder
// 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 "base/bind.h"
#include "base/files/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_timeouts.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/object.h"
#include "chromeos/binder/service_manager_proxy.h"
#include "chromeos/binder/test_service.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/transaction_data_reader.h"
#include "chromeos/binder/writable_transaction_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
class BinderEndToEndTest : public ::testing::Test {
public:
BinderEndToEndTest() : command_broker_(&driver_) {}
void SetUp() override {
ASSERT_TRUE(driver_.Initialize());
// Start the test service and get a remote object from it.
ASSERT_TRUE(test_service_.StartAndWait());
remote_object_ = ServiceManagerProxy::CheckService(
&command_broker_, test_service_.service_name());
ASSERT_EQ(Object::TYPE_REMOTE, remote_object_->GetType());
ASSERT_TRUE(remote_object_);
}
// Performs SIGNAL_TRANSACTION with a new CommandBroker instance.
// Can be called from any threads.
void PerformSignalTransaction() {
CommandBroker command_broker(&driver_);
WritableTransactionData data;
data.SetCode(TestService::SIGNAL_TRANSACTION);
std::unique_ptr<TransactionData> reply;
ASSERT_TRUE(remote_object_->Transact(&command_broker, data, &reply));
ASSERT_TRUE(reply);
TransactionDataReader reader(*reply);
uint32_t code = 0;
EXPECT_TRUE(reader.ReadUint32(&code));
EXPECT_EQ(TestService::SIGNAL_TRANSACTION, code);
}
protected:
base::MessageLoopForIO message_loop_;
Driver driver_;
CommandBroker command_broker_;
TestService test_service_;
scoped_refptr<Object> remote_object_;
};
TEST_F(BinderEndToEndTest, IncrementInt) {
const int32_t kInput = 42;
WritableTransactionData data;
data.SetCode(TestService::INCREMENT_INT_TRANSACTION);
data.WriteInt32(kInput);
std::unique_ptr<TransactionData> reply;
ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply));
ASSERT_TRUE(reply);
TransactionDataReader reader(*reply);
int32_t result = 0;
EXPECT_TRUE(reader.ReadInt32(&result));
EXPECT_EQ(kInput + 1, result);
}
TEST_F(BinderEndToEndTest, GetFD) {
WritableTransactionData data;
data.SetCode(TestService::GET_FD_TRANSACTION);
std::unique_ptr<TransactionData> reply;
ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply));
ASSERT_TRUE(reply);
TransactionDataReader reader(*reply);
int fd = -1;
EXPECT_TRUE(reader.ReadFileDescriptor(&fd));
const std::string kExpected = TestService::GetFileContents();
std::vector<char> buf(kExpected.size());
EXPECT_TRUE(base::ReadFromFD(fd, buf.data(), buf.size()));
EXPECT_EQ(kExpected, std::string(buf.data(), buf.size()));
}
// Tests if the multithreading is correctly supported by ensuring that the
// test service can handle two transactions in parallel (i.e. handling
// SIGNAL_TRANSACTION while one thread is blocked by WAIT_TRANSACTION).
TEST_F(BinderEndToEndTest, MultiThread) {
// Signal the object on a separate thread.
base::Thread signal_thread("SignalThread");
ASSERT_TRUE(signal_thread.Start());
ASSERT_TRUE(signal_thread.WaitUntilThreadStarted());
// The use of delayed task here can result in a race if it takes long to
// perform the wait transaction, but in practice it doesn't matter as it takes
// only about 1 ms to perform a transaction.
signal_thread.task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&BinderEndToEndTest::PerformSignalTransaction,
base::Unretained(this)),
TestTimeouts::tiny_timeout());
// Wait for the signal.
WritableTransactionData data;
data.SetCode(TestService::WAIT_TRANSACTION);
std::unique_ptr<TransactionData> reply;
ASSERT_TRUE(remote_object_->Transact(&command_broker_, data, &reply));
ASSERT_TRUE(reply);
TransactionDataReader reader(*reply);
uint32_t code = 0;
EXPECT_TRUE(reader.ReadUint32(&code));
EXPECT_EQ(TestService::WAIT_TRANSACTION, code);
}
} // namespace binder
// 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 "chromeos/binder/ipc_thread.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_current.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/binder/driver.h"
namespace binder {
// IpcThreadPoller
IpcThreadPoller::IpcThreadPoller(ThreadType type, Driver* driver)
: type_(type),
driver_(driver),
command_broker_(driver),
watcher_(FROM_HERE) {}
IpcThreadPoller::~IpcThreadPoller() {
if (!command_broker_.ExitLooper()) {
LOG(ERROR) << "Failed to exit looper.";
}
if (!driver_->NotifyCurrentThreadExiting()) {
LOG(ERROR) << "Failed to send thread exit.";
}
}
bool IpcThreadPoller::Initialize() {
if (type_ == THREAD_TYPE_MAIN) {
if (!command_broker_.EnterLooper()) {
LOG(ERROR) << "Failed to enter looper.";
return false;
}
} else {
if (!command_broker_.RegisterLooper()) {
LOG(ERROR) << "Failed to register looper.";
return false;
}
}
if (!base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
driver_->GetFD(), true, base::MessagePumpForIO::WATCH_READ, &watcher_,
this)) {
LOG(ERROR) << "Failed to initialize watcher.";
return false;
}
return true;
}
void IpcThreadPoller::OnFileCanReadWithoutBlocking(int fd) {
bool success = command_broker_.PollCommands();
LOG_IF(ERROR, !success) << "PollCommands() failed.";
}
void IpcThreadPoller::OnFileCanWriteWithoutBlocking(int fd) {
NOTREACHED();
}
// MainIpcThread
MainIpcThread::MainIpcThread() : base::Thread("BinderMainThread") {}
MainIpcThread::~MainIpcThread() {
Stop();
}
bool MainIpcThread::Start() {
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
return StartWithOptions(options);
}
void MainIpcThread::Init() {
driver_.reset(new Driver());
if (!driver_->Initialize()) {
LOG(ERROR) << "Failed to initialize driver.";
return;
}
poller_.reset(
new IpcThreadPoller(IpcThreadPoller::THREAD_TYPE_MAIN, driver_.get()));
if (!poller_->Initialize()) {
LOG(ERROR) << "Failed to initialize poller.";
return;
}
initialized_ = true;
}
void MainIpcThread::CleanUp() {
poller_.reset();
driver_.reset();
}
// SubIpcThread
SubIpcThread::SubIpcThread(MainIpcThread* main_thread)
: base::Thread("BinderSubThread"), main_thread_(main_thread) {}
SubIpcThread::~SubIpcThread() {
Stop();
}
bool SubIpcThread::Start() {
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
return StartWithOptions(options);
}
void SubIpcThread::Init() {
// Wait for the main thread to finish initialization.
if (!main_thread_->WaitUntilThreadStarted()) {
LOG(ERROR) << "Failed to wait for the main thread.";
return;
}
poller_.reset(new IpcThreadPoller(IpcThreadPoller::THREAD_TYPE_SUB,
main_thread_->driver()));
if (!poller_->Initialize()) {
LOG(ERROR) << "Failed to initialize poller.";
return;
}
initialized_ = true;
}
void SubIpcThread::CleanUp() {
poller_.reset();
}
} // namespace binder
// 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 CHROMEOS_BINDER_IPC_THREAD_H_
#define CHROMEOS_BINDER_IPC_THREAD_H_
#include <memory>
#include "base/macros.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/threading/thread.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class Driver;
// IpcThreadPoller watches the driver for incoming commands, and polls and
// handles them when necessary.
class CHROMEOS_EXPORT IpcThreadPoller
: public base::MessagePumpForIO::FdWatcher {
public:
enum ThreadType {
THREAD_TYPE_MAIN, // The thread owns the driver instance.
THREAD_TYPE_SUB, // The thread is not the owner of the driver instance.
};
IpcThreadPoller(ThreadType type, Driver* driver);
~IpcThreadPoller() override;
Driver* driver() { return driver_; }
CommandBroker* command_broker() { return &command_broker_; }
// Initializes this object.
// Returns true on success.
bool Initialize();
// base::MessageLoopIO::Watcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
private:
ThreadType type_;
Driver* driver_;
CommandBroker command_broker_;
base::MessagePumpForIO::FdWatchController watcher_;
DISALLOW_COPY_AND_ASSIGN(IpcThreadPoller);
};
// MainIpcThread manages binder-related resources (e.g. binder driver FD) and
// handles incoming binder commands.
class CHROMEOS_EXPORT MainIpcThread : public base::Thread {
public:
MainIpcThread();
~MainIpcThread() override;
Driver* driver() { return driver_.get(); }
CommandBroker* command_broker() { return poller_->command_broker(); }
bool initialized() const { return initialized_; }
// Starts this thread.
// Returns true on success.
bool Start();
protected:
// base::Thread overrides:
void Init() override;
void CleanUp() override;
private:
std::unique_ptr<Driver> driver_;
std::unique_ptr<IpcThreadPoller> poller_;
bool initialized_ = false;
DISALLOW_COPY_AND_ASSIGN(MainIpcThread);
};
// SubIpcThread does the same thing as MainIpcThread, but relies on the driver
// instance owned by the main thread.
class CHROMEOS_EXPORT SubIpcThread : public base::Thread {
public:
// Constructs a sub thread with a Driver instance owned by the main thread.
explicit SubIpcThread(MainIpcThread* main_thread);
~SubIpcThread() override;
Driver* driver() { return poller_->driver(); }
CommandBroker* command_broker() { return poller_->command_broker(); }
bool initialized() const { return initialized_; }
// Starts this thread.
// Returns true on success.
bool Start();
protected:
// base::Thread overrides:
void Init() override;
void CleanUp() override;
private:
MainIpcThread* main_thread_;
std::unique_ptr<IpcThreadPoller> poller_;
bool initialized_ = false;
DISALLOW_COPY_AND_ASSIGN(SubIpcThread);
};
} // namespace binder
#endif // CHROMEOS_BINDER_IPC_THREAD_H_
// 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 "chromeos/binder/local_object.h"
#include <utility>
#include "chromeos/binder/transaction_data.h"
namespace binder {
LocalObject::LocalObject(std::unique_ptr<TransactionHandler> handler)
: handler_(std::move(handler)) {}
LocalObject::~LocalObject() = default;
Object::Type LocalObject::GetType() const {
return TYPE_LOCAL;
}
bool LocalObject::Transact(CommandBroker* command_broker,
const TransactionData& data,
std::unique_ptr<TransactionData>* reply) {
*reply = handler_->OnTransact(command_broker, data);
return true;
}
} // namespace binder
// 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 CHROMEOS_BINDER_LOCAL_OBJECT_H_
#define CHROMEOS_BINDER_LOCAL_OBJECT_H_
#include <memory>
#include "base/macros.h"
#include "chromeos/binder/object.h"
#include "chromeos/chromeos_export.h"
namespace binder {
// Object living in the current process.
class CHROMEOS_EXPORT LocalObject : public Object {
public:
// Inherit this interface to implement transaction.
class TransactionHandler {
public:
virtual ~TransactionHandler() {}
// Called when LocalObject::Transact() is called.
virtual std::unique_ptr<TransactionData> OnTransact(
CommandBroker* command_broker,
const TransactionData& data) = 0;
};
explicit LocalObject(std::unique_ptr<TransactionHandler> handler);
// Object override:
Type GetType() const override;
bool Transact(CommandBroker* command_broker,
const TransactionData& data,
std::unique_ptr<TransactionData>* reply) override;
protected:
~LocalObject() override;
private:
std::unique_ptr<TransactionHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(LocalObject);
};
} // namespace binder
#endif // CHROMEOS_BINDER_LOCAL_OBJECT_H_
// 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 CHROMEOS_BINDER_OBJECT_H_
#define CHROMEOS_BINDER_OBJECT_H_
#include <memory>
#include "base/memory/ref_counted.h"
namespace binder {
class CommandBroker;
class TransactionData;
// An object to perform a transaction.
class Object : public base::RefCountedThreadSafe<Object> {
public:
// Type of an object.
enum Type {
TYPE_LOCAL, // This object lives in this process.
TYPE_REMOTE, // This object lives in a remote process.
};
// Returns the type of this object.
virtual Type GetType() const = 0;
// Performs a transaction.
virtual bool Transact(CommandBroker* command_broker,
const TransactionData& data,
std::unique_ptr<TransactionData>* reply) = 0;
protected:
friend class base::RefCountedThreadSafe<Object>;
virtual ~Object() {}
};
} // namespace binder
#endif // CHROMEOS_BINDER_OBJECT_H_
// 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 "chromeos/binder/remote_object.h"
#include "base/location.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/binder/command_broker.h"
namespace binder {
RemoteObject::RemoteObject(CommandBroker* command_broker, int32_t handle)
: release_closure_(command_broker->GetReleaseReferenceClosure(handle)),
release_task_runner_(base::ThreadTaskRunnerHandle::Get()),
handle_(handle) {
command_broker->AddReference(handle_);
}
RemoteObject::~RemoteObject() {
if (release_task_runner_->BelongsToCurrentThread()) {
release_closure_.Run();
} else {
release_task_runner_->PostTask(FROM_HERE, release_closure_);
}
}
Object::Type RemoteObject::GetType() const {
return TYPE_REMOTE;
}
bool RemoteObject::Transact(CommandBroker* command_broker,
const TransactionData& data,
std::unique_ptr<TransactionData>* reply) {
return command_broker->Transact(handle_, data, reply);
}
} // namespace binder
// 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 CHROMEOS_BINDER_REMOTE_OBJECT_H_
#define CHROMEOS_BINDER_REMOTE_OBJECT_H_
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "chromeos/binder/object.h"
#include "chromeos/chromeos_export.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace binder {
class CommandBroker;
// Object living in a remote process.
class CHROMEOS_EXPORT RemoteObject : public Object {
public:
RemoteObject(CommandBroker* command_broker, int32_t handle);
// Returns the handle of this object.
int32_t GetHandle() const { return handle_; }
// Object override:
Type GetType() const override;
bool Transact(CommandBroker* command_broker,
const TransactionData& data,
std::unique_ptr<TransactionData>* reply) override;
protected:
~RemoteObject() override;
private:
base::Closure release_closure_;
scoped_refptr<base::SingleThreadTaskRunner> release_task_runner_;
int32_t handle_;
DISALLOW_COPY_AND_ASSIGN(RemoteObject);
};
} // namespace binder
#endif // CHROMEOS_BINDER_REMOTE_OBJECT_H_
// 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 "chromeos/binder/service_manager_proxy.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/binder/object.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/transaction_data_reader.h"
#include "chromeos/binder/writable_transaction_data.h"
namespace binder {
// static
const char ServiceManagerProxy::kInterfaceName[] = "android.os.IServiceManager";
// static
scoped_refptr<Object> ServiceManagerProxy::CheckService(
CommandBroker* command_broker,
const base::string16& service_name) {
// TODO(hashimoto): Propagate the current thread's strict mode policy
// (crbug.com/575574).
const int kStrictModePolicy = 0;
WritableTransactionData data;
data.SetCode(CHECK_SERVICE_TRANSACTION);
data.WriteInterfaceToken(base::ASCIIToUTF16(kInterfaceName),
kStrictModePolicy);
data.WriteString16(service_name);
std::unique_ptr<TransactionData> reply;
if (!command_broker->Transact(kContextManagerHandle, data, &reply) ||
!reply || reply->HasStatus()) {
LOG(ERROR) << "Failed to get the service.";
return scoped_refptr<Object>();
}
TransactionDataReader reader(*reply);
return reader.ReadObject(command_broker);
}
// static
bool ServiceManagerProxy::AddService(CommandBroker* command_broker,
const base::string16& service_name,
scoped_refptr<Object> object,
int options) {
// TODO(hashimoto): Propagate the current thread's strict mode policy
// (crbug.com/575574).
const int kStrictModePolicy = 0;
WritableTransactionData data;
data.SetCode(ADD_SERVICE_TRANSACTION);
data.WriteInterfaceToken(base::ASCIIToUTF16(kInterfaceName),
kStrictModePolicy);
data.WriteString16(service_name);
data.WriteObject(object);
data.WriteInt32((options & ALLOW_ISOLATED) ? 1 : 0);
std::unique_ptr<TransactionData> reply;
if (!command_broker->Transact(kContextManagerHandle, data, &reply) ||
!reply || reply->HasStatus()) {
LOG(ERROR) << "Failed to add the service.";
return false;
}
return true;
}
} // namespace binder
// 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 CHROMEOS_BINDER_SERVICE_MANAGER_PROXY_H_
#define CHROMEOS_BINDER_SERVICE_MANAGER_PROXY_H_
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "chromeos/binder/constants.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class CommandBroker;
class Object;
// Proxy of the service manager.
// Use this class to communicate with the service manager process.
class CHROMEOS_EXPORT ServiceManagerProxy {
public:
static const char kInterfaceName[];
// Must match with the values in Android's IServiceManager.h.
// (https://goo.gl/VcPBKL)
enum {
GET_SERVICE_TRANSACTION = kFirstTransactionCode,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
// Options for AddService().
enum AddServiceOptions {
// Allow isolated Android processes to access the service.
// (See http://goo.gl/H95R6h for isolated process.)
ALLOW_ISOLATED = 1,
};
// Returns the service object if it's available.
static scoped_refptr<Object> CheckService(CommandBroker* command_broker,
const base::string16& service_name);
// Registers the given object as a service with the specified name.
// |options| is a bitmask of AddServiceOptions.
static bool AddService(CommandBroker* command_broker,
const base::string16& service_name,
scoped_refptr<Object> object,
int options);
};
} // namespace binder
#endif // CHROMEOS_BINDER_SERVICE_MANAGER_PROXY_H_
// 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 "chromeos/binder/service_manager_proxy.h"
#include <memory>
#include "base/guid.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/binder/command_broker.h"
#include "chromeos/binder/driver.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/transaction_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace binder {
namespace {
class DummyTransactionHandler : public LocalObject::TransactionHandler {
public:
DummyTransactionHandler() {}
~DummyTransactionHandler() override {}
std::unique_ptr<TransactionData> OnTransact(
CommandBroker* command_broker,
const TransactionData& data) override {
return std::unique_ptr<TransactionData>();
}
private:
DISALLOW_COPY_AND_ASSIGN(DummyTransactionHandler);
};
} // namespace
class BinderServiceManagerProxyTest : public ::testing::Test {
public:
BinderServiceManagerProxyTest() : command_broker_(&driver_) {}
~BinderServiceManagerProxyTest() override {}
void SetUp() override { ASSERT_TRUE(driver_.Initialize()); }
protected:
base::MessageLoop message_loop_;
Driver driver_;
CommandBroker command_broker_;
};
TEST_F(BinderServiceManagerProxyTest, AddAndCheck) {
const base::string16 kServiceName =
base::ASCIIToUTF16("org.chromium.TestService-" + base::GenerateGUID());
// Service not available yet.
EXPECT_FALSE(
ServiceManagerProxy::CheckService(&command_broker_, kServiceName));
// Add service.
scoped_refptr<Object> object(
new LocalObject(std::make_unique<DummyTransactionHandler>()));
EXPECT_TRUE(ServiceManagerProxy::AddService(&command_broker_, kServiceName,
object, 0));
// Service is available.
scoped_refptr<Object> result =
ServiceManagerProxy::CheckService(&command_broker_, kServiceName);
ASSERT_TRUE(result);
ASSERT_EQ(LocalObject::TYPE_LOCAL, result->GetType());
EXPECT_EQ(object.get(), result.get());
}
} // namespace binder
// 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 CHROMEOS_BINDER_STATUS_H_
#define CHROMEOS_BINDER_STATUS_H_
#include <errno.h>
#include <stdint.h>
namespace binder {
// Status code.
// Using the same values as used by libbinder.
enum class Status : int32_t {
OK = 0,
UNKNOWN_ERROR = INT32_MIN,
NO_MEMORY = -ENOMEM,
INVALID_OPERATION = -ENOSYS,
BAD_VALUE = -EINVAL,
BAD_TYPE = (UNKNOWN_ERROR + 1),
NAME_NOT_FOUND = -ENOENT,
PERMISSION_DENIED = -EPERM,
NO_INIT = -ENODEV,
ALREADY_EXISTS = -EEXIST,
DEAD_OBJECT = -EPIPE,
FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
WOULD_BLOCK = -EWOULDBLOCK,
TIMED_OUT = -ETIMEDOUT,
UNKNOWN_TRANSACTION = -EBADMSG,
FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
UNEXPECTED_NULL = (UNKNOWN_ERROR + 8),
};
} // namespace binder
#endif // CHROMEOS_BINDER_STATUS_H_
// 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 "chromeos/binder/test_service.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/service_manager_proxy.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/binder/transaction_data_reader.h"
#include "chromeos/binder/writable_transaction_data.h"
namespace binder {
class TestService::TestObject : public LocalObject::TransactionHandler {
public:
TestObject()
: event_(false /* manual_reset */, false /* initially_signaled */) {
VLOG(1) << "Object created: " << this;
}
~TestObject() override { VLOG(1) << "Object destroyed: " << this; }
std::unique_ptr<binder::TransactionData> OnTransact(
binder::CommandBroker* command_broker,
const binder::TransactionData& data) {
VLOG(1) << "Transact code = " << data.GetCode();
binder::TransactionDataReader reader(data);
switch (data.GetCode()) {
case INCREMENT_INT_TRANSACTION: {
int32_t arg = 0;
reader.ReadInt32(&arg);
std::unique_ptr<binder::WritableTransactionData> reply(
new binder::WritableTransactionData());
reply->WriteInt32(arg + 1);
return std::move(reply);
}
case GET_FD_TRANSACTION: {
// Prepare a file.
std::string data = GetFileContents();
base::ScopedTempDir temp_dir;
base::FilePath path;
if (!temp_dir.CreateUniqueTempDir() ||
!base::CreateTemporaryFileInDir(temp_dir.GetPath(), &path) ||
!base::WriteFile(path, data.data(), data.size())) {
LOG(ERROR) << "Failed to create a file";
return std::unique_ptr<TransactionData>();
}
// Open the file.
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid()) {
LOG(ERROR) << "Failed to open the file.";
return std::unique_ptr<TransactionData>();
}
// Return the FD.
// The file will be deleted by |temp_dir|, but the FD remains valid
// until the receiving process closes it.
std::unique_ptr<binder::WritableTransactionData> reply(
new binder::WritableTransactionData());
reply->WriteFileDescriptor(base::ScopedFD(file.TakePlatformFile()));
return std::move(reply);
}
case WAIT_TRANSACTION: {
event_.Wait();
std::unique_ptr<binder::WritableTransactionData> reply(
new binder::WritableTransactionData());
reply->WriteUint32(WAIT_TRANSACTION);
return std::move(reply);
}
case SIGNAL_TRANSACTION: {
event_.Signal();
std::unique_ptr<binder::WritableTransactionData> reply(
new binder::WritableTransactionData());
reply->WriteUint32(SIGNAL_TRANSACTION);
return std::move(reply);
}
}
return std::unique_ptr<TransactionData>();
}
private:
base::WaitableEvent event_;
DISALLOW_COPY_AND_ASSIGN(TestObject);
};
TestService::TestService()
: service_name_(base::ASCIIToUTF16("org.chromium.TestService-" +
base::GenerateGUID())),
sub_thread_(&main_thread_) {}
TestService::~TestService() {}
bool TestService::StartAndWait() {
if (!main_thread_.Start() || !sub_thread_.Start() ||
!main_thread_.WaitUntilThreadStarted() || !main_thread_.initialized() ||
!sub_thread_.WaitUntilThreadStarted() || !sub_thread_.initialized()) {
LOG(ERROR) << "Failed to start the threads.";
return false;
}
bool result = false;
base::RunLoop run_loop;
main_thread_.task_runner()->PostTaskAndReply(
FROM_HERE,
base::Bind(&TestService::Initialize, base::Unretained(this), &result),
run_loop.QuitClosure());
run_loop.Run();
return result;
}
void TestService::Stop() {
sub_thread_.Stop();
main_thread_.Stop();
}
// static
std::string TestService::GetFileContents() {
return "Test data";
}
void TestService::Initialize(bool* result) {
// Add service.
scoped_refptr<LocalObject> object(
new LocalObject(base::WrapUnique(new TestObject)));
*result = ServiceManagerProxy::AddService(main_thread_.command_broker(),
service_name_, object, 0);
}
} // namespace binder
// 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 CHROMEOS_BINDER_TEST_SERVICE_H_
#define CHROMEOS_BINDER_TEST_SERVICE_H_
#include "base/macros.h"
#include "base/strings/string16.h"
#include "chromeos/binder/constants.h"
#include "chromeos/binder/ipc_thread.h"
namespace binder {
// Service for testing.
// Opens binder driver on its own thread and provides a service.
// Note: Although this service runs in the same process as the test code, the
// binder driver thinks this service is in a separate process because it owns a
// separate binder driver FD itself.
class TestService {
public:
enum {
INCREMENT_INT_TRANSACTION = kFirstTransactionCode,
GET_FD_TRANSACTION,
WAIT_TRANSACTION, // Waits for SIGNAL_TRANSACTION.
SIGNAL_TRANSACTION, // Signals a waiting thread.
};
TestService();
~TestService();
// The name of this service.
const base::string16& service_name() const { return service_name_; }
// Starts the service and waits for it to complete initialization.
// Returns true on success.
bool StartAndWait();
// Stops this service.
void Stop();
// Returns the contents of the file returned by GET_FD_TRANSACTION.
static std::string GetFileContents();
private:
class TestObject;
// Initializes the service on the service thread.
// |result| will be set to true on success.
void Initialize(bool* result);
base::string16 service_name_;
MainIpcThread main_thread_;
SubIpcThread sub_thread_;
DISALLOW_COPY_AND_ASSIGN(TestService);
};
} // namespace binder
#endif // CHROMEOS_BINDER_TEST_SERVICE_H_
// 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 CHROMEOS_BINDER_TRANSACTION_DATA_H_
#define CHROMEOS_BINDER_TRANSACTION_DATA_H_
#include <sys/types.h>
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/status.h"
namespace binder {
// Data passed via transactions.
class TransactionData {
public:
virtual ~TransactionData() {}
// Returns the cookie which can be used to identify the target object.
virtual uintptr_t GetCookie() const = 0;
// Returns the transaction code.
virtual uint32_t GetCode() const = 0;
// Returns the PID of the sender.
virtual pid_t GetSenderPID() const = 0;
// Returns the EUID of the sender.
virtual uid_t GetSenderEUID() const = 0;
// Returns true if there is no need to send reply for the transaction.
virtual bool IsOneWay() const = 0;
// Returns true if the payload is a status code.
virtual bool HasStatus() const = 0;
// Returns the status code.
// This method should be called only when HasStatus() returns true.
virtual Status GetStatus() const = 0;
// Returns the payload data.
virtual const void* GetData() const = 0;
// Returns the size of the payload.
virtual size_t GetDataSize() const = 0;
// Returns the offsets of objects stored in the payload.
virtual const binder_uintptr_t* GetObjectOffsets() const = 0;
// Returns the number of objects.
virtual size_t GetNumObjectOffsets() const = 0;
};
} // namespace binder
#endif // CHROMEOS_BINDER_TRANSACTION_DATA_H_
// 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 "chromeos/binder/transaction_data_from_driver.h"
#include <stddef.h>
#include <stdint.h>
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/binder/command_stream.h"
namespace binder {
TransactionDataFromDriver::TransactionDataFromDriver(
const BufferDeleter& buffer_deleter)
: delete_task_runner_(base::ThreadTaskRunnerHandle::Get()),
buffer_deleter_(buffer_deleter) {
memset(&data_, 0, sizeof(data_));
}
TransactionDataFromDriver::~TransactionDataFromDriver() {
if (!HasStatus()) { // Need to free the payload.
// Close FDs.
for (size_t i = 0; i < GetNumObjectOffsets(); ++i) {
const auto& object = *reinterpret_cast<const flat_binder_object*>(
reinterpret_cast<const char*>(GetData()) + GetObjectOffsets()[i]);
if (object.type == BINDER_TYPE_FD) {
close(object.handle);
}
}
// Free data buffer.
if (delete_task_runner_->BelongsToCurrentThread()) {
buffer_deleter_.Run(GetData());
} else {
delete_task_runner_->PostTask(FROM_HERE,
base::BindOnce(buffer_deleter_, GetData()));
}
}
}
uintptr_t TransactionDataFromDriver::GetCookie() const {
return data_.cookie;
}
uint32_t TransactionDataFromDriver::GetCode() const {
return data_.code;
}
pid_t TransactionDataFromDriver::GetSenderPID() const {
return data_.sender_pid;
}
uid_t TransactionDataFromDriver::GetSenderEUID() const {
return data_.sender_euid;
}
bool TransactionDataFromDriver::IsOneWay() const {
return data_.flags & TF_ONE_WAY;
}
bool TransactionDataFromDriver::HasStatus() const {
return data_.flags & TF_STATUS_CODE;
}
Status TransactionDataFromDriver::GetStatus() const {
DCHECK(HasStatus());
return *reinterpret_cast<const Status*>(data_.data.ptr.buffer);
}
const void* TransactionDataFromDriver::GetData() const {
return reinterpret_cast<const void*>(data_.data.ptr.buffer);
}
size_t TransactionDataFromDriver::GetDataSize() const {
return data_.data_size;
}
const binder_uintptr_t* TransactionDataFromDriver::GetObjectOffsets() const {
return reinterpret_cast<const binder_uintptr_t*>(data_.data.ptr.offsets);
}
size_t TransactionDataFromDriver::GetNumObjectOffsets() const {
DCHECK_EQ(0u, data_.offsets_size % sizeof(binder_size_t));
return data_.offsets_size / sizeof(binder_size_t);
}
} // namespace binder
// 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 CHROMEOS_BINDER_TRANSACTION_DATA_FROM_DRIVER_H_
#define CHROMEOS_BINDER_TRANSACTION_DATA_FROM_DRIVER_H_
#include <stddef.h>
#include <stdint.h>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/chromeos_export.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace binder {
// TransactionData passed by the driver, whose data needs to be freed with
// BC_FREE_BUFFER command.
class CHROMEOS_EXPORT TransactionDataFromDriver : public TransactionData {
public:
typedef base::Callback<void(const void* ptr)> BufferDeleter;
explicit TransactionDataFromDriver(const BufferDeleter& buffer_deleter);
~TransactionDataFromDriver() override;
const binder_transaction_data& data() const { return data_; }
binder_transaction_data* mutable_data() { return &data_; }
// TransactionData override:
uintptr_t GetCookie() const override;
uint32_t GetCode() const override;
pid_t GetSenderPID() const override;
uid_t GetSenderEUID() const override;
bool IsOneWay() const override;
bool HasStatus() const override;
Status GetStatus() const override;
const void* GetData() const override;
size_t GetDataSize() const override;
const binder_uintptr_t* GetObjectOffsets() const override;
size_t GetNumObjectOffsets() const override;
private:
scoped_refptr<base::SingleThreadTaskRunner> delete_task_runner_;
BufferDeleter buffer_deleter_;
binder_transaction_data data_;
DISALLOW_COPY_AND_ASSIGN(TransactionDataFromDriver);
};
} // namespace binder
#endif // CHROMEOS_BINDER_TRANSACTION_DATA_FROM_DRIVER_H_
// 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 "chromeos/binder/transaction_data_reader.h"
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/object.h"
#include "chromeos/binder/remote_object.h"
#include "chromeos/binder/transaction_data.h"
namespace binder {
namespace {
// Adds appropriate padding to the given size to make it 4-byte aligned.
size_t AddPadding(size_t n) {
return (n + 3) & (~3);
}
} // namespace
TransactionDataReader::TransactionDataReader(const TransactionData& data)
: reader_(reinterpret_cast<const char*>(data.GetData()),
data.GetDataSize()) {}
TransactionDataReader::~TransactionDataReader() = default;
bool TransactionDataReader::HasMoreData() const {
return reader_.HasMoreData();
}
bool TransactionDataReader::ReadData(void* buf, size_t n) {
DCHECK(buf);
return reader_.Read(buf, n) && reader_.Skip(AddPadding(n) - n);
}
bool TransactionDataReader::ReadInt32(int32_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadUint32(uint32_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadInt64(int64_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadUint64(uint64_t* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadFloat(float* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadDouble(double* value) {
return ReadData(value, sizeof(*value));
}
bool TransactionDataReader::ReadCString(const char** value) {
*value = reader_.current();
for (size_t len = 0; reader_.HasMoreData(); ++len) {
char c = 0;
if (!reader_.Read(&c, sizeof(c))) {
return false;
}
if (c == 0) {
return reader_.Skip(AddPadding(len + 1) - (len + 1));
}
}
return false;
}
bool TransactionDataReader::ReadString(std::string* value) {
int32_t len = 0;
if (!ReadInt32(&len)) {
return false;
}
if (len == 0) {
// Read only when the string is not empty.
// This is different from ReadString16().
value->clear();
return true;
}
const char* start = reader_.current();
if (!reader_.Skip(AddPadding(len + 1))) {
return false;
}
value->assign(start, len);
return true;
}
bool TransactionDataReader::ReadString16(base::string16* value) {
int32_t len = 0;
if (!ReadInt32(&len)) {
return false;
}
const base::char16* start =
reinterpret_cast<const base::char16*>(reader_.current());
if (!reader_.Skip(AddPadding((len + 1) * sizeof(base::char16)))) {
return false;
}
value->assign(start, len);
return true;
}
scoped_refptr<Object> TransactionDataReader::ReadObject(
CommandBroker* command_broker) {
DCHECK(command_broker);
flat_binder_object obj = {};
if (!ReadData(&obj, sizeof(obj))) {
return scoped_refptr<Object>();
}
switch (obj.type) {
case BINDER_TYPE_HANDLE:
return base::MakeRefCounted<RemoteObject>(command_broker, obj.handle);
case BINDER_TYPE_BINDER:
return base::WrapRefCounted(reinterpret_cast<LocalObject*>(obj.cookie));
}
return scoped_refptr<Object>();
}
bool TransactionDataReader::ReadFileDescriptor(int* fd) {
flat_binder_object obj = {};
if (!ReadData(&obj, sizeof(obj)) || obj.type != BINDER_TYPE_FD) {
return false;
}
*fd = obj.handle;
return true;
}
} // namespace binder
// 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 CHROMEOS_BINDER_TRANSACTION_DATA_READER_H_
#define CHROMEOS_BINDER_TRANSACTION_DATA_READER_H_
#include <stddef.h>
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "chromeos/binder/buffer_reader.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class CommandBroker;
class Object;
class TransactionData;
// Reads contents of a TransactionData.
// Use this class to get parameters of incoming transactions, or to get values
// from transaction replies.
class CHROMEOS_EXPORT TransactionDataReader {
public:
explicit TransactionDataReader(const TransactionData& data);
~TransactionDataReader();
// Returns true when there is some data to read.
bool HasMoreData() const;
// Reads the specified number of bytes with appropriate padding.
// Returns true on success.
bool ReadData(void* buf, size_t n);
// Reads an int32_t value. Returns true on success.
bool ReadInt32(int32_t* value);
// Reads an uint32_t value. Returns true on success.
bool ReadUint32(uint32_t* value);
// Reads an int64_t value. Returns true on success.
bool ReadInt64(int64_t* value);
// Reads an uint64_t value. Returns true on success.
bool ReadUint64(uint64_t* value);
// Reads a float value. Returns true on success.
bool ReadFloat(float* value);
// Reads a double value. Returns true on success.
bool ReadDouble(double* value);
// Reads a null-terminated C string.
bool ReadCString(const char** value);
// Reads a string.
bool ReadString(std::string* value);
// Reads a UTF-16 string.
bool ReadString16(base::string16* value);
// Reads an object. Returns null on failure.
// |command_broker| will be used for object ref-count operations.
scoped_refptr<Object> ReadObject(CommandBroker* command_broker);
// Reads a file descriptor.
// The file descriptor is owned by the TransactionData, and it will be closed
// when the TransactionData gets destroyed. You should duplicate the FD (e.g.
// by calling dup()) to keep owning it.
bool ReadFileDescriptor(int* fd);
private:
BufferReader reader_;
DISALLOW_COPY_AND_ASSIGN(TransactionDataReader);
};
} // namespace binder
#endif // CHROMEOS_BINDER_TRANSACTION_DATA_READER_H_
// 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 "chromeos/binder/transaction_status.h"
namespace binder {
TransactionStatus::TransactionStatus(Status status) : status_(status) {}
TransactionStatus::~TransactionStatus() = default;
uintptr_t TransactionStatus::GetCookie() const {
return 0;
}
uint32_t TransactionStatus::GetCode() const {
return 0;
}
pid_t TransactionStatus::GetSenderPID() const {
return 0;
}
uid_t TransactionStatus::GetSenderEUID() const {
return 0;
}
bool TransactionStatus::IsOneWay() const {
return false;
}
bool TransactionStatus::HasStatus() const {
return true;
}
Status TransactionStatus::GetStatus() const {
return status_;
}
const void* TransactionStatus::GetData() const {
return reinterpret_cast<const char*>(&status_);
}
size_t TransactionStatus::GetDataSize() const {
return sizeof(status_);
}
const binder_uintptr_t* TransactionStatus::GetObjectOffsets() const {
return nullptr;
}
size_t TransactionStatus::GetNumObjectOffsets() const {
return 0;
}
} // namespace binder
// 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 CHROMEOS_BINDER_TRANSACTION_STATUS_H_
#define CHROMEOS_BINDER_TRANSACTION_STATUS_H_
#include <stddef.h>
#include <stdint.h>
#include "base/macros.h"
#include "chromeos/binder/status.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/chromeos_export.h"
namespace binder {
// TransactionData whose contents is a status code.
// Use this class to return an error for transactions.
// GetSenderPID() and GetSenderEUID() return 0.
class CHROMEOS_EXPORT TransactionStatus : public TransactionData {
public:
explicit TransactionStatus(Status status);
~TransactionStatus() override;
// TransactionData override:
uintptr_t GetCookie() const override;
uint32_t GetCode() const override;
pid_t GetSenderPID() const override;
uid_t GetSenderEUID() const override;
bool IsOneWay() const override;
bool HasStatus() const override;
Status GetStatus() const override;
const void* GetData() const override;
size_t GetDataSize() const override;
const binder_uintptr_t* GetObjectOffsets() const override;
size_t GetNumObjectOffsets() const override;
private:
Status status_;
DISALLOW_COPY_AND_ASSIGN(TransactionStatus);
};
} // namespace binder
#endif // CHROMEOS_BINDER_TRANSACTION_STATUS_H_
// 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 "chromeos/binder/util.h"
#include "base/logging.h"
#include "chromeos/binder/binder_driver_api.h"
namespace binder {
const char* CommandToString(uint32_t command) {
switch (command) {
case BR_ERROR:
return "BR_ERROR";
case BR_OK:
return "BR_OK";
case BR_TRANSACTION:
return "BR_TRANSACTION";
case BR_REPLY:
return "BR_REPLY";
case BR_ACQUIRE_RESULT:
return "BR_ACQUIRE_RESULT";
case BR_DEAD_REPLY:
return "BR_DEAD_REPLY";
case BR_TRANSACTION_COMPLETE:
return "BR_TRANSACTION_COMPLETE";
case BR_INCREFS:
return "BR_INCREFS";
case BR_ACQUIRE:
return "BR_ACQUIRE";
case BR_RELEASE:
return "BR_RELEASE";
case BR_DECREFS:
return "BR_DECREFS";
case BR_ATTEMPT_ACQUIRE:
return "BR_ATTEMPT_ACQUIRE";
case BR_NOOP:
return "BR_NOOP";
case BR_SPAWN_LOOPER:
return "BR_SPAWN_LOOPER";
case BR_FINISHED:
return "BR_FINISHED";
case BR_DEAD_BINDER:
return "BR_DEAD_BINDER";
case BR_CLEAR_DEATH_NOTIFICATION_DONE:
return "BR_CLEAR_DEATH_NOTIFICATION_DONE";
case BR_FAILED_REPLY:
return "BR_FAILED_REPLY";
case BC_TRANSACTION:
return "BC_TRANSACTION";
case BC_REPLY:
return "BC_REPLY";
case BC_ACQUIRE_RESULT:
return "BC_ACQUIRE_RESULT";
case BC_FREE_BUFFER:
return "BC_FREE_BUFFER";
case BC_INCREFS:
return "BC_INCREFS";
case BC_ACQUIRE:
return "BC_ACQUIRE";
case BC_RELEASE:
return "BC_RELEASE";
case BC_DECREFS:
return "BC_DECREFS";
case BC_INCREFS_DONE:
return "BC_INCREFS_DONE";
case BC_ACQUIRE_DONE:
return "BC_ACQUIRE_DONE";
case BC_ATTEMPT_ACQUIRE:
return "BC_ATTEMPT_ACQUIRE";
case BC_REGISTER_LOOPER:
return "BC_REGISTER_LOOPER";
case BC_ENTER_LOOPER:
return "BC_ENTER_LOOPER";
case BC_EXIT_LOOPER:
return "BC_EXIT_LOOPER";
case BC_REQUEST_DEATH_NOTIFICATION:
return "BC_REQUEST_DEATH_NOTIFICATION";
case BC_CLEAR_DEATH_NOTIFICATION:
return "BC_CLEAR_DEATH_NOTIFICATION";
case BC_DEAD_BINDER_DONE:
return "BC_DEAD_BINDER_DONE";
}
LOG(ERROR) << "Unknown command: " << command;
return "UNKNOWN";
}
} // namespace binder
// 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 CHROMEOS_BINDER_UTIL_H_
#define CHROMEOS_BINDER_UTIL_H_
#include <stdint.h>
#include "chromeos/chromeos_export.h"
namespace binder {
// Returns the string representation of the given binder command or "UNKNOWN"
// if command is unknown, never returns null.
CHROMEOS_EXPORT const char* CommandToString(uint32_t command);
} // namespace binder
#endif // CHROMEOS_BINDER_UTIL_H_
// 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 "chromeos/binder/writable_transaction_data.h"
#include "chromeos/binder/binder_driver_api.h"
#include "chromeos/binder/constants.h"
#include "chromeos/binder/local_object.h"
#include "chromeos/binder/object.h"
#include "chromeos/binder/remote_object.h"
namespace binder {
WritableTransactionData::WritableTransactionData() = default;
WritableTransactionData::~WritableTransactionData() = default;
uintptr_t WritableTransactionData::GetCookie() const {
return 0;
}
uint32_t WritableTransactionData::GetCode() const {
return code_;
}
pid_t WritableTransactionData::GetSenderPID() const {
return 0;
}
uid_t WritableTransactionData::GetSenderEUID() const {
return 0;
}
bool WritableTransactionData::IsOneWay() const {
return is_one_way_;
}
bool WritableTransactionData::HasStatus() const {
return false;
}
Status WritableTransactionData::GetStatus() const {
return Status::OK;
}
const void* WritableTransactionData::GetData() const {
return data_.data();
}
size_t WritableTransactionData::GetDataSize() const {
return data_.size();
}
const binder_uintptr_t* WritableTransactionData::GetObjectOffsets() const {
return object_offsets_.data();
}
size_t WritableTransactionData::GetNumObjectOffsets() const {
return object_offsets_.size();
}
void WritableTransactionData::Reserve(size_t n) {
data_.reserve(n);
}
void WritableTransactionData::WriteData(const void* data, size_t n) {
data_.insert(data_.end(), static_cast<const char*>(data),
static_cast<const char*>(data) + n);
if (n % 4 != 0) { // Add padding.
data_.resize(data_.size() + 4 - (n % 4));
}
}
void WritableTransactionData::WriteInt32(int32_t value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteUint32(uint32_t value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteInt64(int64_t value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteUint64(uint64_t value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteFloat(float value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteDouble(double value) {
WriteData(&value, sizeof(value));
}
void WritableTransactionData::WriteCString(const char* value) {
WriteData(value, strlen(value) + 1);
}
void WritableTransactionData::WriteString(const std::string& value) {
WriteInt32(value.size());
if (value.size() > 0) {
// Write only when the string is not empty.
// This is different from WriteString16().
//
// Despite having the length info, null-terminate the data to be consistent
// with libbinder.
WriteData(value.c_str(), value.size() + 1);
}
}
void WritableTransactionData::WriteString16(const base::string16& value) {
WriteInt32(value.size());
// Despite having the length info, null-terminate the data to be consistent
// with libbinder.
WriteData(value.c_str(), (value.size() + 1) * sizeof(base::char16));
}
void WritableTransactionData::WriteInterfaceToken(
const base::string16& interface,
int32_t strict_mode_policy) {
WriteInt32(kStrictModePenaltyGather | strict_mode_policy);
WriteString16(interface);
}
void WritableTransactionData::WriteObject(scoped_refptr<Object> object) {
objects_.push_back(object); // Hold reference.
flat_binder_object flat = {};
flat.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
switch (object->GetType()) {
case Object::TYPE_LOCAL: {
auto* local = static_cast<LocalObject*>(object.get());
flat.type = BINDER_TYPE_BINDER;
flat.cookie = reinterpret_cast<uintptr_t>(local);
// flat.binder is unused, but the driver requires it to be a non-zero
// unique value.
flat.binder = reinterpret_cast<uintptr_t>(local);
break;
}
case Object::TYPE_REMOTE: {
auto* remote = static_cast<RemoteObject*>(object.get());
flat.type = BINDER_TYPE_HANDLE;
flat.handle = remote->GetHandle();
break;
}
}
object_offsets_.push_back(data_.size());
WriteData(&flat, sizeof(flat));
}
void WritableTransactionData::WriteFileDescriptor(base::ScopedFD fd) {
files_.push_back(std::move(fd));
flat_binder_object flat = {};
flat.type = BINDER_TYPE_FD;
flat.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
flat.handle = files_.back().get();
object_offsets_.push_back(data_.size());
WriteData(&flat, sizeof(flat));
}
} // namespace binder
// 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 CHROMEOS_BINDER_WRITABLE_TRANSACTION_DATA_H_
#define CHROMEOS_BINDER_WRITABLE_TRANSACTION_DATA_H_
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "chromeos/binder/transaction_data.h"
#include "chromeos/chromeos_export.h"
namespace binder {
class Object;
// Use this class to construct TransactionData (as parameters and replies) to
// transact with remote objects.
// GetSenderPID() and GetSenderEUID() return 0.
//
// Note: Unlike D-Bus, the binder driver doesn't care about the validity of
// contents being communicated. Packed data is treated simply as a blob, so it
// doesn't provide any string encoding check, endian conversion, nor type
// information about the packed data. It's developers' responsibility to ensure
// that the sending process and the receiving process are handling the
// transaction data in the same manner.
class CHROMEOS_EXPORT WritableTransactionData : public TransactionData {
public:
WritableTransactionData();
~WritableTransactionData() override;
// TransactionData override:
uintptr_t GetCookie() const override;
uint32_t GetCode() const override;
pid_t GetSenderPID() const override;
uid_t GetSenderEUID() const override;
bool IsOneWay() const override;
bool HasStatus() const override;
Status GetStatus() const override;
const void* GetData() const override;
size_t GetDataSize() const override;
const binder_uintptr_t* GetObjectOffsets() const override;
size_t GetNumObjectOffsets() const override;
// Expands the capacity of the internal buffer.
void Reserve(size_t n);
// Sets the transaction code returned by GetCode().
void SetCode(uint32_t code) { code_ = code; }
// Sets the value returned by IsOneWay().
void SetIsOneWay(bool is_one_way) { is_one_way_ = is_one_way; }
// Appends the specified data with appropriate padding.
void WriteData(const void* data, size_t n);
// Appends an int32_t value.
void WriteInt32(int32_t value);
// Appends a uint32_t value.
void WriteUint32(uint32_t value);
// Appends an int64_t vlaue.
void WriteInt64(int64_t value);
// Appends a uint64_t value.
void WriteUint64(uint64_t value);
// Appends a float value.
void WriteFloat(float value);
// Appends a double value.
void WriteDouble(double value);
// Appends a null-terminated C string.
void WriteCString(const char* value);
// Appends a string.
void WriteString(const std::string& value);
// Appends a UTF-16 string.
void WriteString16(const base::string16& value);
// Appends an RPC header.
// |interface| is the interface which must be implemented by the receiving
// process (e.g. android.os.IServiceManager).
// |strict_mode_policy| is the current thread's strict mode policy.
// (see http://developer.android.com/reference/android/os/StrictMode.html)
void WriteInterfaceToken(const base::string16& interface,
int32_t strict_mode_policy);
// Appends an object.
void WriteObject(scoped_refptr<Object> object);
// Appends a file descriptor.
void WriteFileDescriptor(base::ScopedFD fd);
private:
uint32_t code_ = 0;
bool is_one_way_ = false;
std::vector<char> data_;
std::vector<binder_uintptr_t> object_offsets_;
std::vector<scoped_refptr<Object>> objects_;
std::vector<base::ScopedFD> files_;
DISALLOW_COPY_AND_ASSIGN(WritableTransactionData);
};
} // namespace binder
#endif // CHROMEOS_BINDER_WRITABLE_TRANSACTION_DATA_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment