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 <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/stringprintf.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27
28 #include <future> // NOLINT(build/c++11)
29
30 namespace android {
31 namespace automotive {
32 namespace watchdog {
33
34 using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
35 using ::aidl::android::automotive::watchdog::internal::ComponentType;
36 using ::aidl::android::automotive::watchdog::internal::PackageInfo;
37 using ::aidl::android::automotive::watchdog::internal::UidType;
38 using ::android::sp;
39 using ::android::base::StringAppendF;
40 using ::ndk::ScopedAStatus;
41 using ::testing::_;
42 using ::testing::ByMove;
43 using ::testing::DoAll;
44 using ::testing::NotNull;
45 using ::testing::Pair;
46 using ::testing::Return;
47 using ::testing::SetArgPointee;
48 using ::testing::UnorderedElementsAre;
49 using ::testing::UnorderedElementsAreArray;
50
51 namespace {
52
53 constexpr std::chrono::seconds FETCH_PACKAGE_NAMES_TIMEOUT_SECS = 1s;
54
55 using PackageToAppCategoryMap =
56 std::unordered_map<std::string,
57 aidl::android::automotive::watchdog::internal::ApplicationCategoryType>;
58
toString(const std::unordered_map<uid_t,PackageInfo> & mappings)59 std::string toString(const std::unordered_map<uid_t, PackageInfo>& mappings) {
60 std::string buffer = "{";
61 for (const auto& [uid, info] : mappings) {
62 if (buffer.size() > 1) {
63 StringAppendF(&buffer, ", ");
64 }
65 StringAppendF(&buffer, "{%d: %s}", uid, info.toString().c_str());
66 }
67 StringAppendF(&buffer, "}");
68 return buffer;
69 }
70
71 } // namespace
72
73 namespace internal {
74
75 class PackageInfoResolverPeer final {
76 public:
PackageInfoResolverPeer()77 PackageInfoResolverPeer() { mPackageInfoResolver = PackageInfoResolver::sInstance; }
78
~PackageInfoResolverPeer()79 ~PackageInfoResolverPeer() {
80 PackageInfoResolver::sGetpwuidHandler = &getpwuid;
81 clearMappingCache();
82 }
83
initWatchdogServiceHelper(const sp<WatchdogServiceHelperInterface> & watchdogServiceHelper)84 void initWatchdogServiceHelper(
85 const sp<WatchdogServiceHelperInterface>& watchdogServiceHelper) {
86 ASSERT_RESULT_OK(mPackageInfoResolver->initWatchdogServiceHelper(watchdogServiceHelper));
87 }
88
resetWatchdogServiceHelper()89 void resetWatchdogServiceHelper() { mPackageInfoResolver->mWatchdogServiceHelper = nullptr; }
90
injectCacheMapping(const std::unordered_map<uid_t,PackageInfo> & mapping)91 void injectCacheMapping(const std::unordered_map<uid_t, PackageInfo>& mapping) {
92 mPackageInfoResolver->mUidToPackageInfoMapping = mapping;
93 }
94
setPackageConfigurations(const std::unordered_set<std::string> & vendorPackagePrefixes,const PackageToAppCategoryMap & packagesToAppCategories)95 void setPackageConfigurations(const std::unordered_set<std::string>& vendorPackagePrefixes,
96 const PackageToAppCategoryMap& packagesToAppCategories) {
97 mPackageInfoResolver->setPackageConfigurations(vendorPackagePrefixes,
98 packagesToAppCategories);
99 }
100
stubGetpwuid(const std::unordered_map<uid_t,std::string> & nativeUidToPackageNameMapping)101 void stubGetpwuid(const std::unordered_map<uid_t, std::string>& nativeUidToPackageNameMapping) {
102 updateNativeUidToPackageNameMapping(nativeUidToPackageNameMapping);
103 PackageInfoResolver::sGetpwuidHandler = [&](uid_t uid) -> struct passwd* {
104 const auto& it = mNativeUidToPackageNameMapping.find(uid);
105 if (it == mNativeUidToPackageNameMapping.end()) {
106 return nullptr;
107 }
108 return &it->second;
109 };
110 }
111
112 private:
updateNativeUidToPackageNameMapping(const std::unordered_map<uid_t,std::string> & mapping)113 void updateNativeUidToPackageNameMapping(
114 const std::unordered_map<uid_t, std::string>& mapping) {
115 clearMappingCache();
116 for (const auto& it : mapping) {
117 size_t packageNameLen = it.second.size() + 1;
118 char* packageName = new char[packageNameLen];
119 if (packageName == nullptr) {
120 continue;
121 }
122 memset(packageName, 0, packageNameLen);
123 snprintf(packageName, packageNameLen, "%s", it.second.c_str());
124
125 struct passwd pwd {
126 .pw_name = packageName, .pw_uid = it.first
127 };
128 mNativeUidToPackageNameMapping.insert(std::make_pair(it.first, pwd));
129 }
130 }
131
clearMappingCache()132 void clearMappingCache() {
133 for (const auto it : mNativeUidToPackageNameMapping) {
134 // Delete the previously allocated char array before clearing the mapping.
135 delete it.second.pw_name;
136 }
137 mNativeUidToPackageNameMapping.clear();
138 }
139
140 sp<PackageInfoResolver> mPackageInfoResolver;
141 std::unordered_map<uid_t, struct passwd> mNativeUidToPackageNameMapping;
142 };
143
144 } // namespace internal
145
146 class PackageInfoResolverTest : public ::testing::Test {
147 protected:
SetUp()148 virtual void SetUp() {
149 mPackageInfoResolver = PackageInfoResolver::getInstance();
150 mPackageInfoResolverPeer = std::make_unique<internal::PackageInfoResolverPeer>();
151 mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
152 ASSERT_NO_FATAL_FAILURE(
153 mPackageInfoResolverPeer->initWatchdogServiceHelper(mMockWatchdogServiceHelper));
154 }
155
TearDown()156 virtual void TearDown() {
157 PackageInfoResolver::terminate();
158 mPackageInfoResolverPeer.reset();
159 mMockWatchdogServiceHelper.clear();
160 }
161
162 sp<PackageInfoResolverInterface> mPackageInfoResolver;
163 std::unique_ptr<internal::PackageInfoResolverPeer> mPackageInfoResolverPeer;
164 sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
165 };
166
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsViaGetpwuid)167 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
168 PackageToAppCategoryMap packagesToAppCategories = {
169 // These mappings should be ignored for native packages.
170 {"system.package.B", ApplicationCategoryType::MAPS},
171 {"vendor.package.A", ApplicationCategoryType::MEDIA},
172 {"vendor.pkg.maps", ApplicationCategoryType::MAPS},
173 };
174 mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
175
176 std::unordered_map<uid_t, PackageInfo> expectedMappings{
177 {7700,
178 constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
179 ApplicationCategoryType::OTHERS)},
180 {5100,
181 constructPackageInfo("vendor.package.A", 5100, UidType::NATIVE, ComponentType::VENDOR,
182 ApplicationCategoryType::OTHERS)},
183 {6700,
184 constructPackageInfo("vendor.package.B", 6700, UidType::NATIVE, ComponentType::VENDOR,
185 ApplicationCategoryType::OTHERS)},
186 {9997,
187 constructPackageInfo("vendor.pkg.C", 9997, UidType::NATIVE, ComponentType::VENDOR,
188 ApplicationCategoryType::OTHERS)},
189 };
190
191 mPackageInfoResolverPeer->stubGetpwuid({{7700, "system.package.B"},
192 {5100, "vendor.package.A"},
193 {6700, "vendor.package.B"},
194 {9997, "vendor.pkg.C"}});
195 EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
196
197 auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
198
199 EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
200 << "Expected: " << toString(expectedMappings)
201 << "\nActual: " << toString(actualMappings);
202 }
203
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsViaWatchdogService)204 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
205 PackageToAppCategoryMap packagesToAppCategories = {
206 // system.package.B is native package so this should be ignored.
207 {"system.package.B", ApplicationCategoryType::MAPS},
208 {"vendor.package.A", ApplicationCategoryType::MEDIA},
209 {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
210 {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
211 };
212 mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
213 /*
214 * Shared UID should be resolved with car watchdog service as well to get the shared packages
215 * list.
216 */
217 mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
218
219 std::unordered_map<uid_t, PackageInfo> expectedMappings{
220 {6100,
221 constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
222 ComponentType::SYSTEM, ApplicationCategoryType::OTHERS,
223 {"system.pkg.1", "system.pkg.2"})},
224 {7700,
225 constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
226 ApplicationCategoryType::OTHERS)},
227 {15100,
228 constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
229 ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
230 {16700,
231 constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
232 ApplicationCategoryType::OTHERS)},
233 {18100,
234 constructPackageInfo("shared:vendor.package.C", 18100, UidType::APPLICATION,
235 ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
236 {19100,
237 constructPackageInfo("shared:vendor.package.D", 19100, UidType::APPLICATION,
238 ComponentType::VENDOR, ApplicationCategoryType::OTHERS,
239 {"vendor.package.shared.uid.D"})},
240 };
241
242 std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700, 18100, 19100};
243 std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
244 std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
245 expectedMappings.at(7700),
246 expectedMappings.at(15100),
247 expectedMappings.at(16700),
248 expectedMappings.at(18100),
249 expectedMappings.at(19100)};
250
251 expectedMappings.at(15100).appCategoryType = ApplicationCategoryType::MEDIA;
252 expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
253 expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
254
255 EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(true));
256 EXPECT_CALL(*mMockWatchdogServiceHelper,
257 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
258 .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos),
259 Return(ByMove(ScopedAStatus::ok()))));
260
261 auto actualMappings =
262 mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
263
264 EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
265 << "Expected: " << toString(expectedMappings)
266 << "\nActual: " << toString(actualMappings);
267 }
268
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsWithoutWatchdogServiceHelper)269 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsWithoutWatchdogServiceHelper) {
270 internal::PackageInfoResolverPeer peer;
271 auto packageInfoResolver = PackageInfoResolver::getInstance();
272 mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
273
274 std::unordered_map<uid_t, PackageInfo> expectedMappings{
275 {6100,
276 constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
277 ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
278 };
279
280 mPackageInfoResolverPeer->resetWatchdogServiceHelper();
281
282 EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
283
284 auto actualMappings =
285 mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
286
287 EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
288 << "Expected: " << toString(expectedMappings)
289 << "\nActual: " << toString(actualMappings);
290 }
291
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsMissingWatchdogServiceConnection)292 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsMissingWatchdogServiceConnection) {
293 internal::PackageInfoResolverPeer peer;
294 auto packageInfoResolver = PackageInfoResolver::getInstance();
295 mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
296
297 std::unordered_map<uid_t, PackageInfo> expectedMappings{
298 {6100,
299 constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
300 ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
301 };
302
303 EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(false));
304 EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
305
306 auto actualMappings =
307 mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
308
309 EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
310 << "Expected: " << toString(expectedMappings)
311 << "\nActual: " << toString(actualMappings);
312 }
313
TEST_F(PackageInfoResolverTest,TestResolvesApplicationUidFromLocalCache)314 TEST_F(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
315 internal::PackageInfoResolverPeer peer;
316 auto packageInfoResolver = PackageInfoResolver::getInstance();
317 std::unordered_map<uid_t, PackageInfo> expectedMappings{
318 {1003456,
319 constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
320 ApplicationCategoryType::OTHERS)}};
321 mPackageInfoResolverPeer->injectCacheMapping(expectedMappings);
322
323 mPackageInfoResolverPeer->stubGetpwuid({});
324
325 EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
326
327 auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({1003456});
328
329 EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
330 << "Expected: " << toString(expectedMappings)
331 << "\nActual: " << toString(actualMappings);
332 }
333
TEST_F(PackageInfoResolverTest,TestAsyncFetchPackageNamesForUids)334 TEST_F(PackageInfoResolverTest, TestAsyncFetchPackageNamesForUids) {
335 internal::PackageInfoResolverPeer peer;
336 auto packageInfoResolver = PackageInfoResolver::getInstance();
337 uid_t callingUid = 1003456;
338 std::unordered_map<uid_t, PackageInfo> expectedMappings{
339 {callingUid,
340 constructPackageInfo("vendor.package", callingUid, UidType::NATIVE,
341 ComponentType::SYSTEM, ApplicationCategoryType::OTHERS)}};
342 mPackageInfoResolverPeer->injectCacheMapping(expectedMappings);
343
344 auto promise = std::promise<void>();
345 auto future = promise.get_future();
346
347 mPackageInfoResolver->asyncFetchPackageNamesForUids({callingUid},
348 [&](std::unordered_map<uid_t, std::string>
349 packageNames) {
350 ASSERT_TRUE(
351 packageNames.find(callingUid) !=
352 packageNames.end());
353 ASSERT_EQ(packageNames[callingUid],
354 "vendor.package");
355 promise.set_value();
356 });
357
358 ASSERT_EQ(std::future_status::ready, future.wait_for(FETCH_PACKAGE_NAMES_TIMEOUT_SECS));
359 }
360
361 } // namespace watchdog
362 } // namespace automotive
363 } // namespace android
364