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