chromium/third_party/perfetto/src/trace_processor/importers/ftrace/binder_tracker.cc

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/importers/ftrace/binder_tracker.h"
#include <cstdint>
#include <optional>
#include <string>
#include <utility>
#include "perfetto/base/compiler.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/types/variadic.h"

// Binder tracker: displays slices for binder transactions and other operations.
// =============================================================================
//
// Supported events
// ----------------
// # Transactions
//
// * binder/binder_transaction
// * binder/binder_transaction_reply
//
// With these two events the tracker can display slices for binder transactions
// in the sending and receiving threads. Rarely, when transactions fail in some
// way, it's possible that the tracker doesn't have enough information to
// properly terminate slices. See "Commands" below for a solution.
//
// # Buffer allocations
//
// * binder/binder_transaction_alloc_buf
//
// This annotates the transaction slices (from the above events) with info about
// allocations. The event alone doesn't make sense without the "Transactions"
// events.
//
// # Commands
//
// * binder/binder_command
// * binder/binder_return
//
// These two events are only useful in conjunction with the "Transactions"
// events. Their presence allow the tracker to terminate slices more reliably
// when a transaction fails.
//
// # Locking
//
// * binder/binder_lock
// * binder/binder_locked
// * binder/binder_unlock
//
// Obsolete: this was removed from kernel v4.14
//
// Implementation details
// ----------------------
//
// # Basic transaction tracking:
//
// For each transaction, two threads are involved.
//
// A oneway (aka asynchronous) transaction has these events:
//
// ```
//      Thread Snd                                Thread Rcv
//         |                                         |
// binder_transaction(id, is_oneway)                 |
//                                                   |
//                                       binder_transaction_received(id)
// ```
//
// The tracker will create one instant events one each thread.
//
// A regular (aka synchronous) transaction has these events:
//
// ```
//      Thread Snd                                Thread Rcv
//         |                                         |
// binder_transaction(id)                            |
//         |                                         |
//         |                             binder_transaction_received(id)
//         |                                         |
//         |                             binder_transaction(other_id, is_reply)
//         |
// binder_transaction_received(other_id, is_reply)
// ```
//
// The tracker will create a "binder transaction" slice on Thread 1 and a
// "binder reply" slice on Thread 2.
//
// synchronous transactions can be nested: inside a "binder reply", a thread can
// make a binder transaction to another thread (just regular synchronous
// function calls).
//
// If a regular transaction fails, the kernel will not emit some events, causing
// the tracker to leave some slices open forever, while the threads are actually
// not working on the transaction anymore.
//
// ```
//      Thread Snd                                Thread Rcv
//         |                                         |
// binder_transaction(id)                            |
//         |                                         |
// ```
//
// or
//
// ```
//      Thread Snd                                Thread Rcv
//         |                                         |
// binder_transaction(id)                            |
//         |                                         |
//         |                             binder_transaction_received(id)
//         |                                         |
//         |                             binder_transaction(other_id, is_reply)
//         |
// ```
//
// In order to solve this problem (https://b.corp.google.com/issues/295124679),
// the tracker also understand commands and return commands. Binder commands are
// instructions that a userspace thread passes to the binder kernel driver (they
// all start with BC_), while binder return commands (they all start with BR_)
// are instructions that the binder kernel driver passes to the userspace
// thread.
//
// A synchronous transaction with commands and returns looks like this:
//
// ```
//      Thread Snd                                Thread Rcv
//         |                                         |
// binder_command(BC_TRANSACTION)                    |
//         |                                         |
// binder_transaction(id)                            |
//         |                                         |
//         |                             binder_transaction_received(id)
//         |                                         |
//         |                             binder_return(BR_TRANSACTION)
//         |                                         |
//         |                             binder_command(BC_REPLY)
//         |                                         |
//         |                             binder_transaction(other_id, is_reply)
//         |                                         |
//         |                             binder_return(BR_TRANSACTION_COMPLETE)
//         |                                         |
// binder_return(BR_TRANSACTION_COMPLETE)            |
//         |                                         |
// binder_transaction_received(other_id, is_reply)   |
//         |                                         |
// binder_return(BR_REPLY)
// ```
//
// For each thread, the tracker keeps a stack (since synchronous transactions
// can be nested). In case of failure, the tracker can observe special return
// commands (BR_DEAD_REPLY, BR_FROZEN_REPLY, ...): based on the state of the top
// of the stack it knows is it needs to terminate a slice.
//
// The tracking for commands and returns also tries to keep a correct stack, to
// avoid unbounded growth of the stack itself (even though it's internal only).
namespace perfetto {
namespace trace_processor {

namespace {
constexpr int kOneWay =;
constexpr int kRootObject =;
constexpr int kStatusCode =;
constexpr int kAcceptFds =;
constexpr int kNoFlags =;

std::string BinderFlagsToHuman(uint32_t flag) {}

}  // namespace

enum BinderTracker::TxnFrame::State : uint32_t {};

BinderTracker::BinderTracker(TraceProcessorContext* context)
    :{}

BinderTracker::~BinderTracker() = default;

void BinderTracker::Transaction(int64_t ts,
                                uint32_t tid,
                                int32_t transaction_id,
                                int32_t dest_node,
                                uint32_t dest_tgid,
                                uint32_t dest_tid,
                                bool is_reply,
                                uint32_t flags,
                                StringId code) {}

void BinderTracker::TransactionReceived(int64_t ts,
                                        uint32_t pid,
                                        int32_t transaction_id) {}

void BinderTracker::CommandToKernel(int64_t /*ts*/,
                                    uint32_t tid,
                                    uint32_t cmd) {}

void BinderTracker::ReturnFromKernel(int64_t ts, uint32_t tid, uint32_t cmd) {}

void BinderTracker::Lock(int64_t ts, uint32_t pid) {}

void BinderTracker::Locked(int64_t ts, uint32_t pid) {}

void BinderTracker::Unlock(int64_t ts, uint32_t pid) {}

void BinderTracker::TransactionAllocBuf(int64_t ts,
                                        uint32_t pid,
                                        uint64_t data_size,
                                        uint64_t offsets_size) {}

BinderTracker::TxnFrame* BinderTracker::GetTidTopFrame(uint32_t tid) {}

BinderTracker::TxnFrame* BinderTracker::PushTidFrame(uint32_t tid) {}

void BinderTracker::PopTidFrame(uint32_t tid) {}

}  // namespace trace_processor
}  // namespace perfetto