David Chen | de70169 | 2017-10-05 13:16:02 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, versionCode 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 | #include "UidMap.h" |
| 18 | #include <cutils/log.h> |
| 19 | #include <utils/Errors.h> |
| 20 | |
| 21 | using namespace android; |
| 22 | |
| 23 | namespace android { |
| 24 | namespace os { |
| 25 | namespace statsd { |
| 26 | |
| 27 | bool UidMap::hasApp(int uid, const string& packageName) const { |
| 28 | lock_guard<mutex> lock(mMutex); |
| 29 | |
| 30 | auto range = mMap.equal_range(uid); |
| 31 | for (auto it = range.first; it != range.second; ++it) { |
| 32 | if (it->second.packageName == packageName) { |
| 33 | return true; |
| 34 | } |
| 35 | } |
| 36 | return false; |
| 37 | } |
| 38 | |
| 39 | int UidMap::getAppVersion(int uid, const string& packageName) const { |
| 40 | lock_guard<mutex> lock(mMutex); |
| 41 | |
| 42 | auto range = mMap.equal_range(uid); |
| 43 | for (auto it = range.first; it != range.second; ++it) { |
| 44 | if (it->second.packageName == packageName) { |
| 45 | return it->second.versionCode; |
| 46 | } |
| 47 | } |
| 48 | return 0; |
| 49 | } |
| 50 | |
| 51 | void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &versionCode, |
| 52 | const vector <String16> &packageName) { |
| 53 | lock_guard<mutex> lock(mMutex); // Exclusively lock for updates. |
| 54 | |
| 55 | mMap.clear(); |
| 56 | for (unsigned long j=0; j<uid.size(); j++) { |
| 57 | mMap.insert(make_pair(uid[j], AppData(string(String8(packageName[j]).string()), |
| 58 | versionCode[j]))); |
| 59 | } |
| 60 | |
| 61 | if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto |
| 62 | for (unsigned long j=0; j<uid.size(); j++) { |
| 63 | auto t = mOutput.add_initial(); |
| 64 | t->set_app(string(String8(packageName[j]).string())); |
| 65 | t->set_version(int(versionCode[j])); |
| 66 | t->set_uid(uid[j]); |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode){ |
| 72 | lock_guard<mutex> lock(mMutex); |
| 73 | |
| 74 | string app = string(String8(app_16).string()); |
| 75 | |
| 76 | // Notify any interested producers that this app has updated |
| 77 | for (auto it : mSubscribers) { |
| 78 | it->notifyAppUpgrade(app, uid, versionCode); |
| 79 | } |
| 80 | |
| 81 | auto log = mOutput.add_changes(); |
| 82 | log->set_deletion(false); |
| 83 | //log.timestamp = TODO: choose how timestamps are computed |
| 84 | log->set_app(app); |
| 85 | log->set_uid(uid); |
| 86 | log->set_version(versionCode); |
| 87 | |
| 88 | auto range = mMap.equal_range(int(uid)); |
| 89 | for (auto it = range.first; it != range.second; ++it) { |
| 90 | if (it->second.packageName == app) { |
| 91 | it->second.versionCode = int(versionCode); |
| 92 | return; |
| 93 | } |
| 94 | ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid); |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | // Otherwise, we need to add an app at this uid. |
| 99 | mMap.insert(make_pair(uid, AppData(app, int(versionCode)))); |
| 100 | } |
| 101 | |
| 102 | |
| 103 | void UidMap::removeApp(const String16& app_16, const int32_t& uid){ |
| 104 | lock_guard<mutex> lock(mMutex); |
| 105 | |
| 106 | string app = string(String8(app_16).string()); |
| 107 | |
| 108 | auto log = mOutput.add_changes(); |
| 109 | log->set_deletion(true); |
| 110 | //log.timestamp = TODO: choose how timestamps are computed |
| 111 | log->set_app(app); |
| 112 | log->set_uid(uid); |
| 113 | |
| 114 | auto range = mMap.equal_range(int(uid)); |
| 115 | for (auto it = range.first; it != range.second; ++it) { |
| 116 | if (it->second.packageName == app) { |
| 117 | mMap.erase(it); |
| 118 | return; |
| 119 | } |
| 120 | } |
| 121 | ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid); |
| 122 | return; |
| 123 | } |
| 124 | |
| 125 | void UidMap::addListener(sp<PackageInfoListener> producer) { |
| 126 | lock_guard<mutex> lock(mMutex); // Lock for updates |
| 127 | mSubscribers.insert(producer); |
| 128 | } |
| 129 | |
| 130 | void UidMap::removeListener(sp<PackageInfoListener> producer) { |
| 131 | lock_guard<mutex> lock(mMutex); // Lock for updates |
| 132 | mSubscribers.erase(producer); |
| 133 | } |
| 134 | |
| 135 | UidMapping UidMap::getAndClearOutput() { |
| 136 | lock_guard<mutex> lock(mMutex); // Lock for updates |
| 137 | |
| 138 | auto ret = UidMapping(mOutput); // Copy that will be returned. |
| 139 | mOutput.Clear(); |
| 140 | |
| 141 | // Re-initialize the initial state for the outputs. This results in extra data being uploaded |
| 142 | // but helps ensure we can't re-construct the UID->app name, versionCode mapping in server. |
| 143 | for (auto it : mMap) { |
| 144 | auto t = mOutput.add_initial(); |
| 145 | t->set_app(it.second.packageName); |
| 146 | t->set_version(it.second.versionCode); |
| 147 | t->set_uid(it.first); |
| 148 | } |
| 149 | |
| 150 | return ret; |
| 151 | } |
| 152 | |
| 153 | void UidMap::printUidMap(FILE* out) { |
| 154 | lock_guard<mutex> lock(mMutex); |
| 155 | |
| 156 | for (auto it : mMap) { |
| 157 | fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode, it.first); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | |
| 162 | } // namespace statsd |
| 163 | } // namespace os |
| 164 | } // namespace android |