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