android_system_core/init/apex_init_util.cpp
Jooyung Han 6b88d1684c Parser::ParseConfigFile returns Result<void>
ParseApexConfigs() uses Parser::ParseConfigFile() to parse .rc files in
the target apex. ParseConfigFile() returning bool (with logging on
error) doesn't propagate the error message back to the callers
(including apexd or PackageManager).

We'd better to migrate other Parse*() methods of Parser class to return
Result<T>. But this change focuses on plumbing error progagation for
APEX configs.

Bug: 238820991
Test: atest CtsInitTestCases
Change-Id: Ifad97635dbb53a70053ec73a7a5b7e742466daf6
2023-01-11 17:20:16 +09:00

97 lines
3.1 KiB
C++

/*
* Copyright (C) 2022 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 "apex_init_util.h"
#include <glob.h>
#include <vector>
#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include "action_manager.h"
#include "init.h"
#include "parser.h"
#include "service_list.h"
#include "util.h"
namespace android {
namespace init {
static Result<std::vector<std::string>> CollectApexConfigs(const std::string& apex_name) {
glob_t glob_result;
std::string glob_pattern = apex_name.empty() ?
"/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc";
const int ret = glob(glob_pattern.c_str(), GLOB_MARK, nullptr, &glob_result);
if (ret != 0 && ret != GLOB_NOMATCH) {
globfree(&glob_result);
return Error() << "Glob pattern '" << glob_pattern << "' failed";
}
std::vector<std::string> configs;
for (size_t i = 0; i < glob_result.gl_pathc; i++) {
std::string path = glob_result.gl_pathv[i];
// Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
// /apex/<name> paths, so unless we filter them out, we will parse the
// same file twice.
std::vector<std::string> paths = android::base::Split(path, "/");
if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
continue;
}
// Filter directories
if (path.back() == '/') {
continue;
}
configs.push_back(path);
}
globfree(&glob_result);
return configs;
}
static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
Parser parser =
CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
std::vector<std::string> errors;
for (const auto& c : configs) {
auto result = parser.ParseConfigFile(c);
// We should handle other config files even when there's an error.
if (!result.ok()) {
errors.push_back(result.error().message());
}
}
if (!errors.empty()) {
return Error() << "Unable to parse apex configs: " << base::Join(errors, "|");
}
return {};
}
Result<void> ParseApexConfigs(const std::string& apex_name) {
auto configs = OR_RETURN(CollectApexConfigs(apex_name));
if (configs.empty()) {
return {};
}
auto filtered_configs = FilterVersionedConfigs(configs,
android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
return ParseConfigs(filtered_configs);
}
} // namespace init
} // namespace android