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