1 /* 2 * Copyright (C) 2017 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 #pragma once 18 19 #include "config/ConfigKey.h" 20 #include "config/ConfigListener.h" 21 #include "packages/PackageInfoListener.h" 22 #include "stats_util.h" 23 24 #include <binder/IResultReceiver.h> 25 #include <binder/IShellCallback.h> 26 #include <gtest/gtest_prod.h> 27 #include <log/logprint.h> 28 #include <stdio.h> 29 #include <utils/RefBase.h> 30 #include <list> 31 #include <mutex> 32 #include <set> 33 #include <string> 34 #include <unordered_map> 35 36 using namespace android; 37 using namespace std; 38 39 using android::util::ProtoOutputStream; 40 41 namespace android { 42 namespace os { 43 namespace statsd { 44 45 struct AppData { 46 int64_t versionCode; 47 bool deleted; 48 49 // Empty constructor needed for unordered map. AppDataAppData50 AppData() { 51 } AppDataAppData52 AppData(const int64_t v) : versionCode(v), deleted(false){}; 53 }; 54 55 // When calling appendUidMap, we retrieve all the ChangeRecords since the last 56 // timestamp we called appendUidMap for this configuration key. 57 struct ChangeRecord { 58 const bool deletion; 59 const int64_t timestampNs; 60 const string package; 61 const int32_t uid; 62 const int64_t version; 63 const int64_t prevVersion; 64 ChangeRecordChangeRecord65 ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package, 66 const int32_t uid, const int64_t version, const int64_t prevVersion) 67 : deletion(isDeletion), 68 timestampNs(timestampNs), 69 package(package), 70 uid(uid), 71 version(version), 72 prevVersion(prevVersion) { 73 } 74 }; 75 76 const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord); 77 78 // UidMap keeps track of what the corresponding app name (APK name) and version code for every uid 79 // at any given moment. This map must be updated by StatsCompanionService. 80 class UidMap : public virtual android::RefBase { 81 public: 82 UidMap(); 83 ~UidMap(); 84 static const std::map<std::string, uint32_t> sAidToUidMapping; 85 /* 86 * All three inputs must be the same size, and the jth element in each array refers to the same 87 * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j]. 88 */ 89 void updateMap(const int64_t& timestamp, const vector<int32_t>& uid, 90 const vector<int64_t>& versionCode, const vector<String16>& packageName); 91 92 void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid, 93 const int64_t& versionCode); 94 void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid); 95 96 // Returns true if the given uid contains the specified app (eg. com.google.android.gms). 97 bool hasApp(int uid, const string& packageName) const; 98 99 // Returns the app names from uid. 100 std::set<string> getAppNamesFromUid(const int32_t& uid, bool returnNormalized) const; 101 102 int64_t getAppVersion(int uid, const string& packageName) const; 103 104 // Helper for debugging contents of this uid map. Can be triggered with: 105 // adb shell cmd stats print-uid-map 106 void printUidMap(FILE* out) const; 107 108 // Commands for indicating to the map that a producer should be notified if an app is updated. 109 // This allows the metric producer to distinguish when the same uid or app represents a 110 // different version of an app. 111 void addListener(wp<PackageInfoListener> producer); 112 // Remove the listener from the set of metric producers that subscribe to updates. 113 void removeListener(wp<PackageInfoListener> producer); 114 115 // Informs uid map that a config is added/updated. Used for keeping mConfigKeys up to date. 116 void OnConfigUpdated(const ConfigKey& key); 117 118 // Informs uid map that a config is removed. Used for keeping mConfigKeys up to date. 119 void OnConfigRemoved(const ConfigKey& key); 120 121 void assignIsolatedUid(int isolatedUid, int parentUid); 122 void removeIsolatedUid(int isolatedUid, int parentUid); 123 124 // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in. 125 virtual int getHostUidOrSelf(int uid) const; 126 127 // Gets all snapshots and changes that have occurred since the last output. 128 // If every config key has received a change or snapshot record, then this 129 // record is deleted. 130 void appendUidMap(const int64_t& timestamp, const ConfigKey& key, 131 std::set<string> *str_set, util::ProtoOutputStream* proto); 132 133 // Forces the output to be cleared. We still generate a snapshot based on the current state. 134 // This results in extra data uploaded but helps us reconstruct the uid mapping on the server 135 // in case we lose a previous upload. 136 void clearOutput(); 137 138 // Get currently cached value of memory used by UID map. 139 size_t getBytesUsed() const; 140 141 std::set<int32_t> getAppUid(const string& package) const; 142 143 private: 144 std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const; 145 string normalizeAppName(const string& appName) const; 146 147 void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output); 148 149 // TODO: Use shared_mutex for improved read-locking if a library can be found in Android. 150 mutable mutex mMutex; 151 mutable mutex mIsolatedMutex; 152 153 struct PairHash { operatorPairHash154 size_t operator()(std::pair<int, string> p) const noexcept { 155 std::hash<std::string> hash_fn; 156 return hash_fn(std::to_string(p.first) + p.second); 157 } 158 }; 159 // Maps uid and package name to application data. 160 std::unordered_map<std::pair<int, string>, AppData, PairHash> mMap; 161 162 // Maps isolated uid to the parent uid. Any metrics for an isolated uid will instead contribute 163 // to the parent uid. 164 std::unordered_map<int, int> mIsolatedUidMap; 165 166 // Record the changes that can be provided with the uploads. 167 std::list<ChangeRecord> mChanges; 168 169 // Store which uid and apps represent deleted ones. 170 std::list<std::pair<int, string>> mDeletedApps; 171 172 // Metric producers that should be notified if there's an upgrade in any app. 173 set<wp<PackageInfoListener>> mSubscribers; 174 175 // Mapping of config keys we're aware of to the epoch time they last received an update. This 176 // lets us know it's safe to delete events older than the oldest update. The value is nanosec. 177 // Value of -1 denotes this config key has never received an upload. 178 std::unordered_map<ConfigKey, int64_t> mLastUpdatePerConfigKey; 179 180 // Returns the minimum value from mConfigKeys. 181 int64_t getMinimumTimestampNs(); 182 183 // If our current used bytes is above the limit, then we clear out the earliest snapshot. If 184 // there are no more snapshots, then we clear out the earliest delta. We repeat the deletions 185 // until the memory consumed by mOutput is below the specified limit. 186 void ensureBytesUsedBelowLimit(); 187 188 // Override used for testing the max memory allowed by uid map. 0 means we use the value 189 // specified in StatsdStats.h with the rest of the guardrails. 190 size_t maxBytesOverride = 0; 191 192 // Cache the size of mOutput; 193 size_t mBytesUsed; 194 195 // Allows unit-test to access private methods. 196 FRIEND_TEST(UidMapTest, TestClearingOutput); 197 FRIEND_TEST(UidMapTest, TestRemovedAppRetained); 198 FRIEND_TEST(UidMapTest, TestRemovedAppOverGuardrail); 199 FRIEND_TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot); 200 FRIEND_TEST(UidMapTest, TestMemoryComputed); 201 FRIEND_TEST(UidMapTest, TestMemoryGuardrail); 202 }; 203 204 } // namespace statsd 205 } // namespace os 206 } // namespace android 207