You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
11 KiB
261 lines
11 KiB
/*
|
|
* Copyright 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "MockWatchdogServiceHelper.h"
|
|
#include "PackageInfoResolver.h"
|
|
|
|
#include <android-base/stringprintf.h>
|
|
#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
|
|
#include <android/automotive/watchdog/internal/ComponentType.h>
|
|
#include <android/automotive/watchdog/internal/UidType.h>
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace android {
|
|
namespace automotive {
|
|
namespace watchdog {
|
|
|
|
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
|
|
using ::android::automotive::watchdog::internal::ComponentType;
|
|
using ::android::automotive::watchdog::internal::PackageInfo;
|
|
using ::android::automotive::watchdog::internal::UidType;
|
|
using ::android::base::StringAppendF;
|
|
using ::testing::_;
|
|
using ::testing::DoAll;
|
|
using ::testing::NotNull;
|
|
using ::testing::Pair;
|
|
using ::testing::Return;
|
|
using ::testing::SetArgPointee;
|
|
using ::testing::UnorderedElementsAre;
|
|
using ::testing::UnorderedElementsAreArray;
|
|
|
|
namespace {
|
|
|
|
using PackageToAppCategoryMap =
|
|
std::unordered_map<std::string,
|
|
android::automotive::watchdog::internal::ApplicationCategoryType>;
|
|
|
|
PackageInfo constructPackageInfo(const char* packageName, int32_t uid, UidType uidType,
|
|
ComponentType componentType,
|
|
ApplicationCategoryType appCategoryType,
|
|
std::vector<std::string> sharedUidPackages = {}) {
|
|
PackageInfo packageInfo;
|
|
packageInfo.packageIdentifier.name = packageName;
|
|
packageInfo.packageIdentifier.uid = uid;
|
|
packageInfo.uidType = uidType;
|
|
packageInfo.componentType = componentType;
|
|
packageInfo.appCategoryType = appCategoryType;
|
|
packageInfo.sharedUidPackages = sharedUidPackages;
|
|
return packageInfo;
|
|
}
|
|
|
|
std::string toString(const std::unordered_map<uid_t, PackageInfo>& mappings) {
|
|
std::string buffer = "{";
|
|
for (const auto& [uid, info] : mappings) {
|
|
if (buffer.size() > 1) {
|
|
StringAppendF(&buffer, ", ");
|
|
}
|
|
StringAppendF(&buffer, "{%d: %s}", uid, info.toString().c_str());
|
|
}
|
|
StringAppendF(&buffer, "}");
|
|
return buffer;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace internal {
|
|
|
|
class PackageInfoResolverPeer {
|
|
public:
|
|
PackageInfoResolverPeer() {
|
|
PackageInfoResolver::getInstance();
|
|
mPackageInfoResolver = PackageInfoResolver::sInstance;
|
|
mockWatchdogServiceHelper = new MockWatchdogServiceHelper();
|
|
mPackageInfoResolver->initWatchdogServiceHelper(mockWatchdogServiceHelper);
|
|
}
|
|
|
|
~PackageInfoResolverPeer() {
|
|
PackageInfoResolver::sInstance.clear();
|
|
PackageInfoResolver::sGetpwuidHandler = &getpwuid;
|
|
clearMappingCache();
|
|
}
|
|
|
|
void injectCacheMapping(const std::unordered_map<uid_t, PackageInfo>& mapping) {
|
|
mPackageInfoResolver->mUidToPackageInfoMapping = mapping;
|
|
}
|
|
|
|
void setPackageConfigurations(const std::unordered_set<std::string>& vendorPackagePrefixes,
|
|
const PackageToAppCategoryMap& packagesToAppCategories) {
|
|
mPackageInfoResolver->setPackageConfigurations(vendorPackagePrefixes,
|
|
packagesToAppCategories);
|
|
}
|
|
|
|
void stubGetpwuid(const std::unordered_map<uid_t, std::string>& nativeUidToPackageNameMapping) {
|
|
updateNativeUidToPackageNameMapping(nativeUidToPackageNameMapping);
|
|
PackageInfoResolver::sGetpwuidHandler = [&](uid_t uid) -> struct passwd* {
|
|
const auto& it = mNativeUidToPackageNameMapping.find(uid);
|
|
if (it == mNativeUidToPackageNameMapping.end()) {
|
|
return nullptr;
|
|
}
|
|
return &it->second;
|
|
};
|
|
}
|
|
|
|
sp<MockWatchdogServiceHelper> mockWatchdogServiceHelper;
|
|
|
|
private:
|
|
void updateNativeUidToPackageNameMapping(
|
|
const std::unordered_map<uid_t, std::string>& mapping) {
|
|
clearMappingCache();
|
|
for (const auto& it : mapping) {
|
|
char* packageName = new char[it.second.size() + 1];
|
|
if (packageName == nullptr) {
|
|
continue;
|
|
}
|
|
memset(packageName, 0, sizeof(packageName));
|
|
snprintf(packageName, it.second.size() + 1, "%s", it.second.c_str());
|
|
|
|
struct passwd pwd {
|
|
.pw_name = packageName, .pw_uid = it.first
|
|
};
|
|
mNativeUidToPackageNameMapping.insert(std::make_pair(it.first, pwd));
|
|
}
|
|
}
|
|
|
|
void clearMappingCache() {
|
|
for (const auto it : mNativeUidToPackageNameMapping) {
|
|
// Delete the previously allocated char array before clearing the mapping.
|
|
delete it.second.pw_name;
|
|
}
|
|
mNativeUidToPackageNameMapping.clear();
|
|
}
|
|
|
|
sp<PackageInfoResolver> mPackageInfoResolver;
|
|
std::unordered_map<uid_t, struct passwd> mNativeUidToPackageNameMapping;
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
|
|
internal::PackageInfoResolverPeer peer;
|
|
auto packageInfoResolver = PackageInfoResolver::getInstance();
|
|
PackageToAppCategoryMap packagesToAppCategories = {
|
|
// These mappings should be ignored for native packages.
|
|
{"system.package.B", ApplicationCategoryType::MAPS},
|
|
{"vendor.package.A", ApplicationCategoryType::MEDIA},
|
|
{"vendor.pkg.maps", ApplicationCategoryType::MAPS},
|
|
};
|
|
peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
|
|
|
|
std::unordered_map<uid_t, PackageInfo> expectedMappings{
|
|
{7700,
|
|
constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
|
|
ApplicationCategoryType::OTHERS)},
|
|
{5100,
|
|
constructPackageInfo("vendor.package.A", 5100, UidType::NATIVE, ComponentType::VENDOR,
|
|
ApplicationCategoryType::OTHERS)},
|
|
{6700,
|
|
constructPackageInfo("vendor.package.B", 6700, UidType::NATIVE, ComponentType::VENDOR,
|
|
ApplicationCategoryType::OTHERS)},
|
|
{9997,
|
|
constructPackageInfo("vendor.pkg.C", 9997, UidType::NATIVE, ComponentType::VENDOR,
|
|
ApplicationCategoryType::OTHERS)},
|
|
};
|
|
|
|
peer.stubGetpwuid({{7700, "system.package.B"},
|
|
{5100, "vendor.package.A"},
|
|
{6700, "vendor.package.B"},
|
|
{9997, "vendor.pkg.C"}});
|
|
EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
|
|
|
|
auto actualMappings = packageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
|
|
|
|
EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
|
|
<< "Expected: " << toString(expectedMappings)
|
|
<< "\nActual: " << toString(actualMappings);
|
|
}
|
|
|
|
TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
|
|
internal::PackageInfoResolverPeer peer;
|
|
auto packageInfoResolver = PackageInfoResolver::getInstance();
|
|
PackageToAppCategoryMap packagesToAppCategories = {
|
|
// system.package.B is native package so this should be ignored.
|
|
{"system.package.B", ApplicationCategoryType::MAPS},
|
|
{"vendor.package.A", ApplicationCategoryType::MEDIA},
|
|
};
|
|
peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
|
|
/*
|
|
* Shared UID should be resolved with car watchdog service as well to get the shared packages
|
|
* list.
|
|
*/
|
|
peer.stubGetpwuid({{6100, "shared:system.package.A"}});
|
|
|
|
std::unordered_map<uid_t, PackageInfo> expectedMappings{
|
|
{6100,
|
|
constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
|
|
ComponentType::SYSTEM, ApplicationCategoryType::OTHERS,
|
|
{"system.pkg.1", "system.pkg.2"})},
|
|
{7700,
|
|
constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
|
|
ApplicationCategoryType::OTHERS)},
|
|
{15100,
|
|
constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
|
|
ComponentType::VENDOR, ApplicationCategoryType::MEDIA)},
|
|
{16700,
|
|
constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
|
|
ApplicationCategoryType::OTHERS)},
|
|
};
|
|
|
|
std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700};
|
|
std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
|
|
std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
|
|
expectedMappings.at(7700),
|
|
expectedMappings.at(15100),
|
|
expectedMappings.at(16700)};
|
|
EXPECT_CALL(*peer.mockWatchdogServiceHelper,
|
|
getPackageInfosForUids(expectedUids, expectedPrefixes, _))
|
|
.WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos), Return(binder::Status::ok())));
|
|
|
|
auto actualMappings = packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700});
|
|
|
|
EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
|
|
<< "Expected: " << toString(expectedMappings)
|
|
<< "\nActual: " << toString(actualMappings);
|
|
}
|
|
|
|
TEST(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
|
|
internal::PackageInfoResolverPeer peer;
|
|
auto packageInfoResolver = PackageInfoResolver::getInstance();
|
|
std::unordered_map<uid_t, PackageInfo> expectedMappings{
|
|
{1003456,
|
|
constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
|
|
ApplicationCategoryType::OTHERS)}};
|
|
peer.injectCacheMapping(expectedMappings);
|
|
|
|
peer.stubGetpwuid({});
|
|
EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
|
|
|
|
auto actualMappings = packageInfoResolver->getPackageInfosForUids({1003456});
|
|
|
|
EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
|
|
<< "Expected: " << toString(expectedMappings)
|
|
<< "\nActual: " << toString(actualMappings);
|
|
}
|
|
|
|
} // namespace watchdog
|
|
} // namespace automotive
|
|
} // namespace android
|