• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

system/corennnnn


Commit MetaInfo

Revisão6806855b011933ae7d8e1007eabda00e4d774e1b (tree)
Hora2016-12-09 16:22:10
AutorChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Mensagem de Log

ueventd: auto load modules on uevents

This is a squashed and refactory patch of the following commits
from marshmallow-x86:

  • add modprobe-like capability and automatic ueventd loading
Author: Jianxun Zhang <jianxun.zhang@intel.com>
Author: Daniel Leung <daniel.leung@intel.com>
Author: Andrew Boie <andrew.p.boie@intel.com>
- insmod_by_dep() added to libcutils; loads a module into kernel.
Modules the target module depends on will be loaded first. Loading
will be stopped when an error occurs.
- rmmod_by_dep() added to libcutils; removes a module from kernel.
It also tries to remove other modules the target module depends
on until an error occurs.
- Implement wildcard matching for ueventd rules.
The PCI and USB addresses for devices can change from devices
from devices for a particular class of peripheral, for example,
    1. The ueventd rules created with these addresses are
      then device-specific.
This changes the way ueventd rules with wildcard are handled.
Instead of matching just the prefix with a trailing wildcard,
now these rules can have wildcard anywhere in the rule.
The wildcard matching is implemented using fnmatch(), where
its matching is simliar to shell pathname expansion. It suits
this particular usage model well.
For example, instead of creating a rule to match:
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/rfkill*
, this would suffice:
/sys/devices/*/bluetooth/hci0/rfkill*
- Let ueventd auto-load kernel modules. Implements the functionality
for ueventd to auto-load kernel modules when uevents are triggered.
Since /system may not be mounted when uevents are fired,
a deferred loading mechanism is implemented. Once mapping of
module and alias is available, these modules are then loaded.
Modules can also be blacklisted so they will not be loaded
    1. One example would be the Wifi driver, as
      Android's has to control its loading and unloading.
- add 'probemod' builtin command. This command accepts the name of a
kernel module plus a set of command line arguments. The module will
be loaded, along with all its dependencies, using the libcutils
insmod_by_dep() API.
- Drivers in kernel can request modules by launching a program in
user space, the program's path by default is "/sbin/modprobe".
Because Android system has no modprobe and ueventd is the only
program handling the module aliases so far, This patch provides a
cheap approach to handle kernel's requests in ueventd executable.
- Add new builtin init command "coldboot". The main purpose is to
provide an approach in init.*.rc files to fire uevents for devices
under the path which is passed as the the argument. This should be
called after /system is mounted so any queued events that need to
load a module can be fired.
  • allow to load modules from standard module path
  • ueventd: load modules in a forked process
Loading some modules (e.g., ath3k) will be blocked to wait for
    1. The forking is necessary, otherwise ueventd has no
      chance to load the firmware.
  • init: add modprobe to load kernel requested modules
  • libcutils: refine probe_module
Make the code be more elegant and fix the realloc bug.
  • ueventd: refactory module and firmware loading mechanism
Currently each module and firmware loading event is forked to
a child process to handle. It may cause some race conditions.
Now we fork ueventd into two processes. The parent process handles
normal uevents including modules loading, while the child process
only handles firmware loading events. All events are handled
sequentially.
  • ueventd: load all modules with the matched alias
Originally we only load the first module with the matched alias.
It causes some necessary modules are not loaded.

Mudança Sumário

Diff

--- /dev/null
+++ b/include/cutils/probe_module.h
@@ -0,0 +1,103 @@
1+/*
2+ * Copyright (C) 2012 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+#ifndef _LIBS_CUTILS_PROBEMODULE_H
18+#define _LIBS_CUTILS_PROBEMODULE_H
19+
20+#ifdef __cplusplus
21+extern "C" {
22+#endif
23+
24+/* get_default_mod_path() - get the default modules path
25+ * It checks /system/lib/modules/$(uname -r)/ first. If it doesn't exist,
26+ * fall back to /system/lib/modules/.
27+ *
28+ * def_mod_path: The buffer to be filled
29+ *
30+ * return : def_mod_path
31+ */
32+extern char *get_default_mod_path(char *def_mod_path);
33+
34+/* insmod() - load a kernel module (target) from a file
35+ *
36+ * filename : Filename of the target module.
37+ *
38+ * args : A string of target module's parameters. NOTE: we only
39+ * support parameters of the target module.
40+ *
41+ */
42+extern int insmod(const char *filename, const char *args);
43+
44+/* insmod_by_dep() - load a kernel module (target) with its dependency
45+ * The module's dependency must be described in the provided dependency file.
46+ * other modules in the dependency chain will be loaded prior to the target.
47+ *
48+ * module_name: Name of the target module. e.g. name "MyModule" is for
49+ * module file MyModule.ko.
50+ *
51+ * args : A string of target module's parameters. NOTE: we only
52+ * support parameters of the target module.
53+ *
54+ * dep_name : Name of dependency file. If it is NULL, we will look
55+ * up /system/lib/modules/modules.dep by default.
56+ *
57+ * strip : Non-zero values remove paths of modules in dependency.
58+ * before loading them. The final path of a module will be
59+ * base/MyModule.ko. This is for devices which put every
60+ * modules into a single directory.
61+ *
62+ * Passing 0 to strip keeps module paths in dependency file.
63+ * e.g. "kernel/drivers/.../MyModule.ko" in dep file will
64+ * be loaded as base/kernel/drivers/.../MyModule.ko .
65+ *
66+ * base : Base dir, a prefix to be added to module's path prior to
67+ * loading. The last character prior to base string's terminator
68+ * must be a '/'. If it is NULL, we will take
69+ * /system/lib/modules/modules.dep by default.
70+ *
71+ * return : 0 for success; non-zero for any errors.
72+ *
73+ * Note:
74+ * When loading modules, function will not fail for any modules which are
75+ * already in kernel. The module parameters passed to function will not be
76+ * effective in this case if target module is already loaded into kernel.
77+ */
78+extern int insmod_by_dep(
79+ const char *module_name,
80+ const char *args,
81+ const char *dep_name,
82+ int strip,
83+ const char * base);
84+
85+/* rmmod_by_dep() - remove a module (target) from kernel with its dependency
86+ * The module's dependency must be described in the provided dependency file.
87+ * This function will try to remove other modules in the dependency chain too
88+ *
89+ * module_name: Name of the target module. e.g. name "MyModule" is for
90+ * module file MyModule.ko.
91+ *
92+ * dep_name : Name of dependency file. If it is NULL, we will look
93+ * up /system/lib/modules/modules.dep by default.
94+ *
95+ * return : 0 for success; non-zero for any errors.
96+ */
97+extern int rmmod_by_dep(const char *module_name, const char *dep_name);
98+
99+#ifdef __cplusplus
100+}
101+#endif
102+
103+#endif /*_LIBS_CUTILS_PROBEMODULE_H*/
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -105,6 +105,7 @@ LOCAL_STATIC_LIBRARIES := \
105105
106106 # Create symlinks
107107 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
108+ ln -sf ../init $(TARGET_ROOT_OUT)/sbin/modprobe; \
108109 ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
109110 ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
110111
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -29,7 +29,6 @@
2929 #include <sys/socket.h>
3030 #include <sys/mount.h>
3131 #include <sys/resource.h>
32-#include <sys/syscall.h>
3332 #include <sys/time.h>
3433 #include <sys/types.h>
3534 #include <sys/stat.h>
@@ -49,6 +48,7 @@
4948 #include <bootloader_message/bootloader_message.h>
5049 #include <cutils/partition_utils.h>
5150 #include <cutils/android_reboot.h>
51+#include <cutils/probe_module.h>
5252 #include <logwrap/logwrap.h>
5353 #include <private/android_filesystem_config.h>
5454
@@ -69,20 +69,6 @@
6969
7070 static const int kTerminateServiceDelayMicroSeconds = 50000;
7171
72-static int insmod(const char *filename, const char *options) {
73- int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
74- if (fd == -1) {
75- ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
76- return -1;
77- }
78- int rc = syscall(__NR_finit_module, fd, options, 0);
79- if (rc == -1) {
80- ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno));
81- }
82- close(fd);
83- return rc;
84-}
85-
8672 static int __ifupdown(const char *interface, int up) {
8773 struct ifreq ifr;
8874 int s, ret;
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -42,12 +42,14 @@
4242
4343 #include <android-base/file.h>
4444 #include <cutils/list.h>
45+#include <cutils/probe_module.h>
4546 #include <cutils/uevent.h>
4647
4748 #include "devices.h"
4849 #include "ueventd_parser.h"
4950 #include "util.h"
5051 #include "log.h"
52+#include "parser.h"
5153
5254 #define SYSFS_PREFIX "/sys"
5355 #if defined(__i386__) || defined(__x86_64__)
@@ -58,6 +60,10 @@ static const char *firmware_dirs[] = { "/etc/firmware",
5860 "/firmware/image" };
5961 #endif
6062
63+#define MODULES_BLKLST "/system/etc/modules.blacklist"
64+#define READ_MODULES_ALIAS 1
65+#define READ_MODULES_BLKLST 2
66+
6167 extern struct selabel_handle *sehandle;
6268
6369 static int device_fd = -1;
@@ -69,6 +75,7 @@ struct uevent {
6975 const char *firmware;
7076 const char *partition_name;
7177 const char *device_name;
78+ const char *modalias;
7279 int partition_num;
7380 int major;
7481 int minor;
@@ -96,9 +103,26 @@ struct platform_node {
96103 struct listnode list;
97104 };
98105
106+struct module_alias_node {
107+ char *name;
108+ char *pattern;
109+ struct listnode list;
110+};
111+
112+struct module_blacklist_node {
113+ char *name;
114+ struct listnode list;
115+};
116+
99117 static list_declare(sys_perms);
100118 static list_declare(dev_perms);
101119 static list_declare(platform_names);
120+static list_declare(modules_aliases_map);
121+static list_declare(modules_blacklist);
122+static list_declare(deferred_module_loading_list);
123+
124+static int read_modules_aliases();
125+static int read_modules_blacklist();
102126
103127 int add_dev_perms(const char *name, const char *attr,
104128 mode_t perm, unsigned int uid, unsigned int gid,
@@ -377,6 +401,7 @@ static void parse_event(const char *msg, struct uevent *uevent)
377401 uevent->partition_name = NULL;
378402 uevent->partition_num = -1;
379403 uevent->device_name = NULL;
404+ uevent->modalias = NULL;
380405
381406 /* currently ignoring SEQNUM */
382407 while(*msg) {
@@ -407,6 +432,9 @@ static void parse_event(const char *msg, struct uevent *uevent)
407432 } else if(!strncmp(msg, "DEVNAME=", 8)) {
408433 msg += 8;
409434 uevent->device_name = msg;
435+ } else if(!strncmp(msg, "MODALIAS=", 9)) {
436+ msg += 9;
437+ uevent->modalias = msg;
410438 }
411439
412440 /* advance to after the next \0 */
@@ -746,8 +774,182 @@ static void handle_generic_device_event(struct uevent *uevent)
746774 uevent->major, uevent->minor, links);
747775 }
748776
777+static int is_module_blacklisted(const char *name)
778+{
779+ struct listnode *blklst_node;
780+ struct module_blacklist_node *blacklist;
781+ int ret = 0;
782+
783+ if (!name) goto out;
784+
785+ /* See if module is blacklisted, skip if it is */
786+ list_for_each(blklst_node, &modules_blacklist) {
787+ blacklist = node_to_item(blklst_node,
788+ struct module_blacklist_node,
789+ list);
790+ if (!strcmp(name, blacklist->name)) {
791+ INFO("modules %s is blacklisted\n", name);
792+ ret = 1;
793+ goto out;
794+ }
795+ }
796+
797+out:
798+ return ret;
799+}
800+
801+static int load_module_by_device_modalias(const char *id)
802+{
803+ struct listnode *alias_node;
804+ struct module_alias_node *alias;
805+ int ret = -1;
806+
807+ list_for_each(alias_node, &modules_aliases_map) {
808+ alias = node_to_item(alias_node, struct module_alias_node, list);
809+
810+ if (alias && alias->name && alias->pattern) {
811+ if (fnmatch(alias->pattern, id, 0) == 0) {
812+ INFO("trying to load module %s due to uevents\n", alias->name);
813+
814+ if (!is_module_blacklisted(alias->name)) {
815+ if (insmod_by_dep(alias->name, "", NULL, 0, NULL)) {
816+ /* cannot load module. try another one since
817+ * there may be another match.
818+ */
819+ NOTICE("failed to load %s for modalias %s\n",
820+ alias->name, id);
821+ } else {
822+ /* loading was successful */
823+ INFO("loaded module %s due to uevents\n", alias->name);
824+ ret = 0;
825+ }
826+ }
827+ }
828+ }
829+ }
830+
831+ return ret;
832+}
833+
834+static void handle_deferred_module_loading()
835+{
836+ /* try to read the module alias mapping if map is empty
837+ * if succeed, loading all the modules in the queue
838+ */
839+ if (!list_empty(&modules_aliases_map)) {
840+ struct listnode *node = NULL;
841+ struct listnode *next = NULL;
842+ struct module_alias_node *alias = NULL;
843+
844+ list_for_each_safe(node, next, &deferred_module_loading_list) {
845+ alias = node_to_item(node, struct module_alias_node, list);
846+
847+ if (alias && alias->pattern) {
848+ INFO("deferred loading of module for %s\n", alias->pattern);
849+ load_module_by_device_modalias(alias->pattern);
850+ free(alias->pattern);
851+ list_remove(node);
852+ free(alias);
853+ }
854+ }
855+ }
856+}
857+
858+static int module_probe(int argc, char **argv)
859+{
860+ if (list_empty(&modules_aliases_map)) {
861+ read_modules_aliases();
862+ read_modules_blacklist();
863+ }
864+
865+ // is it a modalias?
866+ int ret = load_module_by_device_modalias(argv[1]);
867+ if (ret) {
868+ // treat it as a module name
869+ std::string options;
870+ if (argc > 2) {
871+ options = argv[2];
872+ for (int i = 3; i < argc; ++i) {
873+ options += ' ';
874+ options += argv[i];
875+ }
876+ }
877+ ret = insmod_by_dep(argv[1], options.c_str(), NULL, 0, NULL);
878+ }
879+ return ret;
880+}
881+
882+int modprobe_main(int argc, char **argv)
883+{
884+ const char *prog = argv[0];
885+
886+ /* We only accept requests from root user (kernel) */
887+ if (getuid())
888+ return -EPERM;
889+
890+ /* Kernel will launch a user space program specified by
891+ * /proc/sys/kernel/modprobe to load modules.
892+ * No deferred loading in this case.
893+ */
894+ while (argc > 1 && (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--"))) {
895+ klog_set_level(KLOG_NOTICE_LEVEL);
896+ argc--, argv++;
897+ }
898+
899+ if (argc < 2) {
900+ /* it is called without enough arguments */
901+ return -EINVAL;
902+ }
903+
904+ NOTICE("%s %s\n", prog, argv[1]);
905+ return module_probe(argc, argv);
906+}
907+
908+static void handle_module_loading(const char *modalias)
909+{
910+ struct module_alias_node *node;
911+
912+ /* once modules.alias can be read,
913+ * we load all the deferred ones
914+ */
915+ if (list_empty(&modules_aliases_map)) {
916+ if (read_modules_aliases() == 0) {
917+ read_modules_blacklist();
918+ handle_deferred_module_loading();
919+ }
920+ }
921+
922+ if (!modalias) return;
923+
924+ if (list_empty(&modules_aliases_map)) {
925+ /* if module alias mapping is empty,
926+ * queue it for loading later
927+ */
928+ node = (module_alias_node *) calloc(1, sizeof(*node));
929+ if (node) {
930+ node->pattern = strdup(modalias);
931+ if (!node->pattern) {
932+ free(node);
933+ } else {
934+ list_add_tail(&deferred_module_loading_list, &node->list);
935+ INFO("add to queue for deferred module loading: %s",
936+ node->pattern);
937+ }
938+ } else {
939+ ERROR("failed to allocate memory to store device id for deferred module loading.\n");
940+ }
941+ } else {
942+ load_module_by_device_modalias(modalias);
943+ }
944+
945+}
946+
749947 static void handle_device_event(struct uevent *uevent)
750948 {
949+ if (!strcmp(uevent->action,"add")) {
950+ handle_module_loading(uevent->modalias);
951+ }
952+
751953 if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
752954 fixup_sys_perms(uevent->path);
753955
@@ -810,7 +1012,7 @@ static void process_firmware_event(struct uevent *uevent)
8101012 size_t i;
8111013 int booting = is_booting();
8121014
813- INFO("firmware: loading '%s' for '%s'\n",
1015+ NOTICE("firmware: loading '%s' for '%s'\n",
8141016 uevent->firmware, uevent->path);
8151017
8161018 l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
@@ -878,26 +1080,155 @@ root_free_out:
8781080
8791081 static void handle_firmware_event(struct uevent *uevent)
8801082 {
881- pid_t pid;
882-
8831083 if(strcmp(uevent->subsystem, "firmware"))
8841084 return;
8851085
8861086 if(strcmp(uevent->action, "add"))
8871087 return;
8881088
889- /* we fork, to avoid making large memory allocations in init proper */
890- pid = fork();
891- if (!pid) {
892- process_firmware_event(uevent);
893- _exit(EXIT_SUCCESS);
894- } else if (pid < 0) {
895- ERROR("could not fork to process firmware event: %s\n", strerror(errno));
1089+ process_firmware_event(uevent);
1090+}
1091+
1092+static void parse_line_module_alias(struct parse_state *state, int nargs, char **args)
1093+{
1094+ struct module_alias_node *node;
1095+
1096+ if (!args ||
1097+ (nargs != 3) ||
1098+ !args[0] || !args[1] || !args[2]) {
1099+ /* empty line or not enough arguments */
1100+ return;
1101+ }
1102+
1103+ node = (module_alias_node *) calloc(1, sizeof(*node));
1104+ if (!node) return;
1105+
1106+ node->name = strdup(args[2]);
1107+ if (!node->name) {
1108+ free(node);
1109+ return;
1110+ }
1111+
1112+ node->pattern = strdup(args[1]);
1113+ if (!node->pattern) {
1114+ free(node->name);
1115+ free(node);
1116+ return;
8961117 }
1118+
1119+ list_add_tail(&modules_aliases_map, &node->list);
1120+}
1121+
1122+static void parse_line_module_blacklist(struct parse_state *state, int nargs, char **args)
1123+{
1124+ struct module_blacklist_node *node;
1125+
1126+ if (!args ||
1127+ (nargs != 2) ||
1128+ !args[0] || !args[1]) {
1129+ /* empty line or not enough arguments */
1130+ return;
1131+ }
1132+
1133+ /* this line does not being with "blacklist" */
1134+ if (strncmp(args[0], "blacklist", 9)) return;
1135+
1136+ node = (module_blacklist_node *) calloc(1, sizeof(*node));
1137+ if (!node) return;
1138+
1139+ node->name = strdup(args[1]);
1140+ if (!node->name) {
1141+ free(node);
1142+ return;
1143+ }
1144+
1145+ list_add_tail(&modules_blacklist, &node->list);
1146+}
1147+
1148+static int __read_modules_desc_file(int mode)
1149+{
1150+ struct parse_state state;
1151+ char *args[3];
1152+ int nargs;
1153+ char fn[PATH_MAX];
1154+ int fd = -1;
1155+ int ret = -1;
1156+ int args_to_read = 0;
1157+ std::string data;
1158+
1159+ if (mode == READ_MODULES_ALIAS) {
1160+ /* read modules.alias */
1161+ strcat(get_default_mod_path(fn), "modules.alias");
1162+ } else if (mode == READ_MODULES_BLKLST) {
1163+ /* read modules.blacklist */
1164+ strcpy(fn, MODULES_BLKLST);
1165+ } else {
1166+ /* unknown mode */
1167+ goto out;
1168+ }
1169+
1170+ fd = open(fn, O_RDONLY);
1171+ if (fd == -1) {
1172+ goto out;
1173+ }
1174+
1175+ /* read the whole file */
1176+ if (!read_file(fn, &data)) {
1177+ goto out;
1178+ }
1179+
1180+ /* invoke tokenizer */
1181+ nargs = 0;
1182+ state.filename = fn;
1183+ state.line = 1;
1184+ state.ptr = &data[0];
1185+ state.nexttoken = 0;
1186+ if (mode == READ_MODULES_ALIAS) {
1187+ state.parse_line = parse_line_module_alias;
1188+ args_to_read = 3;
1189+ } else if (mode == READ_MODULES_BLKLST) {
1190+ state.parse_line = parse_line_module_blacklist;
1191+ args_to_read = 2;
1192+ }
1193+ for (;;) {
1194+ int token = next_token(&state);
1195+ switch (token) {
1196+ case T_EOF:
1197+ state.parse_line(&state, 0, 0);
1198+ ret = 0;
1199+ goto out;
1200+ case T_NEWLINE:
1201+ if (nargs) {
1202+ state.parse_line(&state, nargs, args);
1203+ nargs = 0;
1204+ }
1205+ break;
1206+ case T_TEXT:
1207+ if (nargs < args_to_read) {
1208+ args[nargs++] = state.text;
1209+ }
1210+ break;
1211+ }
1212+ }
1213+ ret = 0;
1214+
1215+out:
1216+ if (fd != -1) {
1217+ close(fd);
1218+ }
1219+ return ret;
1220+}
1221+
1222+static int read_modules_aliases() {
1223+ return __read_modules_desc_file(READ_MODULES_ALIAS);
1224+}
1225+
1226+static int read_modules_blacklist() {
1227+ return __read_modules_desc_file(READ_MODULES_BLKLST);
8971228 }
8981229
8991230 #define UEVENT_MSG_LEN 2048
900-void handle_device_fd()
1231+void handle_device_fd(bool child)
9011232 {
9021233 char msg[UEVENT_MSG_LEN+2];
9031234 int n;
@@ -920,8 +1251,11 @@ void handle_device_fd()
9201251 }
9211252 }
9221253
923- handle_device_event(&uevent);
924- handle_firmware_event(&uevent);
1254+ if (child) {
1255+ handle_firmware_event(&uevent);
1256+ } else {
1257+ handle_device_event(&uevent);
1258+ }
9251259 }
9261260 }
9271261
@@ -977,7 +1311,8 @@ static void coldboot(const char *path)
9771311 }
9781312 }
9791313
980-void device_init() {
1314+void device_init(bool child)
1315+{
9811316 sehandle = selinux_android_file_context_handle();
9821317 selinux_status_open(true);
9831318
@@ -988,6 +1323,9 @@ void device_init() {
9881323 }
9891324 fcntl(device_fd, F_SETFL, O_NONBLOCK);
9901325
1326+ if (child) {
1327+ return; // don't do coldboot in child
1328+ }
9911329 if (access(COLDBOOT_DONE, F_OK) == 0) {
9921330 NOTICE("Skipping coldboot, already done!\n");
9931331 return;
--- a/init/devices.h
+++ b/init/devices.h
@@ -19,8 +19,9 @@
1919
2020 #include <sys/stat.h>
2121
22-extern void handle_device_fd();
23-extern void device_init(void);
22+extern void handle_device_fd(bool = false);
23+extern void device_init(bool);
24+extern int modprobe_main(int argc, char **argv);
2425 extern int add_dev_perms(const char *name, const char *attr,
2526 mode_t perm, unsigned int uid,
2627 unsigned int gid, unsigned short prefix,
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -585,6 +585,10 @@ static void selinux_initialize(bool in_kernel_domain) {
585585 }
586586
587587 int main(int argc, char** argv) {
588+ if (strstr(argv[0], "modprobe")) {
589+ return modprobe_main(argc, argv);
590+ }
591+
588592 if (!strcmp(basename(argv[0]), "ueventd")) {
589593 return ueventd_main(argc, argv);
590594 }
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -15,12 +15,14 @@
1515 */
1616
1717 #include <ctype.h>
18+#include <errno.h>
1819 #include <fcntl.h>
1920 #include <poll.h>
2021 #include <signal.h>
2122 #include <stdio.h>
2223 #include <stdlib.h>
2324 #include <string.h>
25+#include <unistd.h>
2426
2527 #include <android-base/stringprintf.h>
2628 #include <private/android_filesystem_config.h>
@@ -64,8 +66,12 @@ int ueventd_main(int argc, char **argv)
6466 ueventd_parse_config_file("/ueventd.rc");
6567 ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
6668
67- device_init();
69+ pid_t pid = fork();
70+ if (pid < 0) {
71+ ERROR("could not fork to process firmware event: %s\n", strerror(errno));
72+ }
6873
74+ device_init(pid == 0);
6975 pollfd ufd;
7076 ufd.events = POLLIN;
7177 ufd.fd = get_device_fd();
@@ -77,7 +83,7 @@ int ueventd_main(int argc, char **argv)
7783 continue;
7884 }
7985 if (ufd.revents & POLLIN) {
80- handle_device_fd();
86+ handle_device_fd(pid == 0);
8187 }
8288 }
8389
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -98,6 +98,7 @@ LOCAL_SRC_FILES := $(libcutils_common_sources) \
9898 debugger.c \
9999 klog.c \
100100 partition_utils.c \
101+ probe_module.c \
101102 properties.c \
102103 qtaguid.c \
103104 trace-dev.c \
--- /dev/null
+++ b/libcutils/probe_module.c
@@ -0,0 +1,387 @@
1+/*
2+ * Copyright (C) 2012 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 <stdio.h>
18+#include <stdlib.h>
19+#include <string.h>
20+#include <limits.h>
21+#include <errno.h>
22+#include <fcntl.h>
23+#include <cutils/misc.h>
24+#include <sys/syscall.h>
25+#include <sys/utsname.h>
26+
27+#define LOG_TAG "ProbeModule"
28+#include <cutils/log.h>
29+
30+#define LDM_DEFAULT_MOD_PATH "/system/lib/modules/"
31+
32+extern int delete_module(const char *, unsigned int);
33+
34+/* get_default_mod_path() interface to outside,
35+ * refer to its description in probe_module.h
36+ */
37+char *get_default_mod_path(char *def_mod_path)
38+{
39+ int len;
40+ struct utsname buf;
41+ uname(&buf);
42+ len = snprintf(def_mod_path, PATH_MAX, "%s", LDM_DEFAULT_MOD_PATH);
43+ strcpy(def_mod_path + len, buf.release);
44+ if (access(def_mod_path, F_OK))
45+ def_mod_path[len] = '\0';
46+ else
47+ strcat(def_mod_path, "/");
48+ return def_mod_path;
49+}
50+
51+int insmod(const char *filename, const char *options)
52+{
53+ int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
54+ if (fd == -1) {
55+ ALOGE("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
56+ return -1;
57+ }
58+ int rc = syscall(__NR_finit_module, fd, options, 0);
59+ if (rc == -1) {
60+ if (errno == EEXIST) {
61+ rc = 0;
62+ } else {
63+ ALOGE("finit_module for \"%s\" failed: %s", filename, strerror(errno));
64+ }
65+ }
66+ close(fd);
67+ return rc;
68+}
69+
70+static char *strip_path(char *str)
71+{
72+ char *ptr = strrchr(str, '/');
73+ return ptr ? ptr + 1 : str;
74+}
75+
76+static void hyphen_to_underscore(char *str)
77+{
78+ while (str && *str != '\0') {
79+ if (*str == '-')
80+ *str = '_';
81+ str++;
82+ }
83+}
84+
85+/* Compare module names, but don't differentiate '_' and '-'.
86+ * return: 0 when s1 is matched to s2 or size is zero.
87+ * non-zero in any other cases.
88+ */
89+static int match_name(const char *s1, const char *s2, const size_t size)
90+{
91+ size_t i;
92+
93+ if (!size)
94+ return 0;
95+
96+ for (i = 0; i < size; i++, s1++, s2++) {
97+
98+ if ((*s1 == '_' || *s1 == '-') && (*s2 == '_' || *s2 == '-'))
99+ continue;
100+
101+ if (*s1 != *s2)
102+ return -1;
103+
104+ if (*s1 == '\0')
105+ return 0;
106+ }
107+
108+ return 0;
109+}
110+
111+/* check if a line in dep file is target module's dependency.
112+ * return 1 when it is, otherwise 0 in any other cases.
113+ */
114+static int is_target_module(char *line, const char *target)
115+{
116+ char *token;
117+ char name[PATH_MAX];
118+ const char *delimiter = ":";
119+ int ret = 0;
120+
121+ /* search token */
122+ token = strstr(line, delimiter);
123+
124+ if (!token) {
125+ ALOGE("invalid line: no token");
126+ return 0;
127+ }
128+
129+ /* only take stuff before the token */
130+ *token = '\0';
131+
132+ /* use "module.ko" in comparision */
133+ strcat(strcpy(name, target), ".ko");
134+
135+ ret = !match_name(strip_path(line), name, strlen(name));
136+
137+ /* restore [single] token, keep line unchanged until we parse it later */
138+ *token = *delimiter;
139+
140+ return ret;
141+
142+}
143+
144+/* turn a single string into an array of dependency.
145+ *
146+ * return: dependency array's address if it succeeded. Caller
147+ * is responsible to free the array's memory.
148+ * NULL when any error happens.
149+ */
150+static char **setup_dep(char *line)
151+{
152+ char *tmp = line;
153+ char *brk;
154+ int i;
155+ char **dep;
156+
157+ for (i = 2; (tmp = strchr(tmp, ' ')); i++)
158+ tmp++;
159+
160+ dep = malloc(sizeof(char *) * i);
161+ if (dep) {
162+ i = 0;
163+ do {
164+ tmp = strtok_r(i ? NULL : line, ": ", &brk);
165+ } while ((dep[i++] = tmp));
166+ }
167+
168+ return dep;
169+}
170+
171+/* install all modules in the dependency chain
172+ * deps : A array of module file names, must be terminated by a NULL pointer
173+ * args : The module parameters for target module.
174+ * strip : Non-zero to strip out path info in the file name;
175+ * 0 to keep path info when loading modules.
176+ * base : a prefix to module path, it will NOT be affected by strip flag.
177+ * return : 0 for success or nothing to do; non-zero when any error occurs.
178+ */
179+static int insmod_s(char *dep[], const char *args, int strip, const char *base)
180+{
181+ char *name;
182+ int cnt;
183+ size_t len;
184+ int ret = 0;
185+ char path_name[PATH_MAX];
186+ char def_mod_path[PATH_MAX];
187+ const char *base_dir;
188+
189+ if (base && strlen(base))
190+ base_dir = base;
191+ else
192+ base_dir = get_default_mod_path(def_mod_path);
193+
194+ /* load modules in reversed order */
195+ for (cnt = 0; dep[cnt]; cnt++)
196+ ;
197+
198+ len = strlen(strcpy(path_name, base_dir));
199+
200+ while (!ret && cnt--) {
201+
202+ name = strip ? strip_path(dep[cnt]) : dep[cnt];
203+
204+ strcpy(path_name + len, name);
205+
206+ ret = insmod(path_name, cnt ? "" : args);
207+ }
208+
209+ return ret;
210+}
211+
212+/* remove all modules in a dependency chain
213+ * NOTE: We assume module name in kernel is same as the file name without .ko
214+ */
215+static int rmmod_s(char *dep[], int flags)
216+{
217+ int i;
218+ int ret = 0;
219+
220+ for (i = 0; dep[i]; i++) {
221+ char *mod_name = strip_path(dep[i]);
222+ size_t len = strlen(mod_name);
223+
224+ if (len > 3 && strstr(mod_name, ".ko") == (mod_name + len - 3)) {
225+ mod_name[len - 3] = '\0';
226+
227+ hyphen_to_underscore(mod_name);
228+
229+ ret = delete_module(mod_name, flags);
230+
231+ if (ret) {
232+ ALOGE("%s: Failed to remove module [%s] error (%s)",
233+ __FUNCTION__, mod_name, strerror(errno));
234+ break;
235+
236+ }
237+ }
238+ }
239+
240+ return ret;
241+}
242+
243+/* look_up_dep() find and setup target module's dependency in modules.dep
244+ *
245+ * dep_file: a pointer to module's dep file loaded in memory, its content
246+ * will be CHANGED during parsing.
247+ *
248+ * return: a pointer to an array which holds the dependency strings and
249+ * terminated by a NULL pointer. Caller is responsible to free the
250+ * array's memory.
251+ *
252+ * non-zero in any other cases. Content of dep array is invalid.
253+ */
254+static char **look_up_dep(const char *module_name, void *dep_file)
255+{
256+ char *line;
257+ char *saved_pos;
258+ char *start;
259+ char **dep = NULL;
260+
261+ if (!dep_file || !module_name || *module_name == '\0')
262+ return NULL;
263+
264+ start = (char *)dep_file;
265+
266+ /* We expect modules.dep file has a new line char before EOF. */
267+ while ((line = strtok_r(start, "\n", &saved_pos)) != NULL) {
268+
269+ start = NULL;
270+
271+ if (is_target_module(line, module_name)) {
272+
273+ dep = setup_dep(line);
274+ /* job done */
275+ break;
276+ }
277+ }
278+
279+ return dep;
280+}
281+
282+/* load_dep_file() load a dep file (usually it is modules.dep)
283+ * into memory. Caller is responsible to free the memory.
284+ *
285+ * file_name: dep file's name, if it is NULL or an empty string,
286+ * This function will try to load a dep file in the
287+ * default path defined in LDM_DEFAULT_DEP_FILE
288+ *
289+ * return: a pointer to the allocated mem which holds all
290+ * content of the depfile. a zero pointer will be
291+ * returned for any errors.
292+ * */
293+static void *load_dep_file(const char *file_name)
294+{
295+ unsigned int len;
296+ char def_mod_path[PATH_MAX];
297+ if (!file_name || *file_name == '\0') {
298+ file_name = get_default_mod_path(def_mod_path);
299+ strcat(def_mod_path, "modules.dep");
300+ }
301+
302+ return load_file(file_name, &len);
303+}
304+
305+/* insmod_by_dep() interface to outside,
306+ * refer to its description in probe_module.h
307+ */
308+int insmod_by_dep(const char *module_name,
309+ const char *args,
310+ const char *dep_name,
311+ int strip,
312+ const char *base)
313+{
314+ void *dep_file;
315+ char **dep = NULL;
316+ int ret = -1;
317+
318+ if (!module_name || *module_name == '\0') {
319+ ALOGE("need valid module name");
320+ return ret;
321+ }
322+
323+ dep_file = load_dep_file(dep_name);
324+
325+ if (!dep_file) {
326+ ALOGE("cannot load dep file : %s", dep_name);
327+ return ret;
328+ }
329+
330+ dep = look_up_dep(module_name, dep_file);
331+
332+ if (!dep) {
333+ ALOGE("%s: cannot load module: [%s]", __FUNCTION__, module_name);
334+ goto free_file;
335+ }
336+
337+ ret = insmod_s(dep, args, strip, base);
338+
339+ free(dep);
340+
341+free_file:
342+ free(dep_file);
343+
344+ return ret;
345+
346+}
347+
348+/* rmmod_by_dep() interface to outside,
349+ * refer to its description in probe_module.h
350+ */
351+int rmmod_by_dep(const char *module_name,
352+ const char *dep_name)
353+{
354+ void *dep_file;
355+ char **dep = NULL;
356+ int ret = -1;
357+
358+ if (!module_name || *module_name == '\0') {
359+ ALOGE("need valid module name");
360+ return ret;
361+ }
362+
363+ dep_file = load_dep_file(dep_name);
364+
365+ if (!dep_file) {
366+ ALOGE("cannot load dep file : %s", dep_name);
367+ return ret;
368+ }
369+
370+ dep = look_up_dep(module_name, dep_file);
371+
372+ if (!dep) {
373+ ALOGE("%s: cannot remove module: [%s]", __FUNCTION__, module_name);
374+ goto free_file;
375+ }
376+
377+ ret = rmmod_s(dep, O_NONBLOCK);
378+
379+ free(dep);
380+
381+free_file:
382+ free(dep_file);
383+
384+ return ret;
385+}
386+
387+/* end of file */