summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/Android.bp1
-rw-r--r--init/modalias_handler.cpp176
-rw-r--r--init/modalias_handler.h47
-rw-r--r--init/uevent.h1
-rw-r--r--init/uevent_listener.cpp4
-rw-r--r--init/ueventd.cpp13
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
35namespace android {
36namespace init {
37
38bool 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
70bool 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
91ModaliasHandler::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
111bool 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
133bool 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
156void 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
25namespace android {
26namespace init {
27
28class 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
106class ColdBoot { 107class 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 });