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