Merge "Revert "Switch to PCRE grep.""
diff --git a/init/Android.bp b/init/Android.bp
index c02b8d1..660d586 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -108,6 +108,7 @@
"import_parser.cpp",
"init.cpp",
"keychords.cpp",
+ "modalias_handler.cpp",
"parser.cpp",
"persistent_properties.cpp",
"persistent_properties.proto",
diff --git a/init/modalias_handler.cpp b/init/modalias_handler.cpp
new file mode 100644
index 0000000..1734a7e
--- /dev/null
+++ b/init/modalias_handler.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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 "modalias_handler.h"
+
+#include <fnmatch.h>
+#include <sys/syscall.h>
+
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include "parser.h"
+
+namespace android {
+namespace init {
+
+Result<Success> ModaliasHandler::ParseDepCallback(std::vector<std::string>&& args) {
+ std::vector<std::string> deps;
+
+ // Set first item as our modules path
+ std::string::size_type pos = args[0].find(':');
+ if (pos != std::string::npos) {
+ deps.emplace_back(args[0].substr(0, pos));
+ } else {
+ return Error() << "dependency lines must start with name followed by ':'";
+ }
+
+ // Remaining items are dependencies of our module
+ for (auto arg = args.begin() + 1; arg != args.end(); ++arg) {
+ deps.push_back(*arg);
+ }
+
+ // Key is striped module name to match names in alias file
+ std::size_t start = args[0].find_last_of("/");
+ std::size_t end = args[0].find(".ko:");
+ if ((end - start) <= 1) return Error() << "malformed dependency line";
+ auto mod_name = args[0].substr(start + 1, (end - start) - 1);
+ // module names can have '-', but their file names will have '_'
+ std::replace(mod_name.begin(), mod_name.end(), '-', '_');
+ this->module_deps_[mod_name] = deps;
+
+ return Success();
+}
+
+Result<Success> ModaliasHandler::ParseAliasCallback(std::vector<std::string>&& args) {
+ auto it = args.begin();
+ const std::string& type = *it++;
+
+ if (type != "alias") {
+ return Error() << "we only handle alias lines, got: " << type;
+ }
+
+ if (args.size() != 3) {
+ return Error() << "alias lines must have 3 entries";
+ }
+
+ std::string& alias = *it++;
+ std::string& module_name = *it++;
+ this->module_aliases_.emplace_back(alias, module_name);
+
+ return Success();
+}
+
+ModaliasHandler::ModaliasHandler() {
+ using namespace std::placeholders;
+
+ static const std::string base_paths[] = {
+ "/vendor/lib/modules/",
+ "/lib/modules/",
+ "/odm/lib/modules/",
+ };
+
+ Parser alias_parser;
+ auto alias_callback = std::bind(&ModaliasHandler::ParseAliasCallback, this, _1);
+ alias_parser.AddSingleLineParser("alias", alias_callback);
+ for (const auto& base_path : base_paths) alias_parser.ParseConfig(base_path + "modules.alias");
+
+ Parser dep_parser;
+ auto dep_callback = std::bind(&ModaliasHandler::ParseDepCallback, this, _1);
+ dep_parser.AddSingleLineParser("", dep_callback);
+ for (const auto& base_path : base_paths) dep_parser.ParseConfig(base_path + "modules.dep");
+}
+
+Result<Success> ModaliasHandler::Insmod(const std::string& path_name, const std::string& args) {
+ base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
+ if (fd == -1) return ErrnoError() << "Could not open module '" << path_name << "'";
+
+ int ret = syscall(__NR_finit_module, fd.get(), args.c_str(), 0);
+ if (ret != 0) {
+ if (errno == EEXIST) {
+ // Module already loaded
+ return Success();
+ }
+ return ErrnoError() << "Failed to insmod '" << path_name << "' with args '" << args << "'";
+ }
+
+ LOG(INFO) << "Loaded kernel module " << path_name;
+ return Success();
+}
+
+Result<Success> ModaliasHandler::InsmodWithDeps(const std::string& module_name,
+ const std::string& args) {
+ if (module_name.empty()) {
+ return Error() << "Need valid module name";
+ }
+
+ auto it = module_deps_.find(module_name);
+ if (it == module_deps_.end()) {
+ return Error() << "Module '" << module_name << "' not in dependency file";
+ }
+ auto& dependencies = it->second;
+
+ // load module dependencies in reverse order
+ for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
+ if (auto result = Insmod(*dep, ""); !result) return result;
+ }
+
+ // load target module itself with args
+ return Insmod(dependencies[0], args);
+}
+
+void ModaliasHandler::HandleModaliasEvent(const Uevent& uevent) {
+ if (uevent.modalias.empty()) return;
+
+ for (const auto& [alias, module] : module_aliases_) {
+ if (fnmatch(alias.c_str(), uevent.modalias.c_str(), 0) != 0) continue; // Keep looking
+
+ LOG(DEBUG) << "Loading kernel module '" << module << "' for alias '" << uevent.modalias
+ << "'";
+
+ if (auto result = InsmodWithDeps(module, ""); !result) {
+ LOG(ERROR) << "Cannot load module: " << result.error();
+ // try another one since there may be another match
+ continue;
+ }
+
+ // loading was successful
+ return;
+ }
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/modalias_handler.h b/init/modalias_handler.h
new file mode 100644
index 0000000..e79da32
--- /dev/null
+++ b/init/modalias_handler.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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 "result.h"
+#include "uevent.h"
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace init {
+
+class ModaliasHandler {
+ public:
+ ModaliasHandler();
+ ~ModaliasHandler(){};
+
+ void HandleModaliasEvent(const Uevent& uevent);
+
+ private:
+ Result<Success> InsmodWithDeps(const std::string& module_name, const std::string& args);
+ Result<Success> Insmod(const std::string& path_name, const std::string& args);
+
+ Result<Success> ParseDepCallback(std::vector<std::string>&& args);
+ Result<Success> ParseAliasCallback(std::vector<std::string>&& args);
+
+ std::vector<std::pair<std::string, std::string>> module_aliases_;
+ std::unordered_map<std::string, std::vector<std::string>> module_deps_;
+};
+
+} // namespace init
+} // namespace android
diff --git a/init/uevent.h b/init/uevent.h
index c4fd945..dc35fd9 100644
--- a/init/uevent.h
+++ b/init/uevent.h
@@ -29,6 +29,7 @@
std::string firmware;
std::string partition_name;
std::string device_name;
+ std::string modalias;
int partition_num;
int major;
int minor;
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 24b14c4..8cf2128 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -39,6 +39,7 @@
uevent->firmware.clear();
uevent->partition_name.clear();
uevent->device_name.clear();
+ uevent->modalias.clear();
// currently ignoring SEQNUM
while (*msg) {
if (!strncmp(msg, "ACTION=", 7)) {
@@ -68,6 +69,9 @@
} else if (!strncmp(msg, "DEVNAME=", 8)) {
msg += 8;
uevent->device_name = msg;
+ } else if (!strncmp(msg, "MODALIAS=", 9)) {
+ msg += 9;
+ uevent->modalias = msg;
}
// advance to after the next \0
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index cd45a3f..e9d829b 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -36,6 +36,7 @@
#include "devices.h"
#include "firmware_handler.h"
+#include "modalias_handler.h"
#include "selinux.h"
#include "uevent_listener.h"
#include "ueventd_parser.h"
@@ -106,9 +107,11 @@
class ColdBoot {
public:
- ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler)
+ ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler,
+ ModaliasHandler& modalias_handler)
: uevent_listener_(uevent_listener),
device_handler_(device_handler),
+ modalias_handler_(modalias_handler),
num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
void Run();
@@ -122,6 +125,7 @@
UeventListener& uevent_listener_;
DeviceHandler& device_handler_;
+ ModaliasHandler& modalias_handler_;
unsigned int num_handler_subprocesses_;
std::vector<Uevent> uevent_queue_;
@@ -133,6 +137,7 @@
for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
auto& uevent = uevent_queue_[i];
device_handler_.HandleDeviceEvent(uevent);
+ modalias_handler_.HandleModaliasEvent(uevent);
}
_exit(EXIT_SUCCESS);
}
@@ -230,6 +235,7 @@
SelabelInitialize();
DeviceHandler device_handler;
+ ModaliasHandler modalias_handler;
UeventListener uevent_listener;
{
@@ -251,7 +257,7 @@
}
if (access(COLDBOOT_DONE, F_OK) != 0) {
- ColdBoot cold_boot(uevent_listener, device_handler);
+ ColdBoot cold_boot(uevent_listener, device_handler, modalias_handler);
cold_boot.Run();
}
@@ -262,8 +268,9 @@
while (waitpid(-1, nullptr, WNOHANG) > 0) {
}
- uevent_listener.Poll([&device_handler](const Uevent& uevent) {
+ uevent_listener.Poll([&device_handler, &modalias_handler](const Uevent& uevent) {
HandleFirmwareEvent(uevent);
+ modalias_handler.HandleModaliasEvent(uevent);
device_handler.HandleDeviceEvent(uevent);
return ListenerAction::kContinue;
});
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 1314330..e7b1728 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -40,19 +40,6 @@
#endif
#endif
-/*
- * Use __VA_ARGS__ if running a static analyzer,
- * to avoid warnings of unused variables in __VA_ARGS__.
- * __FAKE_USE_VA_ARGS is undefined at link time,
- * so don't link with __clang_analyzer__ defined.
- */
-#ifdef __clang_analyzer__
-extern void __fake_use_va_args(int, ...);
-#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
-#else
-#define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif
-
/* --------------------------------------------------------------------- */
/*
@@ -66,6 +53,19 @@
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
+/*
+ * Use __VA_ARGS__ if running a static analyzer,
+ * to avoid warnings of unused variables in __VA_ARGS__.
+ * __FAKE_USE_VA_ARGS is undefined at link time,
+ * so don't link with __clang_analyzer__ defined.
+ */
+#ifdef __clang_analyzer__
+extern void __fake_use_va_args(int, ...);
+#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#else
+#define __FAKE_USE_VA_ARGS(...) ((void)(0))
+#endif
+
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif