/* * 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