diff options
-rw-r--r-- | init/Android.bp | 1 | ||||
-rw-r--r-- | init/modalias_handler.cpp | 176 | ||||
-rw-r--r-- | init/modalias_handler.h | 47 | ||||
-rw-r--r-- | init/uevent.h | 1 | ||||
-rw-r--r-- | init/uevent_listener.cpp | 4 | ||||
-rw-r--r-- | init/ueventd.cpp | 13 |
6 files changed, 239 insertions, 3 deletions
diff --git a/init/Android.bp b/init/Android.bp index aaef7e933..465193660 100644 --- a/init/Android.bp +++ b/init/Android.bp | |||
@@ -69,6 +69,7 @@ cc_library_static { | |||
69 | "import_parser.cpp", | 69 | "import_parser.cpp", |
70 | "init_parser.cpp", | 70 | "init_parser.cpp", |
71 | "log.cpp", | 71 | "log.cpp", |
72 | "modalias_handler.cpp", | ||
72 | "parser.cpp", | 73 | "parser.cpp", |
73 | "service.cpp", | 74 | "service.cpp", |
74 | "uevent_listener.cpp", | 75 | "uevent_listener.cpp", |
diff --git a/init/modalias_handler.cpp b/init/modalias_handler.cpp new file mode 100644 index 000000000..7c34ce287 --- /dev/null +++ b/init/modalias_handler.cpp | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 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 | #include "modalias_handler.h" | ||
18 | |||
19 | #include <fnmatch.h> | ||
20 | #include <sys/syscall.h> | ||
21 | #include <fcntl.h> | ||
22 | |||
23 | #include <algorithm> | ||
24 | #include <functional> | ||
25 | #include <string> | ||
26 | #include <vector> | ||
27 | |||
28 | #include <android-base/chrono_utils.h> | ||
29 | #include <android-base/logging.h> | ||
30 | #include <android-base/unique_fd.h> | ||
31 | |||
32 | #include "init_parser.h" | ||
33 | #include "util.h" | ||
34 | |||
35 | namespace android { | ||
36 | namespace init { | ||
37 | |||
38 | bool ModaliasHandler::ParseDepCallback(std::vector<std::string>&& args, std::string* err) { | ||
39 | std::vector<std::string> deps; | ||
40 | |||
41 | // Set first item as our modules path | ||
42 | std::string::size_type pos = args[0].find(':'); | ||
43 | if (pos != std::string::npos) { | ||
44 | deps.emplace_back(args[0].substr(0, pos)); | ||
45 | } else { | ||
46 | *err = "dependency lines must start with name followed by ':'"; | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | // Remaining items are dependencies of our module | ||
51 | for (auto arg = args.begin() + 1; arg != args.end(); ++arg) { | ||
52 | deps.push_back(*arg); | ||
53 | } | ||
54 | |||
55 | // Key is striped module name to match names in alias file | ||
56 | std::size_t start = args[0].find_last_of("/"); | ||
57 | std::size_t end = args[0].find(".ko:"); | ||
58 | if ((end - start) <= 1) { | ||
59 | *err = "malformed dependency line"; | ||
60 | return false; | ||
61 | } | ||
62 | auto mod_name = args[0].substr(start + 1, (end - start) - 1); | ||
63 | // module names can have '-', but their file names will have '_' | ||
64 | std::replace(mod_name.begin(), mod_name.end(), '-', '_'); | ||
65 | this->module_deps_[mod_name] = deps; | ||
66 | |||
67 | return true; | ||
68 | } | ||
69 | |||
70 | bool ModaliasHandler::ParseAliasCallback(std::vector<std::string>&& args, std::string* err) { | ||
71 | auto it = args.begin(); | ||
72 | const std::string& type = *it++; | ||
73 | |||
74 | if (type != "alias") { | ||
75 | *err = "we only handle alias lines"; | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | if (args.size() != 3) { | ||
80 | *err = "alias lines must have 3 entries"; | ||
81 | return false; | ||
82 | } | ||
83 | |||
84 | std::string& alias = *it++; | ||
85 | std::string& module_name = *it++; | ||
86 | this->module_aliases_.emplace_back(alias, module_name); | ||
87 | |||
88 | return true; | ||
89 | } | ||
90 | |||
91 | ModaliasHandler::ModaliasHandler() { | ||
92 | using namespace std::placeholders; | ||
93 | |||
94 | static const std::string base_paths[] = { | ||
95 | "/vendor/lib/modules/", | ||
96 | "/lib/modules/", | ||
97 | "/odm/lib/modules/", | ||
98 | }; | ||
99 | |||
100 | Parser alias_parser; | ||
101 | auto alias_callback = std::bind(&ModaliasHandler::ParseAliasCallback, this, _1, _2); | ||
102 | alias_parser.AddSingleLineParser("alias", alias_callback); | ||
103 | for (const auto& base_path : base_paths) alias_parser.ParseConfig(base_path + "modules.alias"); | ||
104 | |||
105 | Parser dep_parser; | ||
106 | auto dep_callback = std::bind(&ModaliasHandler::ParseDepCallback, this, _1, _2); | ||
107 | dep_parser.AddSingleLineParser("", dep_callback); | ||
108 | for (const auto& base_path : base_paths) dep_parser.ParseConfig(base_path + "modules.dep"); | ||
109 | } | ||
110 | |||
111 | bool ModaliasHandler::Insmod(const std::string& path_name, const std::string& args) { | ||
112 | base::unique_fd fd( | ||
113 | TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC))); | ||
114 | if (fd == -1) { | ||
115 | PLOG(ERROR) << "Could not open module '" << path_name << "'"; | ||
116 | return false; | ||
117 | } | ||
118 | |||
119 | int ret = syscall(__NR_finit_module, fd.get(), args.c_str(), 0); | ||
120 | if (ret != 0) { | ||
121 | if (errno == EEXIST) { | ||
122 | // Module already loaded | ||
123 | return true; | ||
124 | } | ||
125 | PLOG(ERROR) << "Failed to insmod '" << path_name << "' with args '" << args << "'"; | ||
126 | return false; | ||
127 | } | ||
128 | |||
129 | LOG(INFO) << "Loaded kernel module " << path_name; | ||
130 | return true; | ||
131 | } | ||
132 | |||
133 | bool ModaliasHandler::InsmodWithDeps(const std::string& module_name, | ||
134 | const std::string& args) { | ||
135 | if (module_name.empty()) { | ||
136 | LOG(ERROR) << "Need valid module name"; | ||
137 | return false; | ||
138 | } | ||
139 | |||
140 | auto it = module_deps_.find(module_name); | ||
141 | if (it == module_deps_.end()) { | ||
142 | LOG(ERROR) << "Module '" << module_name << "' not in dependency file"; | ||
143 | return false; | ||
144 | } | ||
145 | auto& dependencies = it->second; | ||
146 | |||
147 | // load module dependencies in reverse order | ||
148 | for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) { | ||
149 | if (auto result = Insmod(*dep, ""); !result) return result; | ||
150 | } | ||
151 | |||
152 | // load target module itself with args | ||
153 | return Insmod(dependencies[0], args); | ||
154 | } | ||
155 | |||
156 | void ModaliasHandler::HandleModaliasEvent(const Uevent& uevent) { | ||
157 | if (uevent.modalias.empty()) return; | ||
158 | |||
159 | for (const auto& [alias, module] : module_aliases_) { | ||
160 | if (fnmatch(alias.c_str(), uevent.modalias.c_str(), 0) != 0) continue; // Keep looking | ||
161 | |||
162 | LOG(DEBUG) << "Loading kernel module '" << module << "' for alias '" << uevent.modalias | ||
163 | << "'"; | ||
164 | |||
165 | if (auto result = InsmodWithDeps(module, ""); !result) { | ||
166 | // try another one since there may be another match | ||
167 | continue; | ||
168 | } | ||
169 | |||
170 | // loading was successful | ||
171 | return; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | } // namespace init | ||
176 | } // namespace android | ||
diff --git a/init/modalias_handler.h b/init/modalias_handler.h new file mode 100644 index 000000000..fb8bbc5ed --- /dev/null +++ b/init/modalias_handler.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 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 | #pragma once | ||
18 | |||
19 | #include "uevent.h" | ||
20 | |||
21 | #include <string> | ||
22 | #include <unordered_map> | ||
23 | #include <vector> | ||
24 | |||
25 | namespace android { | ||
26 | namespace init { | ||
27 | |||
28 | class ModaliasHandler { | ||
29 | public: | ||
30 | ModaliasHandler(); | ||
31 | ~ModaliasHandler(){}; | ||
32 | |||
33 | void HandleModaliasEvent(const Uevent& uevent); | ||
34 | |||
35 | private: | ||
36 | bool InsmodWithDeps(const std::string& module_name, const std::string& args); | ||
37 | bool Insmod(const std::string& path_name, const std::string& args); | ||
38 | |||
39 | bool ParseDepCallback(std::vector<std::string>&& args, std::string* err); | ||
40 | bool ParseAliasCallback(std::vector<std::string>&& args, std::string* err); | ||
41 | |||
42 | std::vector<std::pair<std::string, std::string>> module_aliases_; | ||
43 | std::unordered_map<std::string, std::vector<std::string>> module_deps_; | ||
44 | }; | ||
45 | |||
46 | } // namespace init | ||
47 | } // namespace android | ||
diff --git a/init/uevent.h b/init/uevent.h index c4fd9454c..dc35fd968 100644 --- a/init/uevent.h +++ b/init/uevent.h | |||
@@ -29,6 +29,7 @@ struct Uevent { | |||
29 | std::string firmware; | 29 | std::string firmware; |
30 | std::string partition_name; | 30 | std::string partition_name; |
31 | std::string device_name; | 31 | std::string device_name; |
32 | std::string modalias; | ||
32 | int partition_num; | 33 | int partition_num; |
33 | int major; | 34 | int major; |
34 | int minor; | 35 | int minor; |
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index ac1d7c7ed..2022a0dac 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp | |||
@@ -39,6 +39,7 @@ static void ParseEvent(const char* msg, Uevent* uevent) { | |||
39 | uevent->firmware.clear(); | 39 | uevent->firmware.clear(); |
40 | uevent->partition_name.clear(); | 40 | uevent->partition_name.clear(); |
41 | uevent->device_name.clear(); | 41 | uevent->device_name.clear(); |
42 | uevent->modalias.clear(); | ||
42 | // currently ignoring SEQNUM | 43 | // currently ignoring SEQNUM |
43 | while (*msg) { | 44 | while (*msg) { |
44 | if (!strncmp(msg, "ACTION=", 7)) { | 45 | if (!strncmp(msg, "ACTION=", 7)) { |
@@ -68,6 +69,9 @@ static void ParseEvent(const char* msg, Uevent* uevent) { | |||
68 | } else if (!strncmp(msg, "DEVNAME=", 8)) { | 69 | } else if (!strncmp(msg, "DEVNAME=", 8)) { |
69 | msg += 8; | 70 | msg += 8; |
70 | uevent->device_name = msg; | 71 | uevent->device_name = msg; |
72 | } else if (!strncmp(msg, "MODALIAS=", 9)) { | ||
73 | msg += 9; | ||
74 | uevent->modalias = msg; | ||
71 | } | 75 | } |
72 | 76 | ||
73 | // advance to after the next \0 | 77 | // advance to after the next \0 |
diff --git a/init/ueventd.cpp b/init/ueventd.cpp index c0eae1e9a..93ab0a31b 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "devices.h" | 36 | #include "devices.h" |
37 | #include "firmware_handler.h" | 37 | #include "firmware_handler.h" |
38 | #include "log.h" | 38 | #include "log.h" |
39 | #include "modalias_handler.h" | ||
39 | #include "uevent_listener.h" | 40 | #include "uevent_listener.h" |
40 | #include "ueventd_parser.h" | 41 | #include "ueventd_parser.h" |
41 | #include "util.h" | 42 | #include "util.h" |
@@ -105,9 +106,11 @@ namespace init { | |||
105 | 106 | ||
106 | class ColdBoot { | 107 | class ColdBoot { |
107 | public: | 108 | public: |
108 | ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler) | 109 | ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler, |
110 | ModaliasHandler& modalias_handler) | ||
109 | : uevent_listener_(uevent_listener), | 111 | : uevent_listener_(uevent_listener), |
110 | device_handler_(device_handler), | 112 | device_handler_(device_handler), |
113 | modalias_handler_(modalias_handler), | ||
111 | num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {} | 114 | num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {} |
112 | 115 | ||
113 | void Run(); | 116 | void Run(); |
@@ -121,6 +124,7 @@ class ColdBoot { | |||
121 | 124 | ||
122 | UeventListener& uevent_listener_; | 125 | UeventListener& uevent_listener_; |
123 | DeviceHandler& device_handler_; | 126 | DeviceHandler& device_handler_; |
127 | ModaliasHandler& modalias_handler_; | ||
124 | 128 | ||
125 | unsigned int num_handler_subprocesses_; | 129 | unsigned int num_handler_subprocesses_; |
126 | std::vector<Uevent> uevent_queue_; | 130 | std::vector<Uevent> uevent_queue_; |
@@ -132,6 +136,7 @@ void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_pr | |||
132 | for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) { | 136 | for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) { |
133 | auto& uevent = uevent_queue_[i]; | 137 | auto& uevent = uevent_queue_[i]; |
134 | device_handler_.HandleDeviceEvent(uevent); | 138 | device_handler_.HandleDeviceEvent(uevent); |
139 | modalias_handler_.HandleModaliasEvent(uevent); | ||
135 | } | 140 | } |
136 | _exit(EXIT_SUCCESS); | 141 | _exit(EXIT_SUCCESS); |
137 | } | 142 | } |
@@ -262,10 +267,11 @@ int ueventd_main(int argc, char** argv) { | |||
262 | selinux_set_callback(SELINUX_CB_LOG, cb); | 267 | selinux_set_callback(SELINUX_CB_LOG, cb); |
263 | 268 | ||
264 | DeviceHandler device_handler = CreateDeviceHandler(); | 269 | DeviceHandler device_handler = CreateDeviceHandler(); |
270 | ModaliasHandler modalias_handler; | ||
265 | UeventListener uevent_listener; | 271 | UeventListener uevent_listener; |
266 | 272 | ||
267 | if (access(COLDBOOT_DONE, F_OK) != 0) { | 273 | if (access(COLDBOOT_DONE, F_OK) != 0) { |
268 | ColdBoot cold_boot(uevent_listener, device_handler); | 274 | ColdBoot cold_boot(uevent_listener, device_handler, modalias_handler); |
269 | cold_boot.Run(); | 275 | cold_boot.Run(); |
270 | } | 276 | } |
271 | 277 | ||
@@ -276,8 +282,9 @@ int ueventd_main(int argc, char** argv) { | |||
276 | while (waitpid(-1, nullptr, WNOHANG) > 0) { | 282 | while (waitpid(-1, nullptr, WNOHANG) > 0) { |
277 | } | 283 | } |
278 | 284 | ||
279 | uevent_listener.Poll([&device_handler](const Uevent& uevent) { | 285 | uevent_listener.Poll([&device_handler, &modalias_handler](const Uevent& uevent) { |
280 | HandleFirmwareEvent(uevent); | 286 | HandleFirmwareEvent(uevent); |
287 | modalias_handler.HandleModaliasEvent(uevent); | ||
281 | device_handler.HandleDeviceEvent(uevent); | 288 | device_handler.HandleDeviceEvent(uevent); |
282 | return ListenerAction::kContinue; | 289 | return ListenerAction::kContinue; |
283 | }); | 290 | }); |