1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_METRICS_SYSTEM_SESSION_ANALYZER_SYSTEM_SESSION_ANALYZER_WIN_H_
6 #define COMPONENTS_METRICS_SYSTEM_SESSION_ANALYZER_SYSTEM_SESSION_ANALYZER_WIN_H_
7 
8 #include <windows.h>
9 
10 #include <winevt.h>
11 
12 #include <map>
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #include "base/gtest_prod_util.h"
18 #include "base/time/time.h"
19 
20 namespace metrics {
21 
22 // Analyzes system session events for unclean sessions. Initialization is
23 // expensive and therefore done lazily, as the analyzer is instantiated before
24 // knowing whether it will be used.
25 class SystemSessionAnalyzer {
26  public:
27   enum Status {
28     CLEAN = 0,
29     UNCLEAN = 1,
30     OUTSIDE_RANGE = 2,
31     INITIALIZE_FAILED = 3,
32     FETCH_EVENTS_FAILED = 4,
33     PROCESS_SESSION_FAILED = 5,
34     INSUFFICIENT_DATA = 6,
35   };
36 
37   // Track internal details of what went wrong.
38   enum class ExtendedStatus {
39     NO_FAILURE = 0,
40     RENDER_EVENT_FAILURE = 1,
41     ATTRIBUTE_CNT_MISMATCH = 2,
42     EXPECTED_INT16_TYPE = 3,
43     EXPECTED_FILETIME_TYPE = 4,
44     RETRIEVE_EVENTS_FAILURE = 5,
45     GET_EVENT_INFO_FAILURE = 6,
46     EVTQUERY_FAILED = 7,
47     CREATE_RENDER_CONTEXT_FAILURE = 8,
48     FETCH_EVENTS_FAILURE = 9,
49     EVENT_COUNT_MISMATCH = 10,
50     SESSION_START_MISMATCH = 11,
51     COVERAGE_START_ORDER_FAILURE = 12,
52     EVENT_ORDER_FAILURE = 13,
53     UNEXPECTED_START_EVENT_TYPE = 14,
54     UNEXPECTED_END_EVENT_TYPE = 15,
55   };
56 
57   ExtendedStatus GetExtendedFailureStatus() const;
58   // Set an extended failure status code for easier diagnosing of test failures.
59   // The first extended status code is retained.
60   void SetExtendedFailureStatus(ExtendedStatus);
61 
62   // Minimal information about a log event.
63   struct EventInfo {
64     uint16_t event_id;
65     base::Time event_time;
66   };
67 
68   // Creates a SystemSessionAnalyzer that will analyze system sessions based on
69   // events pertaining to as many as |max_session_cnt| of the most recent system
70   // sessions.
71   explicit SystemSessionAnalyzer(uint32_t max_session_cnt);
72 
73   SystemSessionAnalyzer(const SystemSessionAnalyzer&) = delete;
74   SystemSessionAnalyzer& operator=(const SystemSessionAnalyzer&) = delete;
75 
76   virtual ~SystemSessionAnalyzer();
77 
78   // Returns an analysis status for the system session that contains
79   // |timestamp|.
80   virtual Status IsSessionUnclean(base::Time timestamp);
81 
82  protected:
83   // Queries for the next |requested_events|. On success, returns true and
84   // |event_infos| contains up to |requested_events| events ordered from newest
85   // to oldest.
86   // Returns false otherwise. Virtual for unit testing.
87   virtual bool FetchEvents(size_t requested_events,
88                            std::vector<EventInfo>* event_infos);
89 
90  private:
91   struct EvtHandleCloser {
92     using pointer = EVT_HANDLE;
operatorEvtHandleCloser93     void operator()(EVT_HANDLE handle) const {
94       if (handle)
95         ::EvtClose(handle);
96     }
97   };
98   using EvtHandle = std::unique_ptr<EVT_HANDLE, EvtHandleCloser>;
99 
100   FRIEND_TEST_ALL_PREFIXES(SystemSessionAnalyzerTest, FetchEvents);
101 
102   bool EnsureInitialized();
103   bool EnsureHandlesOpened();
104   bool Initialize();
105   // Validates that |end| and |start| have sane event IDs and event times.
106   // Updates |coverage_start_| and adds the session to unclean_sessions_
107   // as appropriate.
108   bool ProcessSession(const EventInfo& end, const EventInfo& start);
109 
110   bool GetEventInfo(EVT_HANDLE context,
111                     EVT_HANDLE event,
112                     SystemSessionAnalyzer::EventInfo* info);
113   EvtHandle CreateRenderContext();
114 
115   // The maximal number of sessions to query events for.
116   uint32_t max_session_cnt_;
117   uint32_t sessions_queried_;
118 
119   bool initialized_ = false;
120   bool init_success_ = false;
121 
122   // A handle to the query, valid after a successful initialize.
123   EvtHandle query_handle_;
124   // A handle to the event render context, valid after a successful initialize.
125   EvtHandle render_context_;
126 
127   // Information about unclean sessions: start time to session duration.
128   std::map<base::Time, base::TimeDelta> unclean_sessions_;
129 
130   // Timestamp of the oldest event.
131   base::Time coverage_start_;
132 
133   // Track details of what failures occurred.
134   ExtendedStatus extended_status_ = ExtendedStatus::NO_FAILURE;
135 };
136 
137 }  // namespace metrics
138 
139 #endif  // COMPONENTS_METRICS_SYSTEM_SESSION_ANALYZER_SYSTEM_SESSION_ANALYZER_WIN_H_
140