| /* |
| * Copyright (C) 2024 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. |
| */ |
| |
| #ifndef SRC_TRACE_REDACTION_PROCESS_THREAD_TIMELINE_H_ |
| #define SRC_TRACE_REDACTION_PROCESS_THREAD_TIMELINE_H_ |
| |
| #include <cstdint> |
| #include <limits> |
| #include <vector> |
| |
| namespace perfetto::trace_redaction { |
| |
| class ProcessThreadTimeline { |
| public: |
| // Opened and closed events are used to mark the start and end of lifespans. |
| struct Event { |
| public: |
| static constexpr auto kUnknownPid = std::numeric_limits<int32_t>::max(); |
| static constexpr auto kUnknownUid = std::numeric_limits<uint64_t>::max(); |
| |
| enum class Type { kInvalid, kOpen, kClose }; |
| |
| bool operator==(const Event& o) const { |
| switch (type) { |
| case Type::kOpen: |
| return o.type == Type::kOpen && ts == o.ts && pid == o.pid && |
| ppid == o.ppid && uid == o.uid; |
| |
| case Type::kClose: |
| return o.type == Type::kClose && ts == o.ts && pid == o.pid; |
| |
| case Type::kInvalid: |
| return o.type == Type::kInvalid; |
| } |
| |
| return false; |
| } |
| |
| bool operator!=(const Event& o) const { return !(*this == o); } |
| |
| bool valid() const { return type != Type::kInvalid; } |
| |
| static Event Open(uint64_t ts, int32_t pid, int32_t ppid, uint64_t uid) { |
| return {Type::kOpen, ts, pid, ppid, uid}; |
| } |
| |
| static Event Open(uint64_t ts, int32_t pid, int32_t ppid) { |
| return {Type::kOpen, ts, pid, ppid, kUnknownUid}; |
| } |
| |
| static Event Close(uint64_t ts, int32_t pid) { |
| return {Type::kClose, ts, pid, kUnknownPid, kUnknownUid}; |
| } |
| |
| Type type = Type::kInvalid; |
| |
| // The time when the event occured. Undefined when type is kInvalid. |
| uint64_t ts = 0; |
| |
| // The subject of the event. Undefined when type is kInvalid. |
| int32_t pid = kUnknownPid; |
| |
| // The parent of the subject. kUnknownPid if the parent is unknown. |
| // Undefined when type is kClose or kInvalid. |
| int32_t ppid = kUnknownPid; |
| |
| // The package containing the subject. kUnknownUid if the package is |
| // unknown. Undefined when type is kClose or kInvalid. |
| uint64_t uid = kUnknownUid; |
| }; |
| |
| ProcessThreadTimeline() = default; |
| |
| ProcessThreadTimeline(const ProcessThreadTimeline&) = delete; |
| ProcessThreadTimeline& operator=(const ProcessThreadTimeline&) = delete; |
| ProcessThreadTimeline(ProcessThreadTimeline&&) = delete; |
| ProcessThreadTimeline& operator=(ProcessThreadTimeline&&) = delete; |
| |
| void Append(const Event& event); |
| |
| // REQUIRED: Sorts all events by pid, making it possible to locate the subset |
| // of events connected to a pid. Events are not sorted by time because the |
| // subset of events will, on average, be trivally small. |
| void Sort(); |
| |
| // Returns true if a process/thread is connected to a package. |
| bool PidConnectsToUid(uint64_t ts, int32_t pid, uint64_t uid) const; |
| |
| // Get the opening event for a pid. If pid ends at ts, an opening event will |
| // still be returned. |
| const Event* GetOpeningEvent(uint64_t ts, int32_t pid) const; |
| |
| // SELECT MAX(ts), * FROM events WHERE pid=@pid AND type=@type AND ts<=@ts |
| const Event* QueryLeftMax(uint64_t ts, |
| int32_t pid, |
| ProcessThreadTimeline::Event::Type type) const; |
| |
| private: |
| enum class Mode { |
| // The timeline can safely be queried. If the timeline is in read mode, and |
| // a user writes to the timeline, the timeline will change to write mode. |
| kRead, |
| |
| // The timeline change be changed. If the timeline is not in write mode, |
| // reading from the timeline will throw an error. Sort() must be called to |
| // change the timeline from write to read mode. |
| kWrite |
| }; |
| |
| std::vector<Event> events_; |
| |
| Mode mode_ = Mode::kRead; |
| }; |
| |
| } // namespace perfetto::trace_redaction |
| |
| #endif // SRC_TRACE_REDACTION_PROCESS_THREAD_TIMELINE_H_ |