blob: 6352ebef49d9d53f684658ba71e559faf6e51270 [file] [log] [blame]
/*
* 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_