Merge changes from topic "vapex_stop_service" am: e37c15e9b0
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2162760 Change-Id: I48cec7940f792531726c2f6c8fd88406414260e0 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
898d80083a
14 changed files with 469 additions and 109 deletions
|
|
@ -53,6 +53,7 @@ init_common_sources = [
|
|||
"util.cpp",
|
||||
]
|
||||
init_device_sources = [
|
||||
"apex_init_util.cpp",
|
||||
"block_dev_initializer.cpp",
|
||||
"bootchart.cpp",
|
||||
"builtins.cpp",
|
||||
|
|
@ -217,6 +218,7 @@ cc_library_static {
|
|||
"selinux_policy_version",
|
||||
],
|
||||
srcs: init_common_sources + init_device_sources,
|
||||
export_include_dirs: ["."],
|
||||
generated_sources: [
|
||||
"apex-info-list",
|
||||
],
|
||||
|
|
@ -246,6 +248,10 @@ cc_library_static {
|
|||
],
|
||||
},
|
||||
},
|
||||
visibility: [
|
||||
"//system/apex/apexd",
|
||||
"//frameworks/native/cmds/installd",
|
||||
],
|
||||
}
|
||||
|
||||
phony {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class ActionManager {
|
|||
bool HasMoreCommands() const;
|
||||
void DumpState() const;
|
||||
void ClearQueue();
|
||||
auto size() const { return actions_.size(); }
|
||||
|
||||
private:
|
||||
ActionManager(ActionManager const&) = delete;
|
||||
|
|
|
|||
99
init/apex_init_util.cpp
Normal file
99
init/apex_init_util.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 <map>
|
||||
#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());
|
||||
bool success = true;
|
||||
for (const auto& c : configs) {
|
||||
success &= parser.ParseConfigFile(c);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
return {};
|
||||
} else {
|
||||
return Error() << "Unable to parse apex configs";
|
||||
}
|
||||
}
|
||||
|
||||
Result<void> ParseApexConfigs(const std::string& apex_name) {
|
||||
Result<std::vector<std::string>> configs = CollectApexConfigs(apex_name);
|
||||
if (!configs.ok()) {
|
||||
return configs.error();
|
||||
}
|
||||
|
||||
if (configs.value().empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto filtered_configs = FilterVersionedConfigs(configs.value(),
|
||||
android::base::GetIntProperty("ro.build.version.sdk", INT_MAX));
|
||||
return ParseConfigs(filtered_configs);
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
32
init/apex_init_util.h
Normal file
32
init/apex_init_util.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "result.h"
|
||||
|
||||
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);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
@ -69,6 +69,7 @@
|
|||
#include <system/thread_defs.h>
|
||||
|
||||
#include "action_manager.h"
|
||||
#include "apex_init_util.h"
|
||||
#include "bootchart.h"
|
||||
#include "builtin_arguments.h"
|
||||
#include "fscrypt_init_extensions.h"
|
||||
|
|
@ -1279,48 +1280,6 @@ static Result<void> do_update_linker_config(const BuiltinArguments&) {
|
|||
return GenerateLinkerConfiguration();
|
||||
}
|
||||
|
||||
static Result<void> parse_apex_configs() {
|
||||
glob_t glob_result;
|
||||
static constexpr char glob_pattern[] = "/apex/*/etc/*rc";
|
||||
const int ret = glob(glob_pattern, 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;
|
||||
Parser parser =
|
||||
CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
|
||||
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);
|
||||
|
||||
int active_sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX);
|
||||
|
||||
bool success = true;
|
||||
for (const auto& c : parser.FilterVersionedConfigs(configs, active_sdk)) {
|
||||
success &= parser.ParseConfigFile(c);
|
||||
}
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
if (success) {
|
||||
return {};
|
||||
} else {
|
||||
return Error() << "Could not parse apex configs";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a directory under /data/misc/apexdata/ for each APEX.
|
||||
*/
|
||||
|
|
@ -1351,7 +1310,8 @@ static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
|
|||
if (!create_dirs.ok()) {
|
||||
return create_dirs.error();
|
||||
}
|
||||
auto parse_configs = parse_apex_configs();
|
||||
auto parse_configs = ParseApexConfigs(/*apex_name=*/"");
|
||||
ServiceList::GetInstance().MarkServicesUpdate();
|
||||
if (!parse_configs.ok()) {
|
||||
return parse_configs.error();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,10 @@
|
|||
#include <selinux/android.h>
|
||||
#include <unwindstack/AndroidUnwinder.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "action_manager.h"
|
||||
#include "action_parser.h"
|
||||
#include "builtins.h"
|
||||
#include "apex_init_util.h"
|
||||
#include "epoll.h"
|
||||
#include "first_stage_init.h"
|
||||
#include "first_stage_mount.h"
|
||||
|
|
@ -82,6 +84,7 @@
|
|||
#include "selabel.h"
|
||||
#include "selinux.h"
|
||||
#include "service.h"
|
||||
#include "service_list.h"
|
||||
#include "service_parser.h"
|
||||
#include "sigchld_handler.h"
|
||||
#include "snapuserd_transition.h"
|
||||
|
|
@ -446,11 +449,48 @@ static Result<void> DoControlRestart(Service* service) {
|
|||
return {};
|
||||
}
|
||||
|
||||
int StopServicesFromApex(const std::string& apex_name) {
|
||||
auto services = ServiceList::GetInstance().FindServicesByApexName(apex_name);
|
||||
if (services.empty()) {
|
||||
LOG(INFO) << "No service found for APEX: " << apex_name;
|
||||
return 0;
|
||||
}
|
||||
std::set<std::string> service_names;
|
||||
for (const auto& service : services) {
|
||||
service_names.emplace(service->name());
|
||||
}
|
||||
constexpr std::chrono::milliseconds kServiceStopTimeout = 10s;
|
||||
int still_running = StopServicesAndLogViolations(service_names, kServiceStopTimeout,
|
||||
true /*SIGTERM*/);
|
||||
// Send SIGKILL to ones that didn't terminate cleanly.
|
||||
if (still_running > 0) {
|
||||
still_running = StopServicesAndLogViolations(service_names, 0ms, false /*SIGKILL*/);
|
||||
}
|
||||
return still_running;
|
||||
}
|
||||
|
||||
void RemoveServiceAndActionFromApex(const std::string& apex_name) {
|
||||
// Remove services and actions that match apex name
|
||||
ActionManager::GetInstance().RemoveActionIf([&](const std::unique_ptr<Action>& action) -> bool {
|
||||
if (GetApexNameFromFileName(action->filename()) == apex_name) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
ServiceList::GetInstance().RemoveServiceIf([&](const std::unique_ptr<Service>& s) -> bool {
|
||||
if (GetApexNameFromFileName(s->filename()) == apex_name) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
static Result<void> DoUnloadApex(const std::string& apex_name) {
|
||||
std::string prop_name = "init.apex." + apex_name;
|
||||
// TODO(b/232114573) remove services and actions read from the apex
|
||||
// TODO(b/232799709) kill services from the apex
|
||||
SetProperty(prop_name, "unloaded");
|
||||
if (StopServicesFromApex(apex_name) > 0) {
|
||||
return Error() << "Unable to stop all service from " << apex_name;
|
||||
}
|
||||
RemoveServiceAndActionFromApex(apex_name);
|
||||
SetProperty("init.apex." + apex_name, "unloaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -474,14 +514,15 @@ static Result<void> UpdateApexLinkerConfig(const std::string& apex_name) {
|
|||
}
|
||||
|
||||
static Result<void> DoLoadApex(const std::string& apex_name) {
|
||||
std::string prop_name = "init.apex." + apex_name;
|
||||
// TODO(b/232799709) read .rc files from the apex
|
||||
if(auto result = ParseApexConfigs(apex_name); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
if (auto result = UpdateApexLinkerConfig(apex_name); !result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
SetProperty(prop_name, "loaded");
|
||||
SetProperty("init.apex." + apex_name, "loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,5 +46,9 @@ void DebugRebootLogging();
|
|||
|
||||
int SecondStageMain(int argc, char** argv);
|
||||
|
||||
int StopServicesFromApex(const std::string& apex_name);
|
||||
|
||||
void RemoveServiceAndActionFromApex(const std::string& apex_name);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@
|
|||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "action.h"
|
||||
#include "action_manager.h"
|
||||
|
|
@ -27,6 +30,7 @@
|
|||
#include "builtin_arguments.h"
|
||||
#include "builtins.h"
|
||||
#include "import_parser.h"
|
||||
#include "init.h"
|
||||
#include "keyword_map.h"
|
||||
#include "parser.h"
|
||||
#include "service.h"
|
||||
|
|
@ -37,6 +41,7 @@
|
|||
using android::base::GetIntProperty;
|
||||
using android::base::GetProperty;
|
||||
using android::base::SetProperty;
|
||||
using android::base::StringReplace;
|
||||
using android::base::WaitForProperty;
|
||||
using namespace std::literals;
|
||||
|
||||
|
|
@ -188,6 +193,198 @@ service A something
|
|||
EXPECT_TRUE(service->is_override());
|
||||
}
|
||||
|
||||
static std::string GetSecurityContext() {
|
||||
char* ctx;
|
||||
if (getcon(&ctx) == -1) {
|
||||
ADD_FAILURE() << "Failed to call getcon : " << strerror(errno);
|
||||
}
|
||||
std::string result = std::string(ctx);
|
||||
freecon(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
void TestStartApexServices(const std::vector<std::string>& service_names,
|
||||
const std::string& apex_name) {
|
||||
for (auto const& svc : service_names) {
|
||||
auto service = ServiceList::GetInstance().FindService(svc);
|
||||
ASSERT_NE(nullptr, service);
|
||||
ASSERT_RESULT_OK(service->Start());
|
||||
ASSERT_TRUE(service->IsRunning());
|
||||
LOG(INFO) << "Service " << svc << " is running";
|
||||
if (!apex_name.empty()) {
|
||||
service->set_filename("/apex/" + apex_name + "/init_test.rc");
|
||||
} else {
|
||||
service->set_filename("");
|
||||
}
|
||||
}
|
||||
if (!apex_name.empty()) {
|
||||
auto apex_services = ServiceList::GetInstance().FindServicesByApexName(apex_name);
|
||||
EXPECT_EQ(service_names.size(), apex_services.size());
|
||||
}
|
||||
}
|
||||
|
||||
void TestStopApexServices(const std::vector<std::string>& service_names, bool expect_to_run) {
|
||||
for (auto const& svc : service_names) {
|
||||
auto service = ServiceList::GetInstance().FindService(svc);
|
||||
ASSERT_NE(nullptr, service);
|
||||
EXPECT_EQ(expect_to_run, service->IsRunning());
|
||||
}
|
||||
}
|
||||
|
||||
void TestRemoveApexService(const std::vector<std::string>& service_names, bool exist) {
|
||||
for (auto const& svc : service_names) {
|
||||
auto service = ServiceList::GetInstance().FindService(svc);
|
||||
ASSERT_EQ(exist, service != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void InitApexService(const std::string_view& init_template) {
|
||||
std::string init_script = StringReplace(init_template, "$selabel",
|
||||
GetSecurityContext(), true);
|
||||
|
||||
TestInitText(init_script, BuiltinFunctionMap(), {}, &ActionManager::GetInstance(),
|
||||
&ServiceList::GetInstance());
|
||||
}
|
||||
|
||||
void TestApexServicesInit(const std::vector<std::string>& apex_services,
|
||||
const std::vector<std::string>& other_apex_services,
|
||||
const std::vector<std::string> non_apex_services) {
|
||||
auto num_svc = apex_services.size() + other_apex_services.size() + non_apex_services.size();
|
||||
ASSERT_EQ(num_svc, ServiceList::GetInstance().size());
|
||||
|
||||
TestStartApexServices(apex_services, "com.android.apex.test_service");
|
||||
TestStartApexServices(other_apex_services, "com.android.other_apex.test_service");
|
||||
TestStartApexServices(non_apex_services, /*apex_anme=*/ "");
|
||||
|
||||
StopServicesFromApex("com.android.apex.test_service");
|
||||
TestStopApexServices(apex_services, /*expect_to_run=*/ false);
|
||||
TestStopApexServices(other_apex_services, /*expect_to_run=*/ true);
|
||||
TestStopApexServices(non_apex_services, /*expect_to_run=*/ true);
|
||||
|
||||
RemoveServiceAndActionFromApex("com.android.apex.test_service");
|
||||
ASSERT_EQ(other_apex_services.size() + non_apex_services.size(),
|
||||
ServiceList::GetInstance().size());
|
||||
|
||||
// TODO(b/244232142): Add test to check if actions are removed
|
||||
TestRemoveApexService(apex_services, /*exist*/ false);
|
||||
TestRemoveApexService(other_apex_services, /*exist*/ true);
|
||||
TestRemoveApexService(non_apex_services, /*exist*/ true);
|
||||
|
||||
ServiceList::GetInstance().RemoveServiceIf([&](const std::unique_ptr<Service>& s) -> bool {
|
||||
return true;
|
||||
});
|
||||
|
||||
ActionManager::GetInstance().RemoveActionIf([&](const std::unique_ptr<Action>& s) -> bool {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
TEST(init, StopServiceByApexName) {
|
||||
std::string_view script_template = R"init(
|
||||
service apex_test_service /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(script_template);
|
||||
TestApexServicesInit({"apex_test_service"}, {}, {});
|
||||
}
|
||||
|
||||
TEST(init, StopMultipleServicesByApexName) {
|
||||
std::string_view script_template = R"init(
|
||||
service apex_test_service_multiple_a /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
service apex_test_service_multiple_b /system/bin/id
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(script_template);
|
||||
TestApexServicesInit({"apex_test_service_multiple_a",
|
||||
"apex_test_service_multiple_b"}, {}, {});
|
||||
}
|
||||
|
||||
TEST(init, StopServicesFromMultipleApexes) {
|
||||
std::string_view apex_script_template = R"init(
|
||||
service apex_test_service_multi_apex_a /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
service apex_test_service_multi_apex_b /system/bin/id
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(apex_script_template);
|
||||
|
||||
std::string_view other_apex_script_template = R"init(
|
||||
service apex_test_service_multi_apex_c /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(other_apex_script_template);
|
||||
|
||||
TestApexServicesInit({"apex_test_service_multi_apex_a",
|
||||
"apex_test_service_multi_apex_b"}, {"apex_test_service_multi_apex_c"}, {});
|
||||
}
|
||||
|
||||
TEST(init, StopServicesFromApexAndNonApex) {
|
||||
std::string_view apex_script_template = R"init(
|
||||
service apex_test_service_apex_a /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
service apex_test_service_apex_b /system/bin/id
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(apex_script_template);
|
||||
|
||||
std::string_view non_apex_script_template = R"init(
|
||||
service apex_test_service_non_apex /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(non_apex_script_template);
|
||||
|
||||
TestApexServicesInit({"apex_test_service_apex_a",
|
||||
"apex_test_service_apex_b"}, {}, {"apex_test_service_non_apex"});
|
||||
}
|
||||
|
||||
TEST(init, StopServicesFromApexMixed) {
|
||||
std::string_view script_template = R"init(
|
||||
service apex_test_service_mixed_a /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(script_template);
|
||||
|
||||
std::string_view other_apex_script_template = R"init(
|
||||
service apex_test_service_mixed_b /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(other_apex_script_template);
|
||||
|
||||
std::string_view non_apex_script_template = R"init(
|
||||
service apex_test_service_mixed_c /system/bin/yes
|
||||
user shell
|
||||
group shell
|
||||
seclabel $selabel
|
||||
)init";
|
||||
InitApexService(non_apex_script_template);
|
||||
|
||||
TestApexServicesInit({"apex_test_service_mixed_a"},
|
||||
{"apex_test_service_mixed_b"}, {"apex_test_service_mixed_c"});
|
||||
}
|
||||
|
||||
TEST(init, EventTriggerOrderMultipleFiles) {
|
||||
// 6 total files, which should have their triggers executed in the following order:
|
||||
// 1: start - original script parsed
|
||||
|
|
|
|||
|
|
@ -156,58 +156,6 @@ bool Parser::ParseConfigFile(const std::string& path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> Parser::FilterVersionedConfigs(const std::vector<std::string>& configs,
|
||||
int active_sdk) {
|
||||
std::vector<std::string> filtered_configs;
|
||||
|
||||
std::map<std::string, std::pair<std::string, int>> script_map;
|
||||
for (const auto& c : configs) {
|
||||
int sdk = 0;
|
||||
const std::vector<std::string> parts = android::base::Split(c, ".");
|
||||
std::string base;
|
||||
if (parts.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// parts[size()-1], aka the suffix, should be "rc" or "#rc"
|
||||
// any other pattern gets discarded
|
||||
|
||||
const auto& suffix = parts[parts.size() - 1];
|
||||
if (suffix == "rc") {
|
||||
sdk = 0;
|
||||
} else {
|
||||
char trailer[9] = {0};
|
||||
int r = sscanf(suffix.c_str(), "%d%8s", &sdk, trailer);
|
||||
if (r != 2) {
|
||||
continue;
|
||||
}
|
||||
if (strlen(trailer) > 2 || strcmp(trailer, "rc") != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdk < 0 || sdk > active_sdk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
base = parts[0];
|
||||
for (unsigned int i = 1; i < parts.size() - 1; i++) {
|
||||
base = base + "." + parts[i];
|
||||
}
|
||||
|
||||
// is this preferred over what we already have
|
||||
auto it = script_map.find(base);
|
||||
if (it == script_map.end() || it->second.second < sdk) {
|
||||
script_map[base] = std::make_pair(c, sdk);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& m : script_map) {
|
||||
filtered_configs.push_back(m.second.first);
|
||||
}
|
||||
return filtered_configs;
|
||||
}
|
||||
|
||||
bool Parser::ParseConfigDir(const std::string& path) {
|
||||
LOG(INFO) << "Parsing directory " << path << "...";
|
||||
std::unique_ptr<DIR, decltype(&closedir)> config_dir(opendir(path.c_str()), closedir);
|
||||
|
|
|
|||
|
|
@ -76,12 +76,6 @@ class Parser {
|
|||
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
|
||||
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
|
||||
|
||||
// Compare all files */path.#rc and */path.rc with the same path prefix.
|
||||
// Keep the one with the highest # that doesn't exceed the system's SDK.
|
||||
// (.rc == .0rc for ranking purposes)
|
||||
std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
|
||||
int active_sdk);
|
||||
|
||||
// Host init verifier check file permissions.
|
||||
bool ParseConfigFileInsecure(const std::string& path);
|
||||
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ class Service {
|
|||
}
|
||||
}
|
||||
Subcontext* subcontext() const { return subcontext_; }
|
||||
const std::string& filename() const { return filename_; }
|
||||
void set_filename(const std::string& name) { filename_ = name; }
|
||||
|
||||
private:
|
||||
void NotifyStateChange(const std::string& new_state) const;
|
||||
|
|
|
|||
|
|
@ -16,10 +16,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
|
@ -52,6 +56,17 @@ class ServiceList {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Service*> FindServicesByApexName(const std::string& apex_name) const {
|
||||
CHECK(!apex_name.empty()) << "APEX name cannot be empty";
|
||||
std::vector<Service*> matches;
|
||||
for (const auto& svc : services_) {
|
||||
if (GetApexNameFromFileName(svc->filename()) == apex_name) {
|
||||
matches.emplace_back(svc.get());
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
Service* FindInterface(const std::string& interface_name) {
|
||||
for (const auto& svc : services_) {
|
||||
if (svc->interfaces().count(interface_name) > 0) {
|
||||
|
|
@ -79,6 +94,8 @@ class ServiceList {
|
|||
services_update_finished_ = false;
|
||||
}
|
||||
|
||||
auto size() const { return services_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Service>> services_;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
|
@ -748,5 +749,57 @@ std::string GetApexNameFromFileName(const std::string& path) {
|
|||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
|
||||
int active_sdk) {
|
||||
std::vector<std::string> filtered_configs;
|
||||
|
||||
std::map<std::string, std::pair<std::string, int>> script_map;
|
||||
for (const auto& c : configs) {
|
||||
int sdk = 0;
|
||||
const std::vector<std::string> parts = android::base::Split(c, ".");
|
||||
std::string base;
|
||||
if (parts.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// parts[size()-1], aka the suffix, should be "rc" or "#rc"
|
||||
// any other pattern gets discarded
|
||||
|
||||
const auto& suffix = parts[parts.size() - 1];
|
||||
if (suffix == "rc") {
|
||||
sdk = 0;
|
||||
} else {
|
||||
char trailer[9] = {0};
|
||||
int r = sscanf(suffix.c_str(), "%d%8s", &sdk, trailer);
|
||||
if (r != 2) {
|
||||
continue;
|
||||
}
|
||||
if (strlen(trailer) > 2 || strcmp(trailer, "rc") != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdk < 0 || sdk > active_sdk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
base = parts[0];
|
||||
for (unsigned int i = 1; i < parts.size() - 1; i++) {
|
||||
base = base + "." + parts[i];
|
||||
}
|
||||
|
||||
// is this preferred over what we already have
|
||||
auto it = script_map.find(base);
|
||||
if (it == script_map.end() || it->second.second < sdk) {
|
||||
script_map[base] = std::make_pair(c, sdk);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& m : script_map) {
|
||||
filtered_configs.push_back(m.second.first);
|
||||
}
|
||||
return filtered_configs;
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
|||
|
|
@ -109,5 +109,11 @@ bool IsMicrodroid();
|
|||
bool Has32BitAbi();
|
||||
|
||||
std::string GetApexNameFromFileName(const std::string& path);
|
||||
|
||||
// Compare all files */path.#rc and */path.rc with the same path prefix.
|
||||
// Keep the one with the highest # that doesn't exceed the system's SDK.
|
||||
// (.rc == .0rc for ranking purposes)
|
||||
std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
|
||||
int active_sdk);
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue