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