1 /*
2  * Copyright (C) 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <utils/RefBase.h>
19 
20 #include <set>
21 #include <unordered_map>
22 
23 #include "HashableDimensionKey.h"
24 #include "logd/LogEvent.h"
25 #include "state/StateListener.h"
26 
27 namespace android {
28 namespace os {
29 namespace statsd {
30 
31 class StateTracker : public virtual RefBase {
32 public:
33     StateTracker(int32_t atomId);
34 
~StateTracker()35     virtual ~StateTracker(){};
36 
37     // Updates state map and notifies all listeners if a state change occurs.
38     // Checks if a state change has occurred by getting the state value from
39     // the log event and comparing the old and new states.
40     void onLogEvent(const LogEvent& event);
41 
42     void onLogEventLost(DataCorruptedReason reason);
43 
44     // Adds new listeners to set of StateListeners. If a listener is already
45     // registered, it is ignored.
46     void registerListener(const wp<StateListener>& listener);
47 
48     void unregisterListener(const wp<StateListener>& listener);
49 
50     // The output is a FieldValue object that has mStateField as the field and
51     // the original state value (found using the given query key) as the value.
52     //
53     // If the key isn't mapped to a state or the key size doesn't match the
54     // number of primary fields, the output value is set to kStateUnknown.
55     bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const;
56 
getListenersCount()57     inline int getListenersCount() const {
58         return mListeners.size();
59     }
60 
61     const static int kStateUnknown = -1;
62 
63 private:
64     struct StateValueInfo {
65         int32_t state = kStateUnknown;  // state value
66         int count = 0;                  // nested count (only used for binary states)
67     };
68 
69     Field mField;
70 
71     // Maps primary key to state value info
72     std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
73 
74     // Set of all StateListeners (objects listening for state changes)
75     std::set<wp<StateListener>> mListeners;
76 
77     // Reset all state values in map to the given state.
78     void handleReset(const int64_t eventTimeNs, const FieldValue& newState);
79 
80     // Clears the state value mapped to the given primary key by setting it to kStateUnknown.
81     void clearStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
82 
83     // Update the StateMap based on the received state value.
84     void updateStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
85                                   const FieldValue& newState, const bool nested,
86                                   StateValueInfo& stateValueInfo);
87 
88     // Notify registered state listeners of state change.
89     void notifyListeners(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
90                          const FieldValue& oldState, const FieldValue& newState);
91 };
92 
93 bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output);
94 
95 }  // namespace statsd
96 }  // namespace os
97 }  // namespace android
98