blob: b17f6966ad1a66b3dd515ba325575f58ce648abd [file] [log] [blame]
// Copyright 2019 The Chromium OS 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 DIAGNOSTICS_ROUTINES_SUBPROC_ROUTINE_H_
#define DIAGNOSTICS_ROUTINES_SUBPROC_ROUTINE_H_
#include <cstdint>
#include <memory>
#include <string>
#include <base/command_line.h>
#include <base/macros.h>
#include <base/process/process.h>
#include <base/time/default_tick_clock.h>
#include "diagnostics/routines/diag_process_adapter.h"
#include "diagnostics/routines/diag_routine.h"
#include "wilco_dtc_supportd.pb.h" // NOLINT(build/include)
namespace diagnostics {
// Output messages for the routine when in various states.
extern const char kSubprocRoutineCancelled[];
extern const char kSubprocRoutineFailedMessage[];
extern const char kSubprocRoutineFailedToLaunchProcessMessage[];
extern const char kSubprocRoutineFailedToStopMessage[];
extern const char kSubprocRoutineInvalidParametersMessage[];
extern const char kSubprocRoutineProcessCrashedOrKilledMessage[];
extern const char kSubprocRoutineProcessCancellingMessage[];
extern const char kSubprocRoutineProcessRunningMessage[];
extern const char kSubprocRoutineReady[];
extern const char kSubprocRoutineSucceededMessage[];
// We don't always know when a SubprocRoutine should finish. Sometimes we have
// to fake our prediction of percent complete.
extern const int kSubprocRoutineFakeProgressPercentUnknown;
extern const int kSubprocRoutineFakeProgressPercentCancelling;
// Progress percentage when the routine has been running for equal to
// or longer than the time specified in the SubprocRoutineRoutineParameters, but
// has not stopped yet.
extern const int64_t kSubprocRoutineLongRunningProgress;
// The SubprocRoutine takes a command line to run. It is non-interactive, and
// this does not fully support Pause and Resume. Pause will simply kill the
// process. The exit code of the process is used to determine success or failure
// of the test. So, the "check" portion of the Routine must live inside the
// sub-process.
class SubprocRoutine final : public DiagnosticRoutine {
public:
// The state of the SubprocRoutine is modeled in the SubprocStatus enum.
enum SubprocStatus {
kSubprocStatusCancelled,
kSubprocStatusCancelling,
kSubprocStatusCompleteFailure,
kSubprocStatusCompleteSuccess,
kSubprocStatusError,
kSubprocStatusLaunchFailed,
kSubprocStatusReady,
kSubprocStatusRunning,
};
SubprocRoutine(const base::CommandLine& command_line,
int predicted_duration_in_seconds);
SubprocRoutine(std::unique_ptr<DiagProcessAdapter> process_adapter,
std::unique_ptr<base::TickClock> tick_clock,
const base::CommandLine& command_line,
int predicted_duration_in_seconds);
// DiagnosticRoutine overrides:
~SubprocRoutine() override;
void Start() override;
void Resume() override;
void Cancel() override;
void PopulateStatusUpdate(grpc_api::GetRoutineUpdateResponse* response,
bool include_output) override;
grpc_api::DiagnosticRoutineStatus GetStatus() override;
private:
// Functions to manipulate the child process.
void StartProcess();
void KillProcess(bool from_dtor);
// Handle state transitions due to process state within this object.
void CheckProcessStatus();
void CheckActiveProcessStatus();
int CalculateProgressPercent();
// |subproc_status_| is the state of the subproc as understood by the
// SubprocRoutine object's state machine. Essentially, this variable stores
// which state we are in.
SubprocStatus subproc_status_;
// |process_adapter_| is a dependency that is injected at object creation time
// which enables swapping out process control functionality for the main
// purpose of facilitating Unit tests.
std::unique_ptr<DiagProcessAdapter> process_adapter_;
// |tick_clock_| is a dependency that is injected at object creation time
// which enables swapping out time-tracking functionality for the main
// purpose of facilitating Unit tests.
std::unique_ptr<base::TickClock> tick_clock_;
// |command_line_| is the process which runs to test the diagnostic in
// question.
base::CommandLine command_line_;
// |predicted_duration_in_seconds_| is used to calculate progress percentage
// when it is non-zero.
int predicted_duration_in_seconds_ = 0;
// |last_reported_progress_percent_| is used to save the last reported
// progress percentage for handling progress reported across status changes.
int last_reported_progress_percent_ = 0;
// |handle_| keeps track of the running process.
base::ProcessHandle handle_ = base::kNullProcessHandle;
// |start_ticks_| records the time when the routine began. This is used with
// |predicted_duration_in_seconds_| to report on progress percentate.
base::TimeTicks start_ticks_;
DISALLOW_COPY_AND_ASSIGN(SubprocRoutine);
};
} // namespace diagnostics
#endif // DIAGNOSTICS_ROUTINES_SUBPROC_ROUTINE_H_