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