• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 #include "MockWatchdogServiceHelper.h"
18 #include "PackageInfoResolver.h"
19 #include "PackageInfoTestUtils.h"
20 
21 #include <android-base/stringprintf.h>
22 #include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
23 #include <android/automotive/watchdog/internal/ComponentType.h>
24 #include <android/automotive/watchdog/internal/UidType.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 
28 namespace android {
29 namespace automotive {
30 namespace watchdog {
31 
32 using ::android::sp;
33 using ::android::automotive::watchdog::internal::ApplicationCategoryType;
34 using ::android::automotive::watchdog::internal::ComponentType;
35 using ::android::automotive::watchdog::internal::PackageInfo;
36 using ::android::automotive::watchdog::internal::UidType;
37 using ::android::base::StringAppendF;
38 using ::testing::_;
39 using ::testing::DoAll;
40 using ::testing::NotNull;
41 using ::testing::Pair;
42 using ::testing::Return;
43 using ::testing::SetArgPointee;
44 using ::testing::UnorderedElementsAre;
45 using ::testing::UnorderedElementsAreArray;
46 
47 namespace {
48 
49 using PackageToAppCategoryMap =
50         std::unordered_map<std::string,
51                            android::automotive::watchdog::internal::ApplicationCategoryType>;
52 
toString(const std::unordered_map<uid_t,PackageInfo> & mappings)53 std::string toString(const std::unordered_map<uid_t, PackageInfo>& mappings) {
54     std::string buffer = "{";
55     for (const auto& [uid, info] : mappings) {
56         if (buffer.size() > 1) {
57             StringAppendF(&buffer, ", ");
58         }
59         StringAppendF(&buffer, "{%d: %s}", uid, info.toString().c_str());
60     }
61     StringAppendF(&buffer, "}");
62     return buffer;
63 }
64 
65 }  // namespace
66 
67 namespace internal {
68 
69 class PackageInfoResolverPeer final {
70 public:
PackageInfoResolverPeer()71     PackageInfoResolverPeer() {
72         PackageInfoResolver::getInstance();
73         mPackageInfoResolver = PackageInfoResolver::sInstance;
74         mockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
75         mPackageInfoResolver->initWatchdogServiceHelper(mockWatchdogServiceHelper);
76     }
77 
~PackageInfoResolverPeer()78     ~PackageInfoResolverPeer() {
79         PackageInfoResolver::sInstance.clear();
80         PackageInfoResolver::sGetpwuidHandler = &getpwuid;
81         clearMappingCache();
82     }
83 
injectCacheMapping(const std::unordered_map<uid_t,PackageInfo> & mapping)84     void injectCacheMapping(const std::unordered_map<uid_t, PackageInfo>& mapping) {
85         mPackageInfoResolver->mUidToPackageInfoMapping = mapping;
86     }
87 
setPackageConfigurations(const std::unordered_set<std::string> & vendorPackagePrefixes,const PackageToAppCategoryMap & packagesToAppCategories)88     void setPackageConfigurations(const std::unordered_set<std::string>& vendorPackagePrefixes,
89                                   const PackageToAppCategoryMap& packagesToAppCategories) {
90         mPackageInfoResolver->setPackageConfigurations(vendorPackagePrefixes,
91                                                        packagesToAppCategories);
92     }
93 
stubGetpwuid(const std::unordered_map<uid_t,std::string> & nativeUidToPackageNameMapping)94     void stubGetpwuid(const std::unordered_map<uid_t, std::string>& nativeUidToPackageNameMapping) {
95         updateNativeUidToPackageNameMapping(nativeUidToPackageNameMapping);
96         PackageInfoResolver::sGetpwuidHandler = [&](uid_t uid) -> struct passwd* {
97             const auto& it = mNativeUidToPackageNameMapping.find(uid);
98             if (it == mNativeUidToPackageNameMapping.end()) {
99                 return nullptr;
100             }
101             return &it->second;
102         };
103     }
104 
105     sp<MockWatchdogServiceHelper> mockWatchdogServiceHelper;
106 
107 private:
updateNativeUidToPackageNameMapping(const std::unordered_map<uid_t,std::string> & mapping)108     void updateNativeUidToPackageNameMapping(
109             const std::unordered_map<uid_t, std::string>& mapping) {
110         clearMappingCache();
111         for (const auto& it : mapping) {
112             size_t packageNameLen = it.second.size() + 1;
113             char* packageName = new char[packageNameLen];
114             if (packageName == nullptr) {
115                 continue;
116             }
117             memset(packageName, 0, packageNameLen);
118             snprintf(packageName, packageNameLen, "%s", it.second.c_str());
119 
120             struct passwd pwd {
121                 .pw_name = packageName, .pw_uid = it.first
122             };
123             mNativeUidToPackageNameMapping.insert(std::make_pair(it.first, pwd));
124         }
125     }
126 
clearMappingCache()127     void clearMappingCache() {
128         for (const auto it : mNativeUidToPackageNameMapping) {
129             // Delete the previously allocated char array before clearing the mapping.
130             delete it.second.pw_name;
131         }
132         mNativeUidToPackageNameMapping.clear();
133     }
134 
135     sp<PackageInfoResolver> mPackageInfoResolver;
136     std::unordered_map<uid_t, struct passwd> mNativeUidToPackageNameMapping;
137 };
138 
139 }  // namespace internal
140 
TEST(PackageInfoResolverTest,TestGetPackageInfosForUidsViaGetpwuid)141 TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
142     internal::PackageInfoResolverPeer peer;
143     auto packageInfoResolver = PackageInfoResolver::getInstance();
144     PackageToAppCategoryMap packagesToAppCategories = {
145             // These mappings should be ignored for native packages.
146             {"system.package.B", ApplicationCategoryType::MAPS},
147             {"vendor.package.A", ApplicationCategoryType::MEDIA},
148             {"vendor.pkg.maps", ApplicationCategoryType::MAPS},
149     };
150     peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
151 
152     std::unordered_map<uid_t, PackageInfo> expectedMappings{
153             {7700,
154              constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
155                                   ApplicationCategoryType::OTHERS)},
156             {5100,
157              constructPackageInfo("vendor.package.A", 5100, UidType::NATIVE, ComponentType::VENDOR,
158                                   ApplicationCategoryType::OTHERS)},
159             {6700,
160              constructPackageInfo("vendor.package.B", 6700, UidType::NATIVE, ComponentType::VENDOR,
161                                   ApplicationCategoryType::OTHERS)},
162             {9997,
163              constructPackageInfo("vendor.pkg.C", 9997, UidType::NATIVE, ComponentType::VENDOR,
164                                   ApplicationCategoryType::OTHERS)},
165     };
166 
167     peer.stubGetpwuid({{7700, "system.package.B"},
168                        {5100, "vendor.package.A"},
169                        {6700, "vendor.package.B"},
170                        {9997, "vendor.pkg.C"}});
171     EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
172 
173     auto actualMappings = packageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
174 
175     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
176             << "Expected: " << toString(expectedMappings)
177             << "\nActual: " << toString(actualMappings);
178 }
179 
TEST(PackageInfoResolverTest,TestGetPackageInfosForUidsViaWatchdogService)180 TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
181     internal::PackageInfoResolverPeer peer;
182     auto packageInfoResolver = PackageInfoResolver::getInstance();
183     PackageToAppCategoryMap packagesToAppCategories = {
184             // system.package.B is native package so this should be ignored.
185             {"system.package.B", ApplicationCategoryType::MAPS},
186             {"vendor.package.A", ApplicationCategoryType::MEDIA},
187             {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
188             {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
189     };
190     peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
191     /*
192      * Shared UID should be resolved with car watchdog service as well to get the shared packages
193      * list.
194      */
195     peer.stubGetpwuid({{6100, "shared:system.package.A"}});
196 
197     std::unordered_map<uid_t, PackageInfo> expectedMappings{
198             {6100,
199              constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
200                                   ComponentType::SYSTEM, ApplicationCategoryType::OTHERS,
201                                   {"system.pkg.1", "system.pkg.2"})},
202             {7700,
203              constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
204                                   ApplicationCategoryType::OTHERS)},
205             {15100,
206              constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
207                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
208             {16700,
209              constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
210                                   ApplicationCategoryType::OTHERS)},
211             {18100,
212              constructPackageInfo("shared:vendor.package.C", 18100, UidType::APPLICATION,
213                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
214             {19100,
215              constructPackageInfo("shared:vendor.package.D", 19100, UidType::APPLICATION,
216                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS,
217                                   {"vendor.package.shared.uid.D"})},
218     };
219 
220     std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700, 18100, 19100};
221     std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
222     std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
223                                                    expectedMappings.at(7700),
224                                                    expectedMappings.at(15100),
225                                                    expectedMappings.at(16700),
226                                                    expectedMappings.at(18100),
227                                                    expectedMappings.at(19100)};
228 
229     expectedMappings.at(15100).appCategoryType = ApplicationCategoryType::MEDIA;
230     expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
231     expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
232 
233     EXPECT_CALL(*peer.mockWatchdogServiceHelper,
234                 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
235             .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos), Return(binder::Status::ok())));
236 
237     auto actualMappings =
238             packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
239 
240     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
241             << "Expected: " << toString(expectedMappings)
242             << "\nActual: " << toString(actualMappings);
243 }
244 
TEST(PackageInfoResolverTest,TestResolvesApplicationUidFromLocalCache)245 TEST(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
246     internal::PackageInfoResolverPeer peer;
247     auto packageInfoResolver = PackageInfoResolver::getInstance();
248     std::unordered_map<uid_t, PackageInfo> expectedMappings{
249             {1003456,
250              constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
251                                   ApplicationCategoryType::OTHERS)}};
252     peer.injectCacheMapping(expectedMappings);
253 
254     peer.stubGetpwuid({});
255     EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
256 
257     auto actualMappings = packageInfoResolver->getPackageInfosForUids({1003456});
258 
259     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
260             << "Expected: " << toString(expectedMappings)
261             << "\nActual: " << toString(actualMappings);
262 }
263 
264 }  // namespace watchdog
265 }  // namespace automotive
266 }  // namespace android
267