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