// 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 #include #include #include #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(); } #define BINDER_RP(br) ALOG("return_proto: %s: %d (0x%x)", #br, br, br) BINDER_RP(BR_ERROR); BINDER_RP(BR_OK); BINDER_RP(BR_TRANSACTION); BINDER_RP(BR_REPLY); BINDER_RP(BR_ACQUIRE_RESULT); BINDER_RP(BR_DEAD_REPLY); BINDER_RP(BR_TRANSACTION_COMPLETE); BINDER_RP(BR_INCREFS); BINDER_RP(BR_ACQUIRE); BINDER_RP(BR_RELEASE); BINDER_RP(BR_DECREFS); BINDER_RP(BR_ATTEMPT_ACQUIRE); BINDER_RP(BR_NOOP); BINDER_RP(BR_SPAWN_LOOPER); BINDER_RP(BR_FINISHED); BINDER_RP(BR_DEAD_BINDER); BINDER_RP(BR_CLEAR_DEATH_NOTIFICATION_DONE); BINDER_RP(BR_FAILED_REPLY); return fd; } void CopyCommandsToBuffer(const std::vector& commands, std::vector* buffer) { size_t last_command_size = 0; for (const Command* command : commands) { memcpy(&(*buffer)[last_command_size], reinterpret_cast(command->GetData()), command->GetSize()); last_command_size += command->GetSize(); } } } // namespace Channel::Channel(uint32_t handle) : handle_(handle), driver_(ConnectDriver()), reader_() { reader_.SetDataSize(256); } Channel::~Channel() { } int Channel::Call(uint32_t code, const Parcel& in, Parcel* out) { reader_.SetDataPosition(0); struct binder_write_read bwr = {}; TransactionCommand command(TransactionCommand::TWO_WAY); command.SetHandle(handle()); command.SetCode(code); command.SetParcel(in); bwr.write_size = command.GetSize(); bwr.write_buffer = command.GetData(); bwr.read_size = reader_.DataSize(); bwr.read_buffer = reader_.DataPointer(); int rv = ioctl(driver_, BINDER_WRITE_READ, &bwr); ALOG("BINDER_WRITE_READ %d (written %d/%d, read %d/%d)", rv, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size); if (rv != 0) return -errno; for (binder_size_t index = 0; index < bwr.read_consumed; index = reader_.DataPosition()) { size_t remaining = bwr.read_consumed - index; if (remaining < sizeof(uint32_t)) break; uint32_t command = 0; if (!reader_.ReadUInt32(&command)) break; if (!ProcessCommand(command, remaining)) break; } return rv; } bool Channel::ProcessCommand(uint32_t command, size_t data_remaining) { ALOG("ProcessCommand: 0x%x", command); switch (command) { case BR_ERROR: { if (data_remaining < sizeof(int)) return false; uint32_t error_code = 0; if (!reader_.ReadUInt32(&error_code)) return false; ALOG("BR_ERROR: %d", error_code); break; } case BR_OK: ALOG("BR_OK"); break; case BR_TRANSACTION: break; case BR_REPLY: break; case BR_ACQUIRE_RESULT: break; case BR_DEAD_REPLY: break; case BR_TRANSACTION_COMPLETE: break; case BR_INCREFS: break; case BR_ACQUIRE: break; case BR_RELEASE: break; case BR_DECREFS: break; case BR_ATTEMPT_ACQUIRE: break; case BR_NOOP: ALOG("BR_NOOP"); break; case BR_SPAWN_LOOPER: break; case BR_FINISHED: break; case BR_DEAD_BINDER: break; case BR_CLEAR_DEATH_NOTIFICATION_DONE: break; case BR_FAILED_REPLY: ALOG("BR_FAILED_REPLY"); break; }; } } // namespace minibind