• 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 <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{.pw_name = packageName, .pw_uid = it.first};
126             mNativeUidToPackageNameMapping.insert(std::make_pair(it.first, pwd));
127         }
128     }
129 
clearMappingCache()130     void clearMappingCache() {
131         for (const auto it : mNativeUidToPackageNameMapping) {
132             // Delete the previously allocated char array before clearing the mapping.
133             delete it.second.pw_name;
134         }
135         mNativeUidToPackageNameMapping.clear();
136     }
137 
138     std::shared_ptr<PackageInfoResolver> mPackageInfoResolver;
139     std::unordered_map<uid_t, struct passwd> mNativeUidToPackageNameMapping;
140 };
141 
142 }  // namespace internal
143 
144 class PackageInfoResolverTest : public ::testing::Test {
145 protected:
SetUp()146     virtual void SetUp() {
147         mPackageInfoResolver = PackageInfoResolver::getInstance();
148         mPackageInfoResolverPeer = std::make_unique<internal::PackageInfoResolverPeer>();
149         mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
150         ASSERT_NO_FATAL_FAILURE(
151                 mPackageInfoResolverPeer->initWatchdogServiceHelper(mMockWatchdogServiceHelper));
152     }
153 
TearDown()154     virtual void TearDown() {
155         PackageInfoResolver::terminate();
156         mPackageInfoResolverPeer.reset();
157         mMockWatchdogServiceHelper.clear();
158     }
159 
160     std::shared_ptr<PackageInfoResolverInterface> mPackageInfoResolver;
161     std::unique_ptr<internal::PackageInfoResolverPeer> mPackageInfoResolverPeer;
162     sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
163 };
164 
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsViaGetpwuid)165 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
166     PackageToAppCategoryMap packagesToAppCategories = {
167             // These mappings should be ignored for native packages.
168             {"system.package.B", ApplicationCategoryType::MAPS},
169             {"vendor.package.A", ApplicationCategoryType::MEDIA},
170             {"vendor.pkg.maps", ApplicationCategoryType::MAPS},
171     };
172     mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
173 
174     std::unordered_map<uid_t, PackageInfo> expectedMappings{
175             {7700,
176              constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
177                                   ApplicationCategoryType::OTHERS)},
178             {5100,
179              constructPackageInfo("vendor.package.A", 5100, UidType::NATIVE, ComponentType::VENDOR,
180                                   ApplicationCategoryType::OTHERS)},
181             {6700,
182              constructPackageInfo("vendor.package.B", 6700, UidType::NATIVE, ComponentType::VENDOR,
183                                   ApplicationCategoryType::OTHERS)},
184             {9997,
185              constructPackageInfo("vendor.pkg.C", 9997, UidType::NATIVE, ComponentType::VENDOR,
186                                   ApplicationCategoryType::OTHERS)},
187     };
188 
189     mPackageInfoResolverPeer->stubGetpwuid({{7700, "system.package.B"},
190                                             {5100, "vendor.package.A"},
191                                             {6700, "vendor.package.B"},
192                                             {9997, "vendor.pkg.C"}});
193     EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
194 
195     auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
196 
197     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
198             << "Expected: " << toString(expectedMappings)
199             << "\nActual: " << toString(actualMappings);
200 }
201 
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsViaWatchdogService)202 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
203     PackageToAppCategoryMap packagesToAppCategories = {
204             // system.package.B is native package so this should be ignored.
205             {"system.package.B", ApplicationCategoryType::MAPS},
206             {"vendor.package.A", ApplicationCategoryType::MEDIA},
207             {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
208             {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
209     };
210     mPackageInfoResolverPeer->setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
211     /*
212      * Shared UID should be resolved with car watchdog service as well to get the shared packages
213      * list.
214      */
215     mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
216 
217     std::unordered_map<uid_t, PackageInfo> expectedMappings{
218             {6100,
219              constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
220                                   ComponentType::SYSTEM, ApplicationCategoryType::OTHERS,
221                                   {"system.pkg.1", "system.pkg.2"})},
222             {7700,
223              constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
224                                   ApplicationCategoryType::OTHERS)},
225             {15100,
226              constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
227                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
228             {16700,
229              constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
230                                   ApplicationCategoryType::OTHERS)},
231             {18100,
232              constructPackageInfo("shared:vendor.package.C", 18100, UidType::APPLICATION,
233                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
234             {19100,
235              constructPackageInfo("shared:vendor.package.D", 19100, UidType::APPLICATION,
236                                   ComponentType::VENDOR, ApplicationCategoryType::OTHERS,
237                                   {"vendor.package.shared.uid.D"})},
238     };
239 
240     std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700, 18100, 19100};
241     std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
242     std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
243                                                    expectedMappings.at(7700),
244                                                    expectedMappings.at(15100),
245                                                    expectedMappings.at(16700),
246                                                    expectedMappings.at(18100),
247                                                    expectedMappings.at(19100)};
248 
249     expectedMappings.at(15100).appCategoryType = ApplicationCategoryType::MEDIA;
250     expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
251     expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
252 
253     EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(true));
254     EXPECT_CALL(*mMockWatchdogServiceHelper,
255                 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
256             .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos),
257                             Return(ByMove(ScopedAStatus::ok()))));
258 
259     auto actualMappings =
260             mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
261 
262     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
263             << "Expected: " << toString(expectedMappings)
264             << "\nActual: " << toString(actualMappings);
265 }
266 
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsWithoutWatchdogServiceHelper)267 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsWithoutWatchdogServiceHelper) {
268     internal::PackageInfoResolverPeer peer;
269     auto packageInfoResolver = PackageInfoResolver::getInstance();
270     mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
271 
272     std::unordered_map<uid_t, PackageInfo> expectedMappings{
273             {6100,
274              constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
275                                   ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
276     };
277 
278     mPackageInfoResolverPeer->resetWatchdogServiceHelper();
279 
280     EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
281 
282     auto actualMappings =
283             mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
284 
285     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
286             << "Expected: " << toString(expectedMappings)
287             << "\nActual: " << toString(actualMappings);
288 }
289 
TEST_F(PackageInfoResolverTest,TestGetPackageInfosForUidsMissingWatchdogServiceConnection)290 TEST_F(PackageInfoResolverTest, TestGetPackageInfosForUidsMissingWatchdogServiceConnection) {
291     internal::PackageInfoResolverPeer peer;
292     auto packageInfoResolver = PackageInfoResolver::getInstance();
293     mPackageInfoResolverPeer->stubGetpwuid({{6100, "shared:system.package.A"}});
294 
295     std::unordered_map<uid_t, PackageInfo> expectedMappings{
296             {6100,
297              constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
298                                   ComponentType::SYSTEM, ApplicationCategoryType::OTHERS, {})},
299     };
300 
301     EXPECT_CALL(*mMockWatchdogServiceHelper, isServiceConnected()).WillOnce(Return(false));
302     EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
303 
304     auto actualMappings =
305             mPackageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
306 
307     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
308             << "Expected: " << toString(expectedMappings)
309             << "\nActual: " << toString(actualMappings);
310 }
311 
TEST_F(PackageInfoResolverTest,TestResolvesApplicationUidFromLocalCache)312 TEST_F(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
313     internal::PackageInfoResolverPeer peer;
314     auto packageInfoResolver = PackageInfoResolver::getInstance();
315     std::unordered_map<uid_t, PackageInfo> expectedMappings{
316             {1003456,
317              constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
318                                   ApplicationCategoryType::OTHERS)}};
319     mPackageInfoResolverPeer->injectCacheMapping(expectedMappings);
320 
321     mPackageInfoResolverPeer->stubGetpwuid({});
322 
323     EXPECT_CALL(*mMockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
324 
325     auto actualMappings = mPackageInfoResolver->getPackageInfosForUids({1003456});
326 
327     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
328             << "Expected: " << toString(expectedMappings)
329             << "\nActual: " << toString(actualMappings);
330 }
331 
TEST_F(PackageInfoResolverTest,TestAsyncFetchPackageNamesForUids)332 TEST_F(PackageInfoResolverTest, TestAsyncFetchPackageNamesForUids) {
333     internal::PackageInfoResolverPeer peer;
334     auto packageInfoResolver = PackageInfoResolver::getInstance();
335     uid_t callingUid = 1003456;
336     std::unordered_map<uid_t, PackageInfo> expectedMappings{
337             {callingUid,
338              constructPackageInfo("vendor.package", callingUid, UidType::NATIVE,
339                                   ComponentType::SYSTEM, ApplicationCategoryType::OTHERS)}};
340     mPackageInfoResolverPeer->injectCacheMapping(expectedMappings);
341 
342     auto promise = std::promise<void>();
343     auto future = promise.get_future();
344 
345     mPackageInfoResolver->asyncFetchPackageNamesForUids({callingUid},
346                                                         [&](std::unordered_map<uid_t, std::string>
347                                                                     packageNames) {
348                                                             ASSERT_TRUE(
349                                                                     packageNames.find(callingUid) !=
350                                                                     packageNames.end());
351                                                             ASSERT_EQ(packageNames[callingUid],
352                                                                       "vendor.package");
353                                                             promise.set_value();
354                                                         });
355 
356     ASSERT_EQ(std::future_status::ready, future.wait_for(FETCH_PACKAGE_NAMES_TIMEOUT_SECS));
357 }
358 
359 }  // namespace watchdog
360 }  // namespace automotive
361 }  // namespace android
362