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 #include "HashableDimensionKey.h"
20 #include "logd/LogEvent.h"
21 
22 #include "state/StateListener.h"
23 
24 #include <unordered_map>
25 
26 namespace android {
27 namespace os {
28 namespace statsd {
29 
30 class StateTracker : public virtual RefBase {
31 public:
32     StateTracker(const int32_t atomId);
33 
~StateTracker()34     virtual ~StateTracker(){};
35 
36     // Updates state map and notifies all listeners if a state change occurs.
37     // Checks if a state change has occurred by getting the state value from
38     // the log event and comparing the old and new states.
39     void onLogEvent(const LogEvent& event);
40 
41     // Adds new listeners to set of StateListeners. If a listener is already
42     // registered, it is ignored.
43     void registerListener(wp<StateListener> listener);
44 
45     void unregisterListener(wp<StateListener> listener);
46 
47     // The output is a FieldValue object that has mStateField as the field and
48     // the original state value (found using the given query key) as the value.
49     //
50     // If the key isn't mapped to a state or the key size doesn't match the
51     // number of primary fields, the output value is set to kStateUnknown.
52     bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const;
53 
getListenersCount()54     inline int getListenersCount() const {
55         return mListeners.size();
56     }
57 
58     const static int kStateUnknown = -1;
59 
60 private:
61     struct StateValueInfo {
62         int32_t state = kStateUnknown;  // state value
63         int count = 0;                  // nested count (only used for binary states)
64     };
65 
66     Field mField;
67 
68     // Maps primary key to state value info
69     std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
70 
71     // Set of all StateListeners (objects listening for state changes)
72     std::set<wp<StateListener>> mListeners;
73 
74     // Reset all state values in map to the given state.
75     void handleReset(const int64_t eventTimeNs, const FieldValue& newState);
76 
77     // Clears the state value mapped to the given primary key by setting it to kStateUnknown.
78     void clearStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
79 
80     // Update the StateMap based on the received state value.
81     void updateStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
82                                   const FieldValue& newState, const bool nested,
83                                   StateValueInfo* stateValueInfo);
84 
85     // Notify registered state listeners of state change.
86     void notifyListeners(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
87                          const FieldValue& oldState, const FieldValue& newState);
88 };
89 
90 bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output);
91 
92 }  // namespace statsd
93 }  // namespace os
94 }  // namespace android
95