| /* |
| * Copyright (c) 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. |
| */ |
| |
| #define LOG_TAG "carwatchdogd" |
| |
| #include "IoOveruseConfigs.h" |
| |
| #include "OveruseConfigurationXmlHelper.h" |
| #include "PackageInfoResolver.h" |
| |
| #include <android-base/strings.h> |
| #include <log/log.h> |
| |
| #include <inttypes.h> |
| |
| #include <filesystem> |
| #include <limits> |
| |
| namespace android { |
| namespace automotive { |
| namespace watchdog { |
| |
| using ::android::automotive::watchdog::PerStateBytes; |
| using ::android::automotive::watchdog::internal::ApplicationCategoryType; |
| using ::android::automotive::watchdog::internal::ComponentType; |
| using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold; |
| using ::android::automotive::watchdog::internal::IoOveruseConfiguration; |
| using ::android::automotive::watchdog::internal::PackageInfo; |
| using ::android::automotive::watchdog::internal::PackageMetadata; |
| using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold; |
| using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration; |
| using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration; |
| using ::android::automotive::watchdog::internal::UidType; |
| using ::android::base::Error; |
| using ::android::base::Result; |
| using ::android::base::StartsWith; |
| using ::android::base::StringAppendF; |
| using ::android::base::StringPrintf; |
| using ::android::binder::Status; |
| |
| namespace { |
| |
| // Enum to filter the updatable overuse configs by each component. |
| enum OveruseConfigEnum { |
| COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES = 1 << 0, |
| VENDOR_PACKAGE_PREFIXES = 1 << 1, |
| PACKAGE_APP_CATEGORY_MAPPINGS = 1 << 2, |
| COMPONENT_SPECIFIC_GENERIC_THRESHOLDS = 1 << 3, |
| COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS = 1 << 4, |
| PER_CATEGORY_THRESHOLDS = 1 << 5, |
| SYSTEM_WIDE_ALERT_THRESHOLDS = 1 << 6, |
| }; |
| |
| const int32_t kSystemComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES | |
| PACKAGE_APP_CATEGORY_MAPPINGS | COMPONENT_SPECIFIC_GENERIC_THRESHOLDS | |
| COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | SYSTEM_WIDE_ALERT_THRESHOLDS; |
| const int32_t kVendorComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES | |
| VENDOR_PACKAGE_PREFIXES | PACKAGE_APP_CATEGORY_MAPPINGS | |
| COMPONENT_SPECIFIC_GENERIC_THRESHOLDS | COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | |
| PER_CATEGORY_THRESHOLDS; |
| const int32_t kThirdPartyComponentUpdatableConfigs = COMPONENT_SPECIFIC_GENERIC_THRESHOLDS; |
| |
| const std::vector<std::string> toStringVector(const std::unordered_set<std::string>& values) { |
| std::vector<std::string> output; |
| for (const auto& v : values) { |
| if (!v.empty()) { |
| output.emplace_back(v); |
| } |
| } |
| return output; |
| } |
| |
| bool isZeroValueThresholds(const PerStateIoOveruseThreshold& thresholds) { |
| return thresholds.perStateWriteBytes.foregroundBytes == 0 && |
| thresholds.perStateWriteBytes.backgroundBytes == 0 && |
| thresholds.perStateWriteBytes.garageModeBytes == 0; |
| } |
| |
| std::string toString(const PerStateIoOveruseThreshold& thresholds) { |
| return StringPrintf("name=%s, foregroundBytes=%" PRId64 ", backgroundBytes=%" PRId64 |
| ", garageModeBytes=%" PRId64, |
| thresholds.name.c_str(), thresholds.perStateWriteBytes.foregroundBytes, |
| thresholds.perStateWriteBytes.backgroundBytes, |
| thresholds.perStateWriteBytes.garageModeBytes); |
| } |
| |
| Result<void> containsValidThresholds(const PerStateIoOveruseThreshold& thresholds) { |
| if (thresholds.name.empty()) { |
| return Error() << "Doesn't contain threshold name"; |
| } |
| |
| if (isZeroValueThresholds(thresholds)) { |
| return Error() << "Zero value thresholds for " << thresholds.name; |
| } |
| |
| if (thresholds.perStateWriteBytes.foregroundBytes == 0 || |
| thresholds.perStateWriteBytes.backgroundBytes == 0 || |
| thresholds.perStateWriteBytes.garageModeBytes == 0) { |
| return Error() << "Some thresholds are zero: " << toString(thresholds); |
| } |
| return {}; |
| } |
| |
| Result<void> containsValidThreshold(const IoOveruseAlertThreshold& threshold) { |
| if (threshold.durationInSeconds == 0) { |
| return Error() << "Duration must be greater than zero"; |
| } |
| if (threshold.writtenBytesPerSecond == 0) { |
| return Error() << "Written bytes/second must be greater than zero"; |
| } |
| return {}; |
| } |
| |
| ApplicationCategoryType toApplicationCategoryType(const std::string& value) { |
| if (value == "MAPS") { |
| return ApplicationCategoryType::MAPS; |
| } |
| if (value == "MEDIA") { |
| return ApplicationCategoryType::MEDIA; |
| } |
| return ApplicationCategoryType::OTHERS; |
| } |
| |
| Result<void> isValidIoOveruseConfiguration(const ComponentType componentType, |
| const int32_t updatableConfigsFilter, |
| const IoOveruseConfiguration& ioOveruseConfig) { |
| auto componentTypeStr = toString(componentType); |
| if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS) { |
| if (auto result = containsValidThresholds(ioOveruseConfig.componentLevelThresholds); |
| !result.ok()) { |
| return Error() << "Invalid " << toString(componentType) |
| << " component level generic thresholds: " << result.error(); |
| } |
| if (ioOveruseConfig.componentLevelThresholds.name != componentTypeStr) { |
| return Error() << "Invalid component name " |
| << ioOveruseConfig.componentLevelThresholds.name |
| << " in component level generic thresholds for component " |
| << componentTypeStr; |
| } |
| } |
| const auto containsValidSystemWideThresholds = [&]() -> bool { |
| if (ioOveruseConfig.systemWideThresholds.empty()) { |
| return false; |
| } |
| for (const auto& threshold : ioOveruseConfig.systemWideThresholds) { |
| if (auto result = containsValidThreshold(threshold); !result.ok()) { |
| return false; |
| } |
| } |
| return true; |
| }; |
| if ((updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) && |
| !containsValidSystemWideThresholds()) { |
| return Error() << "Invalid system-wide alert threshold provided in " << componentTypeStr |
| << " config"; |
| } |
| return {}; |
| } |
| |
| Result<int32_t> getComponentFilter(const ComponentType componentType) { |
| switch (componentType) { |
| case ComponentType::SYSTEM: |
| return kSystemComponentUpdatableConfigs; |
| case ComponentType::VENDOR: |
| return kVendorComponentUpdatableConfigs; |
| case ComponentType::THIRD_PARTY: |
| return kThirdPartyComponentUpdatableConfigs; |
| default: |
| return Error() << "Invalid component type: " << static_cast<int32_t>(componentType); |
| } |
| } |
| |
| Result<void> isValidResourceOveruseConfig( |
| const ResourceOveruseConfiguration& resourceOveruseConfig) { |
| const auto filter = getComponentFilter(resourceOveruseConfig.componentType); |
| if (!filter.ok()) { |
| return Error() << filter.error(); |
| } |
| std::unordered_map<std::string, ApplicationCategoryType> seenCategoryMappings; |
| for (const auto& meta : resourceOveruseConfig.packageMetadata) { |
| if (const auto it = seenCategoryMappings.find(meta.packageName); |
| it != seenCategoryMappings.end() && it->second != meta.appCategoryType) { |
| return Error() |
| << "Must provide exactly one application category mapping for the package " |
| << meta.packageName << ": Provided mappings " << toString(meta.appCategoryType) |
| << " and " << toString(it->second); |
| } |
| seenCategoryMappings[meta.packageName] = meta.appCategoryType; |
| } |
| if (resourceOveruseConfig.resourceSpecificConfigurations.size() != 1) { |
| return Error() << "Must provide exactly one I/O overuse configuration. Received " |
| << resourceOveruseConfig.resourceSpecificConfigurations.size() |
| << " configurations"; |
| } |
| for (const auto& config : resourceOveruseConfig.resourceSpecificConfigurations) { |
| if (config.getTag() != ResourceSpecificConfiguration::ioOveruseConfiguration) { |
| return Error() << "Invalid resource type: " << config.getTag(); |
| } |
| const auto& ioOveruseConfig = |
| config.get<ResourceSpecificConfiguration::ioOveruseConfiguration>(); |
| if (auto result = isValidIoOveruseConfiguration(resourceOveruseConfig.componentType, |
| *filter, ioOveruseConfig); |
| !result.ok()) { |
| return Error() << "Invalid I/O overuse configuration for component " |
| << toString(resourceOveruseConfig.componentType).c_str() << ": " |
| << result.error(); |
| } |
| } |
| return {}; |
| } |
| |
| Result<void> isValidResourceOveruseConfigs( |
| const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) { |
| std::unordered_set<ComponentType> seenComponentTypes; |
| for (const auto& resourceOveruseConfig : resourceOveruseConfigs) { |
| if (seenComponentTypes.count(resourceOveruseConfig.componentType) > 0) { |
| return Error() << "Cannot provide duplicate configs for the same component type " |
| << toString(resourceOveruseConfig.componentType); |
| } |
| if (const auto result = isValidResourceOveruseConfig(resourceOveruseConfig); !result.ok()) { |
| return result; |
| } |
| seenComponentTypes.insert(resourceOveruseConfig.componentType); |
| } |
| return {}; |
| } |
| |
| } // namespace |
| |
| IoOveruseConfigs::ParseXmlFileFunction IoOveruseConfigs::sParseXmlFile = |
| &OveruseConfigurationXmlHelper::parseXmlFile; |
| IoOveruseConfigs::WriteXmlFileFunction IoOveruseConfigs::sWriteXmlFile = |
| &OveruseConfigurationXmlHelper::writeXmlFile; |
| |
| Result<void> ComponentSpecificConfig::updatePerPackageThresholds( |
| const std::vector<PerStateIoOveruseThreshold>& thresholds, |
| const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes) { |
| mPerPackageThresholds.clear(); |
| if (thresholds.empty()) { |
| return Error() << "\tNo per-package thresholds provided so clearing it\n"; |
| } |
| std::string errorMsgs; |
| for (const auto& packageThreshold : thresholds) { |
| if (packageThreshold.name.empty()) { |
| StringAppendF(&errorMsgs, "\tSkipping per-package threshold without package name\n"); |
| continue; |
| } |
| maybeAppendVendorPackagePrefixes(packageThreshold.name); |
| if (auto result = containsValidThresholds(packageThreshold); !result.ok()) { |
| StringAppendF(&errorMsgs, |
| "\tSkipping invalid package specific thresholds for package '%s': %s\n", |
| packageThreshold.name.c_str(), result.error().message().c_str()); |
| continue; |
| } |
| if (const auto& it = mPerPackageThresholds.find(packageThreshold.name); |
| it != mPerPackageThresholds.end()) { |
| StringAppendF(&errorMsgs, "\tDuplicate threshold received for package '%s'\n", |
| packageThreshold.name.c_str()); |
| } |
| mPerPackageThresholds[packageThreshold.name] = packageThreshold; |
| } |
| return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs; |
| } |
| |
| Result<void> ComponentSpecificConfig::updateSafeToKillPackages( |
| const std::vector<std::string>& packages, |
| const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes) { |
| mSafeToKillPackages.clear(); |
| if (packages.empty()) { |
| return Error() << "\tNo safe-to-kill packages provided so clearing it\n"; |
| } |
| std::string errorMsgs; |
| for (const auto& packageName : packages) { |
| if (packageName.empty()) { |
| StringAppendF(&errorMsgs, "\tSkipping empty safe-to-kill package name"); |
| continue; |
| } |
| maybeAppendVendorPackagePrefixes(packageName); |
| mSafeToKillPackages.insert(packageName); |
| } |
| return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs; |
| } |
| |
| IoOveruseConfigs::IoOveruseConfigs() : |
| mSystemConfig({}), |
| mVendorConfig({}), |
| mThirdPartyConfig({}), |
| mPackagesToAppCategories({}), |
| mPackagesToAppCategoryMappingUpdateMode(OVERWRITE), |
| mPerCategoryThresholds({}), |
| mVendorPackagePrefixes({}) { |
| const auto updateFromXmlPerType = [&](const char* filename, const char* configType) -> bool { |
| if (const auto result = this->updateFromXml(filename); !result.ok()) { |
| ALOGE("Failed to parse %s resource overuse configuration from '%s': %s", configType, |
| filename, result.error().message().c_str()); |
| return false; |
| } |
| ALOGI("Updated with %s resource overuse configuration from '%s'", configType, filename); |
| return true; |
| }; |
| /* |
| * Package to app category mapping is common between system and vendor component configs. When |
| * the build system and vendor component configs are used, the mapping shouldn't be |
| * overwritten by either of the configs because the build configurations defined by the |
| * vendor or system components may not be aware of mappings included in other component's |
| * config. Ergo, the mapping from both the component configs should be merged together. When a |
| * latest config is used for either of the components, the latest mapping should be given higher |
| * priority. |
| */ |
| bool isBuildSystemConfig = false; |
| if (!updateFromXmlPerType(kLatestSystemConfigXmlPath, "latest system")) { |
| isBuildSystemConfig = updateFromXmlPerType(kBuildSystemConfigXmlPath, "build system"); |
| } |
| if (!updateFromXmlPerType(kLatestVendorConfigXmlPath, "latest vendor")) { |
| mPackagesToAppCategoryMappingUpdateMode = isBuildSystemConfig ? MERGE : NO_UPDATE; |
| if (!updateFromXmlPerType(kBuildVendorConfigXmlPath, "build vendor") && |
| mSystemConfig.mGeneric.name != kDefaultThresholdName) { |
| mVendorConfig.mGeneric = mSystemConfig.mGeneric; |
| mVendorConfig.mGeneric.name = toString(ComponentType::VENDOR); |
| } |
| mPackagesToAppCategoryMappingUpdateMode = OVERWRITE; |
| } |
| if (!updateFromXmlPerType(kLatestThirdPartyConfigXmlPath, "latest third-party")) { |
| if (!updateFromXmlPerType(kBuildThirdPartyConfigXmlPath, "build third-party") && |
| mSystemConfig.mGeneric.name != kDefaultThresholdName) { |
| mThirdPartyConfig.mGeneric = mSystemConfig.mGeneric; |
| mThirdPartyConfig.mGeneric.name = toString(ComponentType::THIRD_PARTY); |
| } |
| } |
| } |
| |
| size_t IoOveruseConfigs::AlertThresholdHashByDuration::operator()( |
| const IoOveruseAlertThreshold& threshold) const { |
| return std::hash<std::string>{}(std::to_string(threshold.durationInSeconds)); |
| } |
| |
| bool IoOveruseConfigs::AlertThresholdEqualByDuration::operator()( |
| const IoOveruseAlertThreshold& l, const IoOveruseAlertThreshold& r) const { |
| return l.durationInSeconds == r.durationInSeconds; |
| } |
| |
| Result<void> IoOveruseConfigs::updatePerCategoryThresholds( |
| const std::vector<PerStateIoOveruseThreshold>& thresholds) { |
| mPerCategoryThresholds.clear(); |
| if (thresholds.empty()) { |
| return Error() << "\tNo per-category thresholds provided so clearing it\n"; |
| } |
| std::string errorMsgs; |
| for (const auto& categoryThreshold : thresholds) { |
| if (auto result = containsValidThresholds(categoryThreshold); !result.ok()) { |
| StringAppendF(&errorMsgs, "\tInvalid category specific thresholds: '%s'\n", |
| result.error().message().c_str()); |
| continue; |
| } |
| if (auto category = toApplicationCategoryType(categoryThreshold.name); |
| category == ApplicationCategoryType::OTHERS) { |
| StringAppendF(&errorMsgs, "\tInvalid application category '%s'\n", |
| categoryThreshold.name.c_str()); |
| } else { |
| if (const auto& it = mPerCategoryThresholds.find(category); |
| it != mPerCategoryThresholds.end()) { |
| StringAppendF(&errorMsgs, "\tDuplicate threshold received for category: '%s'\n", |
| categoryThreshold.name.c_str()); |
| } |
| mPerCategoryThresholds[category] = categoryThreshold; |
| } |
| } |
| return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs; |
| } |
| |
| Result<void> IoOveruseConfigs::updateAlertThresholds( |
| const std::vector<IoOveruseAlertThreshold>& thresholds) { |
| mAlertThresholds.clear(); |
| std::string errorMsgs; |
| for (const auto& alertThreshold : thresholds) { |
| if (auto result = containsValidThreshold(alertThreshold); !result.ok()) { |
| StringAppendF(&errorMsgs, "\tInvalid system-wide alert threshold: %s\n", |
| result.error().message().c_str()); |
| continue; |
| } |
| if (const auto& it = mAlertThresholds.find(alertThreshold); it != mAlertThresholds.end()) { |
| StringAppendF(&errorMsgs, |
| "\tDuplicate threshold received for duration %" PRId64 |
| ". Overwriting previous threshold with %" PRId64 |
| " written bytes per second \n", |
| alertThreshold.durationInSeconds, it->writtenBytesPerSecond); |
| } |
| mAlertThresholds.emplace(alertThreshold); |
| } |
| return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs; |
| } |
| |
| Result<void> IoOveruseConfigs::update( |
| const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) { |
| if (const auto result = isValidResourceOveruseConfigs(resourceOveruseConfigs); !result.ok()) { |
| return Error(Status::EX_ILLEGAL_ARGUMENT) << result.error(); |
| } |
| for (const auto& resourceOveruseConfig : resourceOveruseConfigs) { |
| updateFromAidlConfig(resourceOveruseConfig); |
| } |
| return {}; |
| } |
| |
| Result<void> IoOveruseConfigs::updateFromXml(const char* filename) { |
| const auto resourceOveruseConfig = sParseXmlFile(filename); |
| if (!resourceOveruseConfig.ok()) { |
| return Error() << "Failed to parse configuration: " << resourceOveruseConfig.error(); |
| } |
| if (const auto result = isValidResourceOveruseConfig(*resourceOveruseConfig); !result.ok()) { |
| return result; |
| } |
| updateFromAidlConfig(*resourceOveruseConfig); |
| return {}; |
| } |
| |
| void IoOveruseConfigs::updateFromAidlConfig( |
| const ResourceOveruseConfiguration& resourceOveruseConfig) { |
| ComponentSpecificConfig* targetComponentConfig; |
| int32_t updatableConfigsFilter = 0; |
| switch (resourceOveruseConfig.componentType) { |
| case ComponentType::SYSTEM: |
| targetComponentConfig = &mSystemConfig; |
| updatableConfigsFilter = kSystemComponentUpdatableConfigs; |
| break; |
| case ComponentType::VENDOR: |
| targetComponentConfig = &mVendorConfig; |
| updatableConfigsFilter = kVendorComponentUpdatableConfigs; |
| break; |
| case ComponentType::THIRD_PARTY: |
| targetComponentConfig = &mThirdPartyConfig; |
| updatableConfigsFilter = kThirdPartyComponentUpdatableConfigs; |
| break; |
| default: |
| // This case shouldn't execute as it is caught during validation. |
| return; |
| } |
| |
| const std::string componentTypeStr = toString(resourceOveruseConfig.componentType); |
| for (const auto& resourceSpecificConfig : |
| resourceOveruseConfig.resourceSpecificConfigurations) { |
| /* |
| * |resourceSpecificConfig| should contain only ioOveruseConfiguration as it is verified |
| * during validation. |
| */ |
| const auto& ioOveruseConfig = |
| resourceSpecificConfig.get<ResourceSpecificConfiguration::ioOveruseConfiguration>(); |
| if (auto res = update(resourceOveruseConfig, ioOveruseConfig, updatableConfigsFilter, |
| targetComponentConfig); |
| !res.ok()) { |
| ALOGE("Ignorable I/O overuse configuration errors for '%s' component:\n%s", |
| componentTypeStr.c_str(), res.error().message().c_str()); |
| } |
| } |
| return; |
| } |
| |
| Result<void> IoOveruseConfigs::update( |
| const ResourceOveruseConfiguration& resourceOveruseConfiguration, |
| const IoOveruseConfiguration& ioOveruseConfiguration, int32_t updatableConfigsFilter, |
| ComponentSpecificConfig* targetComponentConfig) { |
| if ((updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) { |
| targetComponentConfig->mGeneric = ioOveruseConfiguration.componentLevelThresholds; |
| } |
| |
| std::string nonUpdatableConfigMsgs; |
| if (updatableConfigsFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) { |
| mVendorPackagePrefixes.clear(); |
| for (const auto& prefix : resourceOveruseConfiguration.vendorPackagePrefixes) { |
| if (!prefix.empty()) { |
| mVendorPackagePrefixes.insert(prefix); |
| } |
| } |
| } else if (!resourceOveruseConfiguration.vendorPackagePrefixes.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%svendor packages prefixes", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| if (updatableConfigsFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) { |
| if (mPackagesToAppCategoryMappingUpdateMode == OVERWRITE) { |
| mPackagesToAppCategories.clear(); |
| } |
| if (mPackagesToAppCategoryMappingUpdateMode != NO_UPDATE) { |
| for (const auto& meta : resourceOveruseConfiguration.packageMetadata) { |
| if (!meta.packageName.empty()) { |
| mPackagesToAppCategories[meta.packageName] = meta.appCategoryType; |
| } |
| } |
| } |
| } else if (!resourceOveruseConfiguration.packageMetadata.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%spackage to application category mappings", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| std::string errorMsgs; |
| const auto maybeAppendVendorPackagePrefixes = |
| [&componentType = std::as_const(resourceOveruseConfiguration.componentType), |
| &vendorPackagePrefixes = mVendorPackagePrefixes](const std::string& packageName) { |
| if (componentType != ComponentType::VENDOR) { |
| return; |
| } |
| for (const auto& prefix : vendorPackagePrefixes) { |
| if (StartsWith(packageName, prefix)) { |
| return; |
| } |
| } |
| vendorPackagePrefixes.insert(packageName); |
| }; |
| |
| if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) { |
| if (auto result = targetComponentConfig |
| ->updatePerPackageThresholds(ioOveruseConfiguration |
| .packageSpecificThresholds, |
| maybeAppendVendorPackagePrefixes); |
| !result.ok()) { |
| StringAppendF(&errorMsgs, "\t\t%s", result.error().message().c_str()); |
| } |
| } else if (!ioOveruseConfiguration.packageSpecificThresholds.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%sper-package thresholds", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) { |
| if (auto result = targetComponentConfig |
| ->updateSafeToKillPackages(resourceOveruseConfiguration |
| .safeToKillPackages, |
| maybeAppendVendorPackagePrefixes); |
| !result.ok()) { |
| StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "", |
| result.error().message().c_str()); |
| } |
| } else if (!resourceOveruseConfiguration.safeToKillPackages.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%ssafe-to-kill list", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| if (updatableConfigsFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) { |
| if (auto result = |
| updatePerCategoryThresholds(ioOveruseConfiguration.categorySpecificThresholds); |
| !result.ok()) { |
| StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "", |
| result.error().message().c_str()); |
| } |
| } else if (!ioOveruseConfiguration.categorySpecificThresholds.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%scategory specific thresholds", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| if (updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) { |
| if (auto result = updateAlertThresholds(ioOveruseConfiguration.systemWideThresholds); |
| !result.ok()) { |
| StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "", |
| result.error().message().c_str()); |
| } |
| } else if (!ioOveruseConfiguration.systemWideThresholds.empty()) { |
| StringAppendF(&nonUpdatableConfigMsgs, "%ssystem-wide alert thresholds", |
| !nonUpdatableConfigMsgs.empty() ? ", " : ""); |
| } |
| |
| if (!nonUpdatableConfigMsgs.empty()) { |
| StringAppendF(&errorMsgs, "%s\t\tReceived values for non-updatable configs: [%s]", |
| !errorMsgs.empty() ? "\n" : "", nonUpdatableConfigMsgs.c_str()); |
| } |
| if (!errorMsgs.empty()) { |
| return Error() << errorMsgs.c_str(); |
| } |
| return {}; |
| } |
| |
| void IoOveruseConfigs::get(std::vector<ResourceOveruseConfiguration>* resourceOveruseConfigs) { |
| auto systemConfig = get(mSystemConfig, kSystemComponentUpdatableConfigs); |
| if (systemConfig.has_value()) { |
| systemConfig->componentType = ComponentType::SYSTEM; |
| resourceOveruseConfigs->emplace_back(std::move(*systemConfig)); |
| } |
| |
| auto vendorConfig = get(mVendorConfig, kVendorComponentUpdatableConfigs); |
| if (vendorConfig.has_value()) { |
| vendorConfig->componentType = ComponentType::VENDOR; |
| resourceOveruseConfigs->emplace_back(std::move(*vendorConfig)); |
| } |
| |
| auto thirdPartyConfig = get(mThirdPartyConfig, kThirdPartyComponentUpdatableConfigs); |
| if (thirdPartyConfig.has_value()) { |
| thirdPartyConfig->componentType = ComponentType::THIRD_PARTY; |
| resourceOveruseConfigs->emplace_back(std::move(*thirdPartyConfig)); |
| } |
| } |
| |
| std::optional<ResourceOveruseConfiguration> IoOveruseConfigs::get( |
| const ComponentSpecificConfig& componentSpecificConfig, const int32_t componentFilter) { |
| if (componentSpecificConfig.mGeneric.name == kDefaultThresholdName) { |
| return {}; |
| } |
| ResourceOveruseConfiguration resourceOveruseConfiguration; |
| IoOveruseConfiguration ioOveruseConfiguration; |
| if ((componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) { |
| ioOveruseConfiguration.componentLevelThresholds = componentSpecificConfig.mGeneric; |
| } |
| if (componentFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) { |
| resourceOveruseConfiguration.vendorPackagePrefixes = toStringVector(mVendorPackagePrefixes); |
| } |
| if (componentFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) { |
| for (const auto& [packageName, appCategoryType] : mPackagesToAppCategories) { |
| PackageMetadata meta; |
| meta.packageName = packageName; |
| meta.appCategoryType = appCategoryType; |
| resourceOveruseConfiguration.packageMetadata.push_back(meta); |
| } |
| } |
| if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) { |
| for (const auto& [packageName, threshold] : componentSpecificConfig.mPerPackageThresholds) { |
| ioOveruseConfiguration.packageSpecificThresholds.push_back(threshold); |
| } |
| } |
| if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) { |
| resourceOveruseConfiguration.safeToKillPackages = |
| toStringVector(componentSpecificConfig.mSafeToKillPackages); |
| } |
| if (componentFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) { |
| for (const auto& [category, threshold] : mPerCategoryThresholds) { |
| ioOveruseConfiguration.categorySpecificThresholds.push_back(threshold); |
| } |
| } |
| if (componentFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) { |
| for (const auto& threshold : mAlertThresholds) { |
| ioOveruseConfiguration.systemWideThresholds.push_back(threshold); |
| } |
| } |
| ResourceSpecificConfiguration resourceSpecificConfig; |
| resourceSpecificConfig.set<ResourceSpecificConfiguration::ioOveruseConfiguration>( |
| ioOveruseConfiguration); |
| resourceOveruseConfiguration.resourceSpecificConfigurations.emplace_back( |
| std::move(resourceSpecificConfig)); |
| return resourceOveruseConfiguration; |
| } |
| |
| Result<void> IoOveruseConfigs::writeToDisk() { |
| std::vector<ResourceOveruseConfiguration> resourceOveruseConfigs; |
| get(&resourceOveruseConfigs); |
| for (const auto resourceOveruseConfig : resourceOveruseConfigs) { |
| switch (resourceOveruseConfig.componentType) { |
| case ComponentType::SYSTEM: |
| if (const auto result = |
| sWriteXmlFile(resourceOveruseConfig, kLatestSystemConfigXmlPath); |
| !result.ok()) { |
| return Error() << "Failed to write system resource overuse config to disk"; |
| } |
| continue; |
| case ComponentType::VENDOR: |
| if (const auto result = |
| sWriteXmlFile(resourceOveruseConfig, kLatestVendorConfigXmlPath); |
| !result.ok()) { |
| return Error() << "Failed to write vendor resource overuse config to disk"; |
| } |
| continue; |
| case ComponentType::THIRD_PARTY: |
| if (const auto result = |
| sWriteXmlFile(resourceOveruseConfig, kLatestThirdPartyConfigXmlPath); |
| !result.ok()) { |
| return Error() << "Failed to write third-party resource overuse config to disk"; |
| } |
| continue; |
| case ComponentType::UNKNOWN: |
| continue; |
| } |
| } |
| return {}; |
| } |
| |
| PerStateBytes IoOveruseConfigs::fetchThreshold(const PackageInfo& packageInfo) const { |
| switch (packageInfo.componentType) { |
| case ComponentType::SYSTEM: |
| if (const auto it = mSystemConfig.mPerPackageThresholds.find( |
| packageInfo.packageIdentifier.name); |
| it != mSystemConfig.mPerPackageThresholds.end()) { |
| return it->second.perStateWriteBytes; |
| } |
| if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType); |
| it != mPerCategoryThresholds.end()) { |
| return it->second.perStateWriteBytes; |
| } |
| return mSystemConfig.mGeneric.perStateWriteBytes; |
| case ComponentType::VENDOR: |
| if (const auto it = mVendorConfig.mPerPackageThresholds.find( |
| packageInfo.packageIdentifier.name); |
| it != mVendorConfig.mPerPackageThresholds.end()) { |
| return it->second.perStateWriteBytes; |
| } |
| if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType); |
| it != mPerCategoryThresholds.end()) { |
| return it->second.perStateWriteBytes; |
| } |
| return mVendorConfig.mGeneric.perStateWriteBytes; |
| case ComponentType::THIRD_PARTY: |
| if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType); |
| it != mPerCategoryThresholds.end()) { |
| return it->second.perStateWriteBytes; |
| } |
| return mThirdPartyConfig.mGeneric.perStateWriteBytes; |
| default: |
| ALOGW("Returning default threshold for %s", |
| packageInfo.packageIdentifier.toString().c_str()); |
| return defaultThreshold().perStateWriteBytes; |
| } |
| } |
| |
| bool IoOveruseConfigs::isSafeToKill(const PackageInfo& packageInfo) const { |
| if (packageInfo.uidType == UidType::NATIVE) { |
| // Native packages can't be disabled so don't kill them on I/O overuse. |
| return false; |
| } |
| switch (packageInfo.componentType) { |
| case ComponentType::SYSTEM: |
| return mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) != |
| mSystemConfig.mSafeToKillPackages.end(); |
| case ComponentType::VENDOR: |
| return mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) != |
| mVendorConfig.mSafeToKillPackages.end(); |
| default: |
| return true; |
| } |
| } |
| |
| } // namespace watchdog |
| } // namespace automotive |
| } // namespace android |