• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #define LOG_TAG "carwatchdogd"
18 
19 #include "IoOveruseConfigs.h"
20 
21 #include "OveruseConfigurationXmlHelper.h"
22 #include "PackageInfoResolver.h"
23 
24 #include <android-base/strings.h>
25 #include <log/log.h>
26 
27 #include <inttypes.h>
28 
29 #include <limits>
30 
31 namespace android {
32 namespace automotive {
33 namespace watchdog {
34 
35 using ::aidl::android::automotive::watchdog::PerStateBytes;
36 using ::aidl::android::automotive::watchdog::internal::ApplicationCategoryType;
37 using ::aidl::android::automotive::watchdog::internal::ComponentType;
38 using ::aidl::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
39 using ::aidl::android::automotive::watchdog::internal::IoOveruseConfiguration;
40 using ::aidl::android::automotive::watchdog::internal::PackageInfo;
41 using ::aidl::android::automotive::watchdog::internal::PackageMetadata;
42 using ::aidl::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
43 using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
44 using ::aidl::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
45 using ::aidl::android::automotive::watchdog::internal::UidType;
46 using ::android::base::Error;
47 using ::android::base::Result;
48 using ::android::base::StartsWith;
49 using ::android::base::StringAppendF;
50 using ::android::base::StringPrintf;
51 
52 namespace {
53 
54 // Enum to filter the updatable overuse configs by each component.
55 enum OveruseConfigEnum {
56     COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES = 1 << 0,
57     VENDOR_PACKAGE_PREFIXES = 1 << 1,
58     PACKAGE_APP_CATEGORY_MAPPINGS = 1 << 2,
59     COMPONENT_SPECIFIC_GENERIC_THRESHOLDS = 1 << 3,
60     COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS = 1 << 4,
61     PER_CATEGORY_THRESHOLDS = 1 << 5,
62     SYSTEM_WIDE_ALERT_THRESHOLDS = 1 << 6,
63 };
64 
65 const int32_t kSystemComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
66         PACKAGE_APP_CATEGORY_MAPPINGS | COMPONENT_SPECIFIC_GENERIC_THRESHOLDS |
67         COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | SYSTEM_WIDE_ALERT_THRESHOLDS;
68 const int32_t kVendorComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
69         VENDOR_PACKAGE_PREFIXES | PACKAGE_APP_CATEGORY_MAPPINGS |
70         COMPONENT_SPECIFIC_GENERIC_THRESHOLDS | COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS |
71         PER_CATEGORY_THRESHOLDS;
72 const int32_t kThirdPartyComponentUpdatableConfigs = COMPONENT_SPECIFIC_GENERIC_THRESHOLDS;
73 
toStringVector(const std::unordered_set<std::string> & values)74 const std::vector<std::string> toStringVector(const std::unordered_set<std::string>& values) {
75     std::vector<std::string> output;
76     for (const auto& v : values) {
77         if (!v.empty()) {
78             output.emplace_back(v);
79         }
80     }
81     return output;
82 }
83 
toString(const PerStateIoOveruseThreshold & thresholds)84 std::string toString(const PerStateIoOveruseThreshold& thresholds) {
85     return StringPrintf("name=%s, foregroundBytes=%" PRId64 ", backgroundBytes=%" PRId64
86                         ", garageModeBytes=%" PRId64,
87                         thresholds.name.c_str(), thresholds.perStateWriteBytes.foregroundBytes,
88                         thresholds.perStateWriteBytes.backgroundBytes,
89                         thresholds.perStateWriteBytes.garageModeBytes);
90 }
91 
containsValidThresholds(const PerStateIoOveruseThreshold & thresholds)92 Result<void> containsValidThresholds(const PerStateIoOveruseThreshold& thresholds) {
93     if (thresholds.name.empty()) {
94         return Error() << "Doesn't contain threshold name";
95     }
96 
97     if (thresholds.perStateWriteBytes.foregroundBytes <= 0 ||
98         thresholds.perStateWriteBytes.backgroundBytes <= 0 ||
99         thresholds.perStateWriteBytes.garageModeBytes <= 0) {
100         return Error() << "Some thresholds are less than or equal to zero: "
101                        << toString(thresholds);
102     }
103     return {};
104 }
105 
containsValidThreshold(const IoOveruseAlertThreshold & threshold)106 Result<void> containsValidThreshold(const IoOveruseAlertThreshold& threshold) {
107     if (threshold.durationInSeconds <= 0) {
108         return Error() << "Duration must be greater than zero";
109     }
110     if (threshold.writtenBytesPerSecond <= 0) {
111         return Error() << "Written bytes/second must be greater than zero";
112     }
113     return {};
114 }
115 
toApplicationCategoryType(const std::string & value)116 ApplicationCategoryType toApplicationCategoryType(const std::string& value) {
117     if (value == "MAPS") {
118         return ApplicationCategoryType::MAPS;
119     }
120     if (value == "MEDIA") {
121         return ApplicationCategoryType::MEDIA;
122     }
123     return ApplicationCategoryType::OTHERS;
124 }
125 
isValidIoOveruseConfiguration(const ComponentType componentType,const int32_t updatableConfigsFilter,const IoOveruseConfiguration & ioOveruseConfig)126 Result<void> isValidIoOveruseConfiguration(const ComponentType componentType,
127                                            const int32_t updatableConfigsFilter,
128                                            const IoOveruseConfiguration& ioOveruseConfig) {
129     auto componentTypeStr = toString(componentType);
130     if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS) {
131         if (auto result = containsValidThresholds(ioOveruseConfig.componentLevelThresholds);
132             !result.ok()) {
133             return Error() << "Invalid " << toString(componentType)
134                            << " component level generic thresholds: " << result.error();
135         }
136         if (ioOveruseConfig.componentLevelThresholds.name != componentTypeStr) {
137             return Error() << "Invalid component name "
138                            << ioOveruseConfig.componentLevelThresholds.name
139                            << " in component level generic thresholds for component "
140                            << componentTypeStr;
141         }
142     }
143     const auto containsValidSystemWideThresholds = [&]() -> bool {
144         if (ioOveruseConfig.systemWideThresholds.empty()) {
145             return false;
146         }
147         for (const auto& threshold : ioOveruseConfig.systemWideThresholds) {
148             if (auto result = containsValidThreshold(threshold); !result.ok()) {
149                 return false;
150             }
151         }
152         return true;
153     };
154     if ((updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) &&
155         !containsValidSystemWideThresholds()) {
156         return Error() << "Invalid system-wide alert threshold provided in " << componentTypeStr
157                        << " config";
158     }
159     return {};
160 }
161 
getComponentFilter(const ComponentType componentType)162 Result<int32_t> getComponentFilter(const ComponentType componentType) {
163     switch (componentType) {
164         case ComponentType::SYSTEM:
165             return kSystemComponentUpdatableConfigs;
166         case ComponentType::VENDOR:
167             return kVendorComponentUpdatableConfigs;
168         case ComponentType::THIRD_PARTY:
169             return kThirdPartyComponentUpdatableConfigs;
170         default:
171             return Error() << "Invalid component type: " << static_cast<int32_t>(componentType);
172     }
173 }
174 
isValidResourceOveruseConfig(const ResourceOveruseConfiguration & resourceOveruseConfig)175 Result<void> isValidResourceOveruseConfig(
176         const ResourceOveruseConfiguration& resourceOveruseConfig) {
177     const auto filter = getComponentFilter(resourceOveruseConfig.componentType);
178     if (!filter.ok()) {
179         return Error() << filter.error();
180     }
181     std::unordered_map<std::string, ApplicationCategoryType> seenCategoryMappings;
182     for (const auto& meta : resourceOveruseConfig.packageMetadata) {
183         if (const auto it = seenCategoryMappings.find(meta.packageName);
184             it != seenCategoryMappings.end() && it->second != meta.appCategoryType) {
185             return Error()
186                     << "Must provide exactly one application category mapping for the package "
187                     << meta.packageName << ": Provided mappings " << toString(meta.appCategoryType)
188                     << " and " << toString(it->second);
189         }
190         seenCategoryMappings[meta.packageName] = meta.appCategoryType;
191     }
192     if (resourceOveruseConfig.resourceSpecificConfigurations.size() != 1) {
193         return Error() << "Must provide exactly one I/O overuse configuration. Received "
194                        << resourceOveruseConfig.resourceSpecificConfigurations.size()
195                        << " configurations";
196     }
197     for (const auto& config : resourceOveruseConfig.resourceSpecificConfigurations) {
198         if (config.getTag() != ResourceSpecificConfiguration::ioOveruseConfiguration) {
199             return Error() << "Invalid resource type: " << static_cast<int32_t>(config.getTag());
200         }
201         const auto& ioOveruseConfig =
202                 config.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
203         if (auto result = isValidIoOveruseConfiguration(resourceOveruseConfig.componentType,
204                                                         *filter, ioOveruseConfig);
205             !result.ok()) {
206             return Error() << "Invalid I/O overuse configuration for component "
207                            << toString(resourceOveruseConfig.componentType).c_str() << ": "
208                            << result.error();
209         }
210     }
211     return {};
212 }
213 
isValidResourceOveruseConfigs(const std::vector<ResourceOveruseConfiguration> & resourceOveruseConfigs)214 Result<void> isValidResourceOveruseConfigs(
215         const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) {
216     std::unordered_set<ComponentType> seenComponentTypes;
217     for (const auto& resourceOveruseConfig : resourceOveruseConfigs) {
218         if (seenComponentTypes.count(resourceOveruseConfig.componentType) > 0) {
219             return Error() << "Cannot provide duplicate configs for the same component type "
220                            << toString(resourceOveruseConfig.componentType);
221         }
222         if (const auto result = isValidResourceOveruseConfig(resourceOveruseConfig); !result.ok()) {
223             return result;
224         }
225         seenComponentTypes.insert(resourceOveruseConfig.componentType);
226     }
227     return {};
228 }
229 
isSafeToKillAnyPackage(const std::vector<std::string> & packages,const std::unordered_set<std::string> & safeToKillPackages)230 bool isSafeToKillAnyPackage(const std::vector<std::string>& packages,
231                             const std::unordered_set<std::string>& safeToKillPackages) {
232     for (const auto& packageName : packages) {
233         if (safeToKillPackages.find(packageName) != safeToKillPackages.end()) {
234             return true;
235         }
236     }
237     return false;
238 }
239 
240 }  // namespace
241 
242 IoOveruseConfigs::ParseXmlFileFunction IoOveruseConfigs::sParseXmlFile =
243         &OveruseConfigurationXmlHelper::parseXmlFile;
244 IoOveruseConfigs::WriteXmlFileFunction IoOveruseConfigs::sWriteXmlFile =
245         &OveruseConfigurationXmlHelper::writeXmlFile;
246 
updatePerPackageThresholds(const std::vector<PerStateIoOveruseThreshold> & thresholds,const std::function<void (const std::string &)> & maybeAppendVendorPackagePrefixes)247 Result<void> ComponentSpecificConfig::updatePerPackageThresholds(
248         const std::vector<PerStateIoOveruseThreshold>& thresholds,
249         const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes) {
250     mPerPackageThresholds.clear();
251     if (thresholds.empty()) {
252         return Error() << "\tNo per-package thresholds provided so clearing it\n";
253     }
254     std::string errorMsgs;
255     for (const auto& packageThreshold : thresholds) {
256         if (packageThreshold.name.empty()) {
257             StringAppendF(&errorMsgs, "\tSkipping per-package threshold without package name\n");
258             continue;
259         }
260         maybeAppendVendorPackagePrefixes(packageThreshold.name);
261         if (auto result = containsValidThresholds(packageThreshold); !result.ok()) {
262             StringAppendF(&errorMsgs,
263                           "\tSkipping invalid package specific thresholds for package '%s': %s\n",
264                           packageThreshold.name.c_str(), result.error().message().c_str());
265             continue;
266         }
267         if (const auto& it = mPerPackageThresholds.find(packageThreshold.name);
268             it != mPerPackageThresholds.end()) {
269             StringAppendF(&errorMsgs, "\tDuplicate threshold received for package '%s'\n",
270                           packageThreshold.name.c_str());
271         }
272         mPerPackageThresholds[packageThreshold.name] = packageThreshold;
273     }
274     return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
275 }
276 
updateSafeToKillPackages(const std::vector<std::string> & packages,const std::function<void (const std::string &)> & maybeAppendVendorPackagePrefixes)277 Result<void> ComponentSpecificConfig::updateSafeToKillPackages(
278         const std::vector<std::string>& packages,
279         const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes) {
280     mSafeToKillPackages.clear();
281     if (packages.empty()) {
282         return Error() << "\tNo safe-to-kill packages provided so clearing it\n";
283     }
284     std::string errorMsgs;
285     for (const auto& packageName : packages) {
286         if (packageName.empty()) {
287             StringAppendF(&errorMsgs, "\tSkipping empty safe-to-kill package name");
288             continue;
289         }
290         maybeAppendVendorPackagePrefixes(packageName);
291         mSafeToKillPackages.insert(packageName);
292     }
293     return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
294 }
295 
IoOveruseConfigs()296 IoOveruseConfigs::IoOveruseConfigs() :
297       mSystemConfig({}),
298       mVendorConfig({}),
299       mThirdPartyConfig({}),
300       mPackagesToAppCategories({}),
301       mPackagesToAppCategoryMappingUpdateMode(OVERWRITE),
302       mPerCategoryThresholds({}),
303       mVendorPackagePrefixes({}) {
__anondeb3861f0302(const char* filename, const char* configType) 304     const auto updateFromXmlPerType = [&](const char* filename, const char* configType) -> bool {
305         if (const auto result = this->updateFromXml(filename); !result.ok()) {
306             ALOGE("Failed to parse %s resource overuse configuration from '%s': %s", configType,
307                   filename, result.error().message().c_str());
308             return false;
309         }
310         ALOGI("Updated with %s resource overuse configuration from '%s'", configType, filename);
311         return true;
312     };
313     /*
314      * Package to app category mapping is common between system and vendor component configs. When
315      * the build system and vendor component configs are used, the mapping shouldn't be
316      * overwritten by either of the configs because the build configurations defined by the
317      * vendor or system components may not be aware of mappings included in other component's
318      * config. Ergo, the mapping from both the component configs should be merged together. When a
319      * latest config is used for either of the components, the latest mapping should be given higher
320      * priority.
321      */
322     bool isBuildSystemConfig = false;
323     if (!updateFromXmlPerType(kLatestSystemConfigXmlPath, "latest system")) {
324         isBuildSystemConfig = updateFromXmlPerType(kBuildSystemConfigXmlPath, "build system");
325     }
326     if (!updateFromXmlPerType(kLatestVendorConfigXmlPath, "latest vendor")) {
327         mPackagesToAppCategoryMappingUpdateMode = isBuildSystemConfig ? MERGE : NO_UPDATE;
328         if (!updateFromXmlPerType(kBuildVendorConfigXmlPath, "build vendor") &&
329             mSystemConfig.mGeneric.name != kDefaultThresholdName) {
330             mVendorConfig.mGeneric = mSystemConfig.mGeneric;
331             mVendorConfig.mGeneric.name = toString(ComponentType::VENDOR);
332         }
333         mPackagesToAppCategoryMappingUpdateMode = OVERWRITE;
334     }
335     if (!updateFromXmlPerType(kLatestThirdPartyConfigXmlPath, "latest third-party")) {
336         if (!updateFromXmlPerType(kBuildThirdPartyConfigXmlPath, "build third-party") &&
337             mSystemConfig.mGeneric.name != kDefaultThresholdName) {
338             mThirdPartyConfig.mGeneric = mSystemConfig.mGeneric;
339             mThirdPartyConfig.mGeneric.name = toString(ComponentType::THIRD_PARTY);
340         }
341     }
342 }
343 
operator ()(const IoOveruseAlertThreshold & threshold) const344 size_t IoOveruseConfigs::AlertThresholdHashByDuration::operator()(
345         const IoOveruseAlertThreshold& threshold) const {
346     return std::hash<std::string>{}(std::to_string(threshold.durationInSeconds));
347 }
348 
operator ()(const IoOveruseAlertThreshold & l,const IoOveruseAlertThreshold & r) const349 bool IoOveruseConfigs::AlertThresholdEqualByDuration::operator()(
350         const IoOveruseAlertThreshold& l, const IoOveruseAlertThreshold& r) const {
351     return l.durationInSeconds == r.durationInSeconds;
352 }
353 
updatePerCategoryThresholds(const std::vector<PerStateIoOveruseThreshold> & thresholds)354 Result<void> IoOveruseConfigs::updatePerCategoryThresholds(
355         const std::vector<PerStateIoOveruseThreshold>& thresholds) {
356     mPerCategoryThresholds.clear();
357     if (thresholds.empty()) {
358         return Error() << "\tNo per-category thresholds provided so clearing it\n";
359     }
360     std::string errorMsgs;
361     for (const auto& categoryThreshold : thresholds) {
362         if (auto result = containsValidThresholds(categoryThreshold); !result.ok()) {
363             StringAppendF(&errorMsgs, "\tInvalid category specific thresholds: '%s'\n",
364                           result.error().message().c_str());
365             continue;
366         }
367         if (auto category = toApplicationCategoryType(categoryThreshold.name);
368             category == ApplicationCategoryType::OTHERS) {
369             StringAppendF(&errorMsgs, "\tInvalid application category '%s'\n",
370                           categoryThreshold.name.c_str());
371         } else {
372             if (const auto& it = mPerCategoryThresholds.find(category);
373                 it != mPerCategoryThresholds.end()) {
374                 StringAppendF(&errorMsgs, "\tDuplicate threshold received for category: '%s'\n",
375                               categoryThreshold.name.c_str());
376             }
377             mPerCategoryThresholds[category] = categoryThreshold;
378         }
379     }
380     return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
381 }
382 
updateAlertThresholds(const std::vector<IoOveruseAlertThreshold> & thresholds)383 Result<void> IoOveruseConfigs::updateAlertThresholds(
384         const std::vector<IoOveruseAlertThreshold>& thresholds) {
385     mAlertThresholds.clear();
386     std::string errorMsgs;
387     for (const auto& alertThreshold : thresholds) {
388         if (auto result = containsValidThreshold(alertThreshold); !result.ok()) {
389             StringAppendF(&errorMsgs, "\tInvalid system-wide alert threshold: %s\n",
390                           result.error().message().c_str());
391             continue;
392         }
393         if (const auto& it = mAlertThresholds.find(alertThreshold); it != mAlertThresholds.end()) {
394             StringAppendF(&errorMsgs,
395                           "\tDuplicate threshold received for duration %" PRId64
396                           ". Overwriting previous threshold with %" PRId64
397                           " written bytes per second \n",
398                           alertThreshold.durationInSeconds, it->writtenBytesPerSecond);
399         }
400         mAlertThresholds.emplace(alertThreshold);
401     }
402     return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
403 }
404 
update(const std::vector<ResourceOveruseConfiguration> & resourceOveruseConfigs)405 Result<void> IoOveruseConfigs::update(
406         const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) {
407     if (const auto result = isValidResourceOveruseConfigs(resourceOveruseConfigs); !result.ok()) {
408         return Error(EX_ILLEGAL_ARGUMENT) << result.error();
409     }
410     for (const auto& resourceOveruseConfig : resourceOveruseConfigs) {
411         updateFromAidlConfig(resourceOveruseConfig);
412     }
413     return {};
414 }
415 
updateFromXml(const char * filename)416 Result<void> IoOveruseConfigs::updateFromXml(const char* filename) {
417     const auto resourceOveruseConfig = sParseXmlFile(filename);
418     if (!resourceOveruseConfig.ok()) {
419         return Error() << "Failed to parse configuration: " << resourceOveruseConfig.error();
420     }
421     if (const auto result = isValidResourceOveruseConfig(*resourceOveruseConfig); !result.ok()) {
422         return result;
423     }
424     updateFromAidlConfig(*resourceOveruseConfig);
425     return {};
426 }
427 
updateFromAidlConfig(const ResourceOveruseConfiguration & resourceOveruseConfig)428 void IoOveruseConfigs::updateFromAidlConfig(
429         const ResourceOveruseConfiguration& resourceOveruseConfig) {
430     ComponentSpecificConfig* targetComponentConfig;
431     int32_t updatableConfigsFilter = 0;
432     switch (resourceOveruseConfig.componentType) {
433         case ComponentType::SYSTEM:
434             targetComponentConfig = &mSystemConfig;
435             updatableConfigsFilter = kSystemComponentUpdatableConfigs;
436             break;
437         case ComponentType::VENDOR:
438             targetComponentConfig = &mVendorConfig;
439             updatableConfigsFilter = kVendorComponentUpdatableConfigs;
440             break;
441         case ComponentType::THIRD_PARTY:
442             targetComponentConfig = &mThirdPartyConfig;
443             updatableConfigsFilter = kThirdPartyComponentUpdatableConfigs;
444             break;
445         default:
446             // This case shouldn't execute as it is caught during validation.
447             return;
448     }
449 
450     const std::string componentTypeStr = toString(resourceOveruseConfig.componentType);
451     for (const auto& resourceSpecificConfig :
452          resourceOveruseConfig.resourceSpecificConfigurations) {
453         /*
454          * |resourceSpecificConfig| should contain only ioOveruseConfiguration as it is verified
455          * during validation.
456          */
457         const auto& ioOveruseConfig =
458                 resourceSpecificConfig.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
459         if (auto res = update(resourceOveruseConfig, ioOveruseConfig, updatableConfigsFilter,
460                               targetComponentConfig);
461             !res.ok()) {
462             ALOGE("Ignorable I/O overuse configuration errors for '%s' component:\n%s",
463                   componentTypeStr.c_str(), res.error().message().c_str());
464         }
465     }
466     return;
467 }
468 
update(const ResourceOveruseConfiguration & resourceOveruseConfiguration,const IoOveruseConfiguration & ioOveruseConfiguration,int32_t updatableConfigsFilter,ComponentSpecificConfig * targetComponentConfig)469 Result<void> IoOveruseConfigs::update(
470         const ResourceOveruseConfiguration& resourceOveruseConfiguration,
471         const IoOveruseConfiguration& ioOveruseConfiguration, int32_t updatableConfigsFilter,
472         ComponentSpecificConfig* targetComponentConfig) {
473     if ((updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) {
474         targetComponentConfig->mGeneric = ioOveruseConfiguration.componentLevelThresholds;
475     }
476 
477     std::string nonUpdatableConfigMsgs;
478     if (updatableConfigsFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) {
479         mVendorPackagePrefixes.clear();
480         for (const auto& prefix : resourceOveruseConfiguration.vendorPackagePrefixes) {
481             if (!prefix.empty()) {
482                 mVendorPackagePrefixes.insert(prefix);
483             }
484         }
485     } else if (!resourceOveruseConfiguration.vendorPackagePrefixes.empty()) {
486         StringAppendF(&nonUpdatableConfigMsgs, "%svendor packages prefixes",
487                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
488     }
489 
490     if (updatableConfigsFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) {
491         if (mPackagesToAppCategoryMappingUpdateMode == OVERWRITE) {
492             mPackagesToAppCategories.clear();
493         }
494         if (mPackagesToAppCategoryMappingUpdateMode != NO_UPDATE) {
495             for (const auto& meta : resourceOveruseConfiguration.packageMetadata) {
496                 if (!meta.packageName.empty()) {
497                     mPackagesToAppCategories[meta.packageName] = meta.appCategoryType;
498                 }
499             }
500         }
501     } else if (!resourceOveruseConfiguration.packageMetadata.empty()) {
502         StringAppendF(&nonUpdatableConfigMsgs, "%spackage to application category mappings",
503                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
504     }
505 
506     std::string errorMsgs;
507     const auto maybeAppendVendorPackagePrefixes =
508             [&componentType = std::as_const(resourceOveruseConfiguration.componentType),
509              &vendorPackagePrefixes = mVendorPackagePrefixes](const std::string& packageName) {
510                 if (componentType != ComponentType::VENDOR) {
511                     return;
512                 }
513                 for (const auto& prefix : vendorPackagePrefixes) {
514                     if (StartsWith(packageName, prefix)) {
515                         return;
516                     }
517                 }
518                 vendorPackagePrefixes.insert(packageName);
519             };
520 
521     if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) {
522         if (auto result = targetComponentConfig
523                                   ->updatePerPackageThresholds(ioOveruseConfiguration
524                                                                        .packageSpecificThresholds,
525                                                                maybeAppendVendorPackagePrefixes);
526             !result.ok()) {
527             StringAppendF(&errorMsgs, "\t\t%s", result.error().message().c_str());
528         }
529     } else if (!ioOveruseConfiguration.packageSpecificThresholds.empty()) {
530         StringAppendF(&nonUpdatableConfigMsgs, "%sper-package thresholds",
531                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
532     }
533 
534     if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) {
535         if (auto result = targetComponentConfig
536                                   ->updateSafeToKillPackages(resourceOveruseConfiguration
537                                                                      .safeToKillPackages,
538                                                              maybeAppendVendorPackagePrefixes);
539             !result.ok()) {
540             StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "",
541                           result.error().message().c_str());
542         }
543     } else if (!resourceOveruseConfiguration.safeToKillPackages.empty()) {
544         StringAppendF(&nonUpdatableConfigMsgs, "%ssafe-to-kill list",
545                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
546     }
547 
548     if (updatableConfigsFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) {
549         if (auto result =
550                     updatePerCategoryThresholds(ioOveruseConfiguration.categorySpecificThresholds);
551             !result.ok()) {
552             StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "",
553                           result.error().message().c_str());
554         }
555     } else if (!ioOveruseConfiguration.categorySpecificThresholds.empty()) {
556         StringAppendF(&nonUpdatableConfigMsgs, "%scategory specific thresholds",
557                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
558     }
559 
560     if (updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) {
561         if (auto result = updateAlertThresholds(ioOveruseConfiguration.systemWideThresholds);
562             !result.ok()) {
563             StringAppendF(&errorMsgs, "%s\t\t%s", !errorMsgs.empty() ? "\n" : "",
564                           result.error().message().c_str());
565         }
566     } else if (!ioOveruseConfiguration.systemWideThresholds.empty()) {
567         StringAppendF(&nonUpdatableConfigMsgs, "%ssystem-wide alert thresholds",
568                       !nonUpdatableConfigMsgs.empty() ? ", " : "");
569     }
570 
571     if (!nonUpdatableConfigMsgs.empty()) {
572         StringAppendF(&errorMsgs, "%s\t\tReceived values for non-updatable configs: [%s]",
573                       !errorMsgs.empty() ? "\n" : "", nonUpdatableConfigMsgs.c_str());
574     }
575     if (!errorMsgs.empty()) {
576         return Error() << errorMsgs.c_str();
577     }
578     return {};
579 }
580 
get(std::vector<ResourceOveruseConfiguration> * resourceOveruseConfigs) const581 void IoOveruseConfigs::get(
582         std::vector<ResourceOveruseConfiguration>* resourceOveruseConfigs) const {
583     auto systemConfig = get(mSystemConfig, kSystemComponentUpdatableConfigs);
584     if (systemConfig.has_value()) {
585         systemConfig->componentType = ComponentType::SYSTEM;
586         resourceOveruseConfigs->emplace_back(std::move(*systemConfig));
587     }
588 
589     auto vendorConfig = get(mVendorConfig, kVendorComponentUpdatableConfigs);
590     if (vendorConfig.has_value()) {
591         vendorConfig->componentType = ComponentType::VENDOR;
592         resourceOveruseConfigs->emplace_back(std::move(*vendorConfig));
593     }
594 
595     auto thirdPartyConfig = get(mThirdPartyConfig, kThirdPartyComponentUpdatableConfigs);
596     if (thirdPartyConfig.has_value()) {
597         thirdPartyConfig->componentType = ComponentType::THIRD_PARTY;
598         resourceOveruseConfigs->emplace_back(std::move(*thirdPartyConfig));
599     }
600 }
601 
get(const ComponentSpecificConfig & componentSpecificConfig,const int32_t componentFilter) const602 std::optional<ResourceOveruseConfiguration> IoOveruseConfigs::get(
603         const ComponentSpecificConfig& componentSpecificConfig,
604         const int32_t componentFilter) const {
605     if (componentSpecificConfig.mGeneric.name == kDefaultThresholdName) {
606         return {};
607     }
608     ResourceOveruseConfiguration resourceOveruseConfiguration;
609     IoOveruseConfiguration ioOveruseConfiguration;
610     if ((componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) {
611         ioOveruseConfiguration.componentLevelThresholds = componentSpecificConfig.mGeneric;
612     }
613     if (componentFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) {
614         resourceOveruseConfiguration.vendorPackagePrefixes = toStringVector(mVendorPackagePrefixes);
615     }
616     if (componentFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) {
617         for (const auto& [packageName, appCategoryType] : mPackagesToAppCategories) {
618             PackageMetadata meta;
619             meta.packageName = packageName;
620             meta.appCategoryType = appCategoryType;
621             resourceOveruseConfiguration.packageMetadata.push_back(meta);
622         }
623     }
624     if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) {
625         for (const auto& [packageName, threshold] : componentSpecificConfig.mPerPackageThresholds) {
626             ioOveruseConfiguration.packageSpecificThresholds.push_back(threshold);
627         }
628     }
629     if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) {
630         resourceOveruseConfiguration.safeToKillPackages =
631                 toStringVector(componentSpecificConfig.mSafeToKillPackages);
632     }
633     if (componentFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) {
634         for (const auto& [category, threshold] : mPerCategoryThresholds) {
635             ioOveruseConfiguration.categorySpecificThresholds.push_back(threshold);
636         }
637     }
638     if (componentFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) {
639         for (const auto& threshold : mAlertThresholds) {
640             ioOveruseConfiguration.systemWideThresholds.push_back(threshold);
641         }
642     }
643     ResourceSpecificConfiguration resourceSpecificConfig;
644     resourceSpecificConfig.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(
645             ioOveruseConfiguration);
646     resourceOveruseConfiguration.resourceSpecificConfigurations.emplace_back(
647             std::move(resourceSpecificConfig));
648     return resourceOveruseConfiguration;
649 }
650 
writeToDisk()651 Result<void> IoOveruseConfigs::writeToDisk() {
652     std::vector<ResourceOveruseConfiguration> resourceOveruseConfigs;
653     get(&resourceOveruseConfigs);
654     for (const auto resourceOveruseConfig : resourceOveruseConfigs) {
655         switch (resourceOveruseConfig.componentType) {
656             case ComponentType::SYSTEM:
657                 if (const auto result =
658                             sWriteXmlFile(resourceOveruseConfig, kLatestSystemConfigXmlPath);
659                     !result.ok()) {
660                     return Error() << "Failed to write system resource overuse config to disk";
661                 }
662                 continue;
663             case ComponentType::VENDOR:
664                 if (const auto result =
665                             sWriteXmlFile(resourceOveruseConfig, kLatestVendorConfigXmlPath);
666                     !result.ok()) {
667                     return Error() << "Failed to write vendor resource overuse config to disk";
668                 }
669                 continue;
670             case ComponentType::THIRD_PARTY:
671                 if (const auto result =
672                             sWriteXmlFile(resourceOveruseConfig, kLatestThirdPartyConfigXmlPath);
673                     !result.ok()) {
674                     return Error() << "Failed to write third-party resource overuse config to disk";
675                 }
676                 continue;
677             case ComponentType::UNKNOWN:
678                 continue;
679         }
680     }
681     return {};
682 }
683 
fetchThreshold(const PackageInfo & packageInfo) const684 PerStateBytes IoOveruseConfigs::fetchThreshold(const PackageInfo& packageInfo) const {
685     switch (packageInfo.componentType) {
686         case ComponentType::SYSTEM:
687             if (const auto it = mSystemConfig.mPerPackageThresholds.find(
688                         packageInfo.packageIdentifier.name);
689                 it != mSystemConfig.mPerPackageThresholds.end()) {
690                 return it->second.perStateWriteBytes;
691             }
692             if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType);
693                 it != mPerCategoryThresholds.end()) {
694                 return it->second.perStateWriteBytes;
695             }
696             return mSystemConfig.mGeneric.perStateWriteBytes;
697         case ComponentType::VENDOR:
698             if (const auto it = mVendorConfig.mPerPackageThresholds.find(
699                         packageInfo.packageIdentifier.name);
700                 it != mVendorConfig.mPerPackageThresholds.end()) {
701                 return it->second.perStateWriteBytes;
702             }
703             if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType);
704                 it != mPerCategoryThresholds.end()) {
705                 return it->second.perStateWriteBytes;
706             }
707             return mVendorConfig.mGeneric.perStateWriteBytes;
708         case ComponentType::THIRD_PARTY:
709             if (const auto it = mPerCategoryThresholds.find(packageInfo.appCategoryType);
710                 it != mPerCategoryThresholds.end()) {
711                 return it->second.perStateWriteBytes;
712             }
713             return mThirdPartyConfig.mGeneric.perStateWriteBytes;
714         default:
715             ALOGW("Returning default threshold for %s",
716                   packageInfo.packageIdentifier.toString().c_str());
717             return defaultThreshold().perStateWriteBytes;
718     }
719 }
720 
isSafeToKill(const PackageInfo & packageInfo) const721 bool IoOveruseConfigs::isSafeToKill(const PackageInfo& packageInfo) const {
722     if (packageInfo.uidType == UidType::NATIVE) {
723         // Native packages can't be disabled so don't kill them on I/O overuse.
724         return false;
725     }
726     switch (packageInfo.componentType) {
727         case ComponentType::SYSTEM:
728             if (mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
729                 mSystemConfig.mSafeToKillPackages.end()) {
730                 return true;
731             }
732             return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
733                                           mSystemConfig.mSafeToKillPackages);
734         case ComponentType::VENDOR:
735             if (mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
736                 mVendorConfig.mSafeToKillPackages.end()) {
737                 return true;
738             }
739             /*
740              * Packages under the vendor shared UID may contain system packages because when
741              * CarWatchdogService derives the shared component type it attributes system packages
742              * as vendor packages when there is at least one vendor package.
743              */
744             return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
745                                           mSystemConfig.mSafeToKillPackages) ||
746                     isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
747                                            mVendorConfig.mSafeToKillPackages);
748         default:
749             return true;
750     }
751 }
752 
753 }  // namespace watchdog
754 }  // namespace automotive
755 }  // namespace android
756