• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2020, 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 LOG_TAG "carwatchdogd"
18 
19 #include "PackageInfoResolver.h"
20 
21 #include <aidl/android/automotive/watchdog/internal/ApplicationCategoryType.h>
22 #include <aidl/android/automotive/watchdog/internal/ComponentType.h>
23 #include <aidl/android/automotive/watchdog/internal/UidType.h>
24 #include <android-base/strings.h>
25 #include <cutils/android_filesystem_config.h>
26 
27 #include <inttypes.h>
28 
29 #include <iterator>
30 #include <string_view>
31 
32 namespace android {
33 namespace automotive {
34 namespace watchdog {
35 
36 using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
37 using ::aidl::android::automotive::watchdog::internal::ComponentType;
38 using ::aidl::android::automotive::watchdog::internal::PackageInfo;
39 using ::aidl::android::automotive::watchdog::internal::UidType;
40 using ::android::sp;
41 using ::android::base::Error;
42 using ::android::base::Result;
43 using ::android::base::StartsWith;
44 
45 using GetpwuidFunction = std::function<struct passwd*(uid_t)>;
46 using PackageToAppCategoryMap = std::unordered_map<std::string, ApplicationCategoryType>;
47 
48 namespace {
49 
50 constexpr const char* kSharedPackagePrefix = "shared:";
51 
getComponentTypeForNativeUid(uid_t uid,std::string_view packageName,const std::vector<std::string> & vendorPackagePrefixes)52 ComponentType getComponentTypeForNativeUid(uid_t uid, std::string_view packageName,
53                                            const std::vector<std::string>& vendorPackagePrefixes) {
54     for (const auto& prefix : vendorPackagePrefixes) {
55         if (StartsWith(packageName, prefix)) {
56             return ComponentType::VENDOR;
57         }
58     }
59     if ((uid >= AID_OEM_RESERVED_START && uid <= AID_OEM_RESERVED_END) ||
60         (uid >= AID_OEM_RESERVED_2_START && uid <= AID_OEM_RESERVED_2_END) ||
61         (uid >= AID_ODM_RESERVED_START && uid <= AID_ODM_RESERVED_END)) {
62         return ComponentType::VENDOR;
63     }
64     /**
65      * There are no third party native services. Thus all non-vendor services are considered system
66      * services.
67      */
68     return ComponentType::SYSTEM;
69 }
70 
getPackageInfoForNativeUid(uid_t uid,const std::vector<std::string> & vendorPackagePrefixes,const GetpwuidFunction & getpwuidHandler)71 Result<PackageInfo> getPackageInfoForNativeUid(
72         uid_t uid, const std::vector<std::string>& vendorPackagePrefixes,
73         const GetpwuidFunction& getpwuidHandler) {
74     PackageInfo packageInfo;
75     passwd* usrpwd = getpwuidHandler(uid);
76     if (!usrpwd) {
77         return Error() << "Failed to fetch package name";
78     }
79     const char* packageName = usrpwd->pw_name;
80     packageInfo.packageIdentifier.name = packageName;
81     packageInfo.packageIdentifier.uid = uid;
82     packageInfo.uidType = UidType::NATIVE;
83     packageInfo.componentType =
84             getComponentTypeForNativeUid(uid, packageName, vendorPackagePrefixes);
85     packageInfo.appCategoryType = ApplicationCategoryType::OTHERS;
86     packageInfo.sharedUidPackages = {};
87 
88     return packageInfo;
89 }
90 
91 }  // namespace
92 
93 sp<PackageInfoResolver> PackageInfoResolver::sInstance = nullptr;
94 GetpwuidFunction PackageInfoResolver::sGetpwuidHandler = &getpwuid;
95 
getInstance()96 sp<PackageInfoResolverInterface> PackageInfoResolver::getInstance() {
97     if (sInstance == nullptr) {
98         sInstance = sp<PackageInfoResolver>::make();
99     }
100     return sInstance;
101 }
102 
terminate()103 void PackageInfoResolver::terminate() {
104     sInstance.clear();
105 }
106 
initWatchdogServiceHelper(const sp<WatchdogServiceHelperInterface> & watchdogServiceHelper)107 Result<void> PackageInfoResolver::initWatchdogServiceHelper(
108         const sp<WatchdogServiceHelperInterface>& watchdogServiceHelper) {
109     std::unique_lock writeLock(mRWMutex);
110     if (watchdogServiceHelper == nullptr) {
111         return Error() << "Must provide a non-null watchdog service helper instance";
112     }
113     if (mWatchdogServiceHelper != nullptr) {
114         return Error() << "Duplicate initialization";
115     }
116     mWatchdogServiceHelper = watchdogServiceHelper;
117     return {};
118 }
119 
setPackageConfigurations(const std::unordered_set<std::string> & vendorPackagePrefixes,const PackageToAppCategoryMap & packagesToAppCategories)120 void PackageInfoResolver::setPackageConfigurations(
121         const std::unordered_set<std::string>& vendorPackagePrefixes,
122         const PackageToAppCategoryMap& packagesToAppCategories) {
123     std::unique_lock writeLock(mRWMutex);
124     mVendorPackagePrefixes.clear();
125     std::copy(vendorPackagePrefixes.begin(), vendorPackagePrefixes.end(),
126               std::back_inserter(mVendorPackagePrefixes));
127     mPackagesToAppCategories = packagesToAppCategories;
128     // Clear the package info cache as the package configurations have changed.
129     mUidToPackageInfoMapping.clear();
130 }
131 
updatePackageInfos(const std::vector<uid_t> & uids)132 void PackageInfoResolver::updatePackageInfos(const std::vector<uid_t>& uids) {
133     std::unique_lock writeLock(mRWMutex);
134     std::vector<int32_t> missingUids;
135     for (const uid_t uid : uids) {
136         if (mUidToPackageInfoMapping.find(uid) != mUidToPackageInfoMapping.end()) {
137             continue;
138         }
139         if (uid >= AID_APP_START) {
140             missingUids.emplace_back(static_cast<int32_t>(uid));
141             continue;
142         }
143         auto result = getPackageInfoForNativeUid(uid, mVendorPackagePrefixes,
144                                                  PackageInfoResolver::sGetpwuidHandler);
145         if (!result.ok()) {
146             missingUids.emplace_back(static_cast<int32_t>(uid));
147             continue;
148         }
149         mUidToPackageInfoMapping[uid] = *result;
150         if (StartsWith(result->packageIdentifier.name, kSharedPackagePrefix)) {
151             // When the UID is shared, poll car watchdog service to fetch the shared packages info.
152             missingUids.emplace_back(static_cast<int32_t>(uid));
153         }
154     }
155 
156     /*
157      * There is delay between creating package manager instance and initializing watchdog service
158      * helper. Thus check the watchdog service helper instance before proceeding further.
159      */
160     if (missingUids.empty() || mWatchdogServiceHelper == nullptr ||
161         !mWatchdogServiceHelper->isServiceConnected()) {
162         return;
163     }
164 
165     std::vector<PackageInfo> packageInfos;
166     auto status =
167             mWatchdogServiceHelper->getPackageInfosForUids(missingUids, mVendorPackagePrefixes,
168                                                            &packageInfos);
169     if (!status.isOk()) {
170         ALOGE("Failed to fetch package infos from car watchdog service: %s", status.getMessage());
171         return;
172     }
173     for (auto& packageInfo : packageInfos) {
174         const auto& id = packageInfo.packageIdentifier;
175         if (id.name.empty()) {
176             continue;
177         }
178         if (packageInfo.uidType == UidType::APPLICATION) {
179             if (const auto it = mPackagesToAppCategories.find(id.name);
180                 it != mPackagesToAppCategories.end()) {
181                 packageInfo.appCategoryType = it->second;
182             } else if (!packageInfo.sharedUidPackages.empty()) {
183                 /* The recommendation for the OEMs is to define the application category mapping
184                  * by the shared package names. However, this a fallback to catch if any mapping is
185                  * defined by the individual package name.
186                  */
187                 for (const auto& packageName : packageInfo.sharedUidPackages) {
188                     if (const auto it = mPackagesToAppCategories.find(packageName);
189                         it != mPackagesToAppCategories.end()) {
190                         packageInfo.appCategoryType = it->second;
191                         break;
192                     }
193                 }
194             }
195         }
196         mUidToPackageInfoMapping[id.uid] = packageInfo;
197     }
198 }
199 
getPackageNamesForUids(const std::vector<uid_t> & uids)200 std::unordered_map<uid_t, std::string> PackageInfoResolver::getPackageNamesForUids(
201         const std::vector<uid_t>& uids) {
202     std::unordered_map<uid_t, std::string> uidToPackageNameMapping;
203     if (uids.empty()) {
204         return uidToPackageNameMapping;
205     }
206     updatePackageInfos(uids);
207     {
208         std::shared_lock readLock(mRWMutex);
209         for (const auto& uid : uids) {
210             if (mUidToPackageInfoMapping.find(uid) != mUidToPackageInfoMapping.end()) {
211                 uidToPackageNameMapping[uid] =
212                         mUidToPackageInfoMapping.at(uid).packageIdentifier.name;
213             }
214         }
215     }
216     return uidToPackageNameMapping;
217 }
218 
getPackageInfosForUids(const std::vector<uid_t> & uids)219 std::unordered_map<uid_t, PackageInfo> PackageInfoResolver::getPackageInfosForUids(
220         const std::vector<uid_t>& uids) {
221     std::unordered_map<uid_t, PackageInfo> uidToPackageInfoMapping;
222     if (uids.empty()) {
223         return uidToPackageInfoMapping;
224     }
225     updatePackageInfos(uids);
226     {
227         std::shared_lock readLock(mRWMutex);
228         for (const auto& uid : uids) {
229             if (mUidToPackageInfoMapping.find(uid) != mUidToPackageInfoMapping.end()) {
230                 uidToPackageInfoMapping[uid] = mUidToPackageInfoMapping.at(uid);
231             }
232         }
233     }
234     return uidToPackageInfoMapping;
235 }
236 
237 }  // namespace watchdog
238 }  // namespace automotive
239 }  // namespace android
240