blob: 1770c696daf9bf2bbbdab3f26d4bcdb19db13d21 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_COBALT_BIN_APP_TIMER_MANAGER_H_
#define SRC_COBALT_BIN_APP_TIMER_MANAGER_H_
#include <fuchsia/cobalt/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <stdlib.h>
#include <chrono>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <unordered_map>
namespace cobalt {
// Used to store all necessary values for a Timer to be able to log an Event.
struct TimerVal {
// The metric_id of the event we will create.
uint32_t metric_id;
// The encoding_id used in the event we will log.
uint32_t encoding_id;
// The event_code for the event.
uint32_t event_code;
// The component for the event.
std::string component;
// When the timer starts.
int64_t start_timestamp;
// When the timer ends.
int64_t end_timestamp;
// The time at which the timer is expired.
zx::time expiry_time;
// Task which will delete the timer once it is expired.
async::TaskClosure expiry_task;
// The name of the timer field/part if it is a multipart obervation.
std::string part_name;
// Stores the start-related arguments in the given TimerVal.
void AddStart(uint32_t metric_id, uint32_t event_code, const std::string& component,
uint32_t encoding_id, int64_t timestamp);
// Stores the end-related arguments in the given TimerVal.
void AddEnd(int64_t timestamp, const std::string& part_name);
};
// Stores partial timer values as they are encountered. Once both the start and
// end value of the timer have been encountered the timer's values are returned
// as a TimerVal.
class TimerManager {
public:
// Constructs a TimerManager Object. Uses the given dispatcher to
// schedule tasks which delete timer data once it has expired.
TimerManager(async_dispatcher_t* dispatcher);
// In some situations (e.g. fuzzing) the currently active dispatcher may change over time. Rather
// than constructing a new TimerManager each time, we just update the dispatcher.
void UpdateDispatcher(async_dispatcher_t* dispatcher) { dispatcher_ = dispatcher; };
~TimerManager();
// Checks if the given TimerVal contains all the information it needs to log
// an event. That means it was populated by both StartTimer and EndTimer
// calls.
static bool isReady(const std::unique_ptr<TimerVal>& timer_val_ptr);
// Checks that the arguments are valid timer arguments.
static bool isValidTimerArguments(fidl::StringPtr timer_id, int64_t timestamp,
uint32_t timeout_s);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the start data and resets the TimerVal ptr. If a timer with the
// same timer_id and different start timestamp exists it returns
// FAILED_PRECONDITION. If timer_ID or timeout_s is invalid, returns
// INVALID_ARGUMENTS.
fuchsia::cobalt::Status GetTimerValWithStart(
uint32_t metric_id, uint32_t event_code, const std::string& component,
uint32_t encoding_id, const std::string& timer_id, int64_t timestamp,
uint32_t timeout_s, std::unique_ptr<TimerVal>* timer_val_ptr);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the end data and resets the TimerVal ptr. If a timer with the
// same timer_id and different end timestamp exists it returns an error.
fuchsia::cobalt::Status GetTimerValWithEnd(
const std::string& timer_id, int64_t timestamp, uint32_t timeout_s,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the end data and resets the TimerVal ptr. If a timer with the
// same timer_id and different end timestamp exists it returns an error.
fuchsia::cobalt::Status GetTimerValWithEnd(
const std::string& timer_id, int64_t timestamp, uint32_t timeout_s,
const std::string& part_name, std::unique_ptr<TimerVal>* timer_val_ptr);
private:
// Schedules a task which will delete the timer entries associated with
// timer_id when it expires.
// timeout_s : the timer timer_id will be deleted after timeout_s seconds.
// timer_val_ptr : the task will be stored in the given object until it is
// executed or cancelled. Deleting the TimerVal will cancel
// the task.
void ScheduleExpiryTask(const std::string& timer_id, uint32_t timeout_s,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Copies the data found in the iterator entry to the TimerVal pointer
// provided. It then deletes the data associated with it from the map, which
// includes cancelling the pending expiry task.
void MoveTimerToTimerVal(
std::unordered_map<std::string, std::unique_ptr<TimerVal>>::iterator* timer_val_iter,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Map from timer_id to the TimerVal values associated with it.
std::unordered_map<std::string, std::unique_ptr<TimerVal>> timer_values_;
// Async dispatcher used for deleting expired timer entries.
async_dispatcher_t* dispatcher_; // not owned.
};
} // namespace cobalt
#endif // SRC_COBALT_BIN_APP_TIMER_MANAGER_H_