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 
17 #define STATSD_DEBUG false  // STOPSHIP if true
18 #include "Log.h"
19 
20 #include "StateManager.h"
21 
22 #include <private/android_filesystem_config.h>
23 #include <statslog_statsd.h>
24 
25 #include <unordered_set>
26 
27 namespace android {
28 namespace os {
29 namespace statsd {
30 
StateManager()31 StateManager::StateManager()
32     : mAllowedPkg({
33               "com.android.systemui",
34       }) {
35 }
36 
getInstance()37 StateManager& StateManager::getInstance() {
38     static StateManager sStateManager;
39     return sStateManager;
40 }
41 
clear()42 void StateManager::clear() {
43     mStateTrackers.clear();
44 }
45 
onLogEvent(const LogEvent & event)46 void StateManager::onLogEvent(const LogEvent& event) {
47     // Only process state events from uids in AID_* and packages that are whitelisted in
48     // mAllowedPkg.
49     // Allowlisted AIDs are AID_ROOT and all AIDs in [1000, 2000) which is [AID_SYSTEM, AID_SHELL)
50     if (event.GetUid() == AID_ROOT ||
51         (event.GetUid() >= AID_SYSTEM && event.GetUid() < AID_SHELL) ||
52         mAllowedLogSources.find(event.GetUid()) != mAllowedLogSources.end()) {
53         const int tagId = event.GetTagId();
54         if (tagId == util::STATS_SOCKET_LOSS_REPORTED) {
55             // Hard coded logic to handle socket loss info to highlight metric corruption reason
56             const std::optional<SocketLossInfo>& lossInfo = toSocketLossInfo(event);
57             if (lossInfo) {
58                 handleSocketLossInfo(*lossInfo);
59             }
60         } else {
61             auto stateTrackersForEvent = mStateTrackers.find(tagId);
62             if (stateTrackersForEvent != mStateTrackers.end()) {
63                 stateTrackersForEvent->second->onLogEvent(event);
64             }
65         }
66     }
67 }
68 
handleSocketLossInfo(const SocketLossInfo & socketLossInfo)69 void StateManager::handleSocketLossInfo(const SocketLossInfo& socketLossInfo) {
70     // socketLossInfo stores atomId per UID - to eliminate duplicates using set
71     const std::unordered_set<int> uniqueLostAtomIds(socketLossInfo.atomIds.begin(),
72                                                     socketLossInfo.atomIds.end());
73 
74     // pass lost atom id to all relevant metrics
75     for (const auto lostAtomId : uniqueLostAtomIds) {
76         onLogEventLost(lostAtomId, DATA_CORRUPTED_SOCKET_LOSS);
77     }
78 }
79 
onLogEventLost(int32_t lostAtomId,DataCorruptedReason reason)80 bool StateManager::onLogEventLost(int32_t lostAtomId, DataCorruptedReason reason) {
81     auto stateTrackersIt = mStateTrackers.find(lostAtomId);
82     if (stateTrackersIt != mStateTrackers.end()) {
83         stateTrackersIt->second->onLogEventLost(reason);
84         return true;
85     }
86     return false;
87 }
88 
registerListener(const int32_t atomId,const wp<StateListener> & listener)89 void StateManager::registerListener(const int32_t atomId, const wp<StateListener>& listener) {
90     // Check if state tracker already exists.
91     if (mStateTrackers.find(atomId) == mStateTrackers.end()) {
92         mStateTrackers[atomId] = new StateTracker(atomId);
93     }
94     mStateTrackers[atomId]->registerListener(listener);
95 }
96 
unregisterListener(const int32_t atomId,const wp<StateListener> & listener)97 void StateManager::unregisterListener(const int32_t atomId, const wp<StateListener>& listener) {
98     std::unique_lock<std::mutex> lock(mMutex);
99 
100     // Hold the sp<> until the lock is released so that ~StateTracker() is
101     // not called while the lock is held.
102     sp<StateTracker> toRemove;
103 
104     // Unregister listener from correct StateTracker
105     auto it = mStateTrackers.find(atomId);
106     if (it != mStateTrackers.end()) {
107         it->second->unregisterListener(listener);
108 
109         // Remove the StateTracker if it has no listeners
110         if (it->second->getListenersCount() == 0) {
111             toRemove = it->second;
112             mStateTrackers.erase(it);
113         }
114     } else {
115         ALOGE("StateManager cannot unregister listener, StateTracker for atom %d does not exist",
116               atomId);
117     }
118     lock.unlock();
119 }
120 
getStateValue(const int32_t atomId,const HashableDimensionKey & key,FieldValue * output) const121 bool StateManager::getStateValue(const int32_t atomId, const HashableDimensionKey& key,
122                                  FieldValue* output) const {
123     auto it = mStateTrackers.find(atomId);
124     if (it != mStateTrackers.end()) {
125         return it->second->getStateValue(key, output);
126     }
127     ALOGE("StateManager cannot get state value, no StateTracker for atom %d", atomId);
128     return false;
129 }
130 
updateLogSources(const sp<UidMap> & uidMap)131 void StateManager::updateLogSources(const sp<UidMap>& uidMap) {
132     mAllowedLogSources.clear();
133     for (const auto& pkg : mAllowedPkg) {
134         auto uids = uidMap->getAppUid(pkg);
135         mAllowedLogSources.insert(uids.begin(), uids.end());
136     }
137 }
138 
notifyAppChanged(const string & apk,const sp<UidMap> & uidMap)139 void StateManager::notifyAppChanged(const string& apk, const sp<UidMap>& uidMap) {
140     if (mAllowedPkg.find(apk) != mAllowedPkg.end()) {
141         updateLogSources(uidMap);
142     }
143 }
144 
addAllAtomIds(LogEventFilter::AtomIdSet & allIds) const145 void StateManager::addAllAtomIds(LogEventFilter::AtomIdSet& allIds) const {
146     for (const auto& stateTracker : mStateTrackers) {
147         allIds.insert(stateTracker.first);
148     }
149 }
150 
151 }  // namespace statsd
152 }  // namespace os
153 }  // namespace android
154