Merge changes from topic "read-bootstrap-apex" into main
* changes: Skip bootstrap APEX RC files for the second round Read .rc files from bootstrap apexes
This commit is contained in:
commit
236dbc30fc
6 changed files with 105 additions and 38 deletions
|
@ -674,11 +674,12 @@ provides the `aidl_lazy_test_1` interface.
|
|||
_options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
|
||||
a comma separated string, e.g. barrier=1,noauto\_da\_alloc
|
||||
|
||||
`perform_apex_config`
|
||||
`perform_apex_config [--bootstrap]`
|
||||
> Performs tasks after APEXes are mounted. For example, creates data directories
|
||||
for the mounted APEXes, parses config file(s) from them, and updates linker
|
||||
configurations. Intended to be used only once when apexd notifies the mount
|
||||
event by setting `apexd.status` to ready.
|
||||
Use --bootstrap when invoking in the bootstrap mount namespace.
|
||||
|
||||
`restart [--only-if-running] <service>`
|
||||
> Stops and restarts a running service, does nothing if the service is currently
|
||||
|
|
|
@ -16,13 +16,15 @@
|
|||
|
||||
#include "apex_init_util.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <glob.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/result.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/result.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "action_manager.h"
|
||||
|
@ -34,10 +36,13 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static Result<std::vector<std::string>> CollectApexConfigs(const std::string& apex_name) {
|
||||
static Result<std::vector<std::string>> CollectRcScriptsFromApex(
|
||||
const std::string& apex_name, const std::set<std::string>& skip_apexes) {
|
||||
glob_t glob_result;
|
||||
std::string glob_pattern = apex_name.empty() ?
|
||||
"/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc";
|
||||
// Pattern uses "*rc" instead of ".rc" because APEXes can have versioned RC files
|
||||
// like foo.34rc.
|
||||
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) {
|
||||
|
@ -47,15 +52,28 @@ static Result<std::vector<std::string>> CollectApexConfigs(const std::string& ap
|
|||
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) {
|
||||
|
||||
// Filter out directories
|
||||
if (path.back() == '/') {
|
||||
continue;
|
||||
}
|
||||
// Filter directories
|
||||
if (path.back() == '/') {
|
||||
|
||||
// Get apex name from path.
|
||||
std::vector<std::string> paths = android::base::Split(path, "/");
|
||||
if (paths.size() < 3) {
|
||||
continue;
|
||||
}
|
||||
const std::string& apex_name = paths[2];
|
||||
|
||||
// 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.
|
||||
if (apex_name.find('@') != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out skip_set apexes
|
||||
if (skip_apexes.count(apex_name) > 0) {
|
||||
continue;
|
||||
}
|
||||
configs.push_back(path);
|
||||
|
@ -64,11 +82,41 @@ static Result<std::vector<std::string>> CollectApexConfigs(const std::string& ap
|
|||
return configs;
|
||||
}
|
||||
|
||||
static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
|
||||
static std::set<std::string> GetApexListFrom(const std::string& apex_dir) {
|
||||
std::set<std::string> apex_list;
|
||||
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(apex_dir.c_str()), closedir);
|
||||
if (!dirp) {
|
||||
return apex_list;
|
||||
}
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp.get())) != nullptr) {
|
||||
if (entry->d_type != DT_DIR) continue;
|
||||
|
||||
const char* name = entry->d_name;
|
||||
if (name[0] == '.') continue;
|
||||
if (strchr(name, '@') != nullptr) continue;
|
||||
if (strcmp(name, "sharedlibs") == 0) continue;
|
||||
apex_list.insert(name);
|
||||
}
|
||||
return apex_list;
|
||||
}
|
||||
|
||||
static Result<void> ParseRcScripts(const std::vector<std::string>& files) {
|
||||
if (files.empty()) {
|
||||
return {};
|
||||
}
|
||||
// APEXes can have versioned RC files. These should be filtered based on
|
||||
// SDK version.
|
||||
auto filtered = FilterVersionedConfigs(
|
||||
files, android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
|
||||
if (filtered.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Parser parser =
|
||||
CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
|
||||
std::vector<std::string> errors;
|
||||
for (const auto& c : configs) {
|
||||
for (const auto& c : filtered) {
|
||||
auto result = parser.ParseConfigFile(c);
|
||||
// We should handle other config files even when there's an error.
|
||||
if (!result.ok()) {
|
||||
|
@ -81,16 +129,21 @@ static Result<void> ParseConfigs(const std::vector<std::string>& configs) {
|
|||
return {};
|
||||
}
|
||||
|
||||
Result<void> ParseApexConfigs(const std::string& apex_name) {
|
||||
auto configs = OR_RETURN(CollectApexConfigs(apex_name));
|
||||
Result<void> ParseRcScriptsFromApex(const std::string& apex_name) {
|
||||
auto configs = OR_RETURN(CollectRcScriptsFromApex(apex_name, /*skip_apexes=*/{}));
|
||||
return ParseRcScripts(configs);
|
||||
}
|
||||
|
||||
if (configs.empty()) {
|
||||
return {};
|
||||
Result<void> ParseRcScriptsFromAllApexes(bool bootstrap) {
|
||||
std::set<std::string> skip_apexes;
|
||||
if (!bootstrap) {
|
||||
// In case we already loaded config files from bootstrap APEXes, we need to avoid loading
|
||||
// them again. We can get the list of bootstrap APEXes by scanning /bootstrap-apex and
|
||||
// skip them in CollectRcScriptsFromApex.
|
||||
skip_apexes = GetApexListFrom("/bootstrap-apex");
|
||||
}
|
||||
|
||||
auto filtered_configs = FilterVersionedConfigs(configs,
|
||||
android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
|
||||
return ParseConfigs(filtered_configs);
|
||||
auto configs = OR_RETURN(CollectRcScriptsFromApex(/*apex_name=*/"", skip_apexes));
|
||||
return ParseRcScripts(configs);
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
// Parse all config files for a given apex.
|
||||
// If apex name is empty(""), config files for all apexes will be parsed.
|
||||
Result<void> ParseApexConfigs(const std::string& apex_name);
|
||||
// Parse all RC scripts for a given apex.
|
||||
Result<void> ParseRcScriptsFromApex(const std::string& apex_name);
|
||||
|
||||
// Parse all RC scripts for all apexes under /apex.
|
||||
Result<void> ParseRcScriptsFromAllApexes(bool bootstrap);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
@ -1292,13 +1292,24 @@ static Result<void> create_apex_data_dirs() {
|
|||
}
|
||||
|
||||
static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
|
||||
auto create_dirs = create_apex_data_dirs();
|
||||
if (!create_dirs.ok()) {
|
||||
return create_dirs.error();
|
||||
bool bootstrap = false;
|
||||
if (args.size() == 2) {
|
||||
if (args[1] != "--bootstrap") {
|
||||
return Error() << "Unexpected argument: " << args[1];
|
||||
}
|
||||
bootstrap = true;
|
||||
}
|
||||
auto parse_configs = ParseApexConfigs(/*apex_name=*/"");
|
||||
if (!parse_configs.ok()) {
|
||||
return parse_configs.error();
|
||||
|
||||
if (!bootstrap) {
|
||||
auto create_dirs = create_apex_data_dirs();
|
||||
if (!create_dirs.ok()) {
|
||||
return create_dirs.error();
|
||||
}
|
||||
}
|
||||
|
||||
auto parse_result = ParseRcScriptsFromAllApexes(bootstrap);
|
||||
if (!parse_result.ok()) {
|
||||
return parse_result.error();
|
||||
}
|
||||
|
||||
auto update_linker_config = do_update_linker_config(args);
|
||||
|
@ -1306,8 +1317,10 @@ static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
|
|||
return update_linker_config.error();
|
||||
}
|
||||
|
||||
// Now start delayed services
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
if (!bootstrap) {
|
||||
// Now start delayed services
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1362,7 +1375,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
|
|||
// mount and umount are run in the same context as mount_all for symmetry.
|
||||
{"mount_all", {0, kMax, {false, do_mount_all}}},
|
||||
{"mount", {3, kMax, {false, do_mount}}},
|
||||
{"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},
|
||||
{"perform_apex_config", {0, 1, {false, do_perform_apex_config}}},
|
||||
{"umount", {1, 1, {false, do_umount}}},
|
||||
{"umount_all", {0, 1, {false, do_umount_all}}},
|
||||
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
|
||||
|
|
|
@ -487,7 +487,7 @@ static Result<void> UpdateApexLinkerConfig(const std::string& apex_name) {
|
|||
}
|
||||
|
||||
static Result<void> DoLoadApex(const std::string& apex_name) {
|
||||
if (auto result = ParseApexConfigs(apex_name); !result.ok()) {
|
||||
if (auto result = ParseRcScriptsFromApex(apex_name); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,7 @@ on early-init
|
|||
# become available. Note that this is executed as exec_start to ensure that
|
||||
# the libraries are available to the processes started after this statement.
|
||||
exec_start apexd-bootstrap
|
||||
|
||||
# Generate linker config based on apex mounted in bootstrap namespace
|
||||
update_linker_config
|
||||
perform_apex_config --bootstrap
|
||||
|
||||
# These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run.
|
||||
mkdir /dev/boringssl 0755 root root
|
||||
|
|
Loading…
Reference in a new issue