init: Handle commands in event queue loop
Change-Id: I679059dae43143f3c8f16b68de5694539b699e50
This commit is contained in:
parent
bc39871bf9
commit
ebc6ff105a
|
@ -415,7 +415,6 @@ int do_restart(int nargs, char **args)
|
|||
int do_trigger(int nargs, char **args)
|
||||
{
|
||||
action_for_each_trigger(args[1], action_add_queue_tail);
|
||||
drain_action_queue();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
387
init/init.c
387
init/init.c
|
@ -63,6 +63,10 @@ static char hardware[32];
|
|||
static unsigned revision = 0;
|
||||
static char qemu[32];
|
||||
|
||||
static struct action *cur_action = NULL;
|
||||
static struct command *cur_command = NULL;
|
||||
static struct listnode *command_queue = NULL;
|
||||
|
||||
void notify_service_state(const char *name, const char *state)
|
||||
{
|
||||
char pname[PROP_NAME_MAX];
|
||||
|
@ -301,10 +305,8 @@ void service_stop(struct service *svc)
|
|||
|
||||
void property_changed(const char *name, const char *value)
|
||||
{
|
||||
if (property_triggers_enabled) {
|
||||
if (property_triggers_enabled)
|
||||
queue_property_triggers(name, value);
|
||||
drain_action_queue();
|
||||
}
|
||||
}
|
||||
|
||||
static void restart_service_if_needed(struct service *svc)
|
||||
|
@ -494,21 +496,52 @@ static void get_hardware_name(void)
|
|||
}
|
||||
}
|
||||
|
||||
void drain_action_queue(void)
|
||||
static struct command *get_first_command(struct action *act)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct command *cmd;
|
||||
struct action *act;
|
||||
node = list_head(&act->commands);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
return node_to_item(node, struct command, clist);
|
||||
}
|
||||
|
||||
static struct command *get_next_command(struct action *act, struct command *cmd)
|
||||
{
|
||||
struct listnode *node;
|
||||
node = cmd->clist.next;
|
||||
if (!node)
|
||||
return NULL;
|
||||
if (node == &act->commands)
|
||||
return NULL;
|
||||
|
||||
return node_to_item(node, struct command, clist);
|
||||
}
|
||||
|
||||
static int is_last_command(struct action *act, struct command *cmd)
|
||||
{
|
||||
return (list_tail(&act->commands) == &cmd->clist);
|
||||
}
|
||||
|
||||
void execute_one_command(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while ((act = action_remove_queue_head())) {
|
||||
INFO("processing action %p (%s)\n", act, act->name);
|
||||
list_for_each(node, &act->commands) {
|
||||
cmd = node_to_item(node, struct command, clist);
|
||||
ret = cmd->func(cmd->nargs, cmd->args);
|
||||
INFO("command '%s' r=%d\n", cmd->args[0], ret);
|
||||
}
|
||||
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
|
||||
cur_action = action_remove_queue_head();
|
||||
if (!cur_action)
|
||||
return;
|
||||
INFO("processing action %p (%s)\n", cur_action, cur_action->name);
|
||||
cur_command = get_first_command(cur_action);
|
||||
} else {
|
||||
cur_command = get_next_command(cur_action, cur_command);
|
||||
}
|
||||
|
||||
if (!cur_command)
|
||||
return;
|
||||
|
||||
ret = cur_command->func(cur_command->nargs, cur_command->args);
|
||||
INFO("command '%s' r=%d\n", cur_command->args[0], ret);
|
||||
}
|
||||
|
||||
void open_devnull_stdio(void)
|
||||
|
@ -532,16 +565,155 @@ void open_devnull_stdio(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static int device_init_action(int nargs, char **args)
|
||||
{
|
||||
INFO("device init\n");
|
||||
device_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int property_init_action(int nargs, char **args)
|
||||
{
|
||||
INFO("property init\n");
|
||||
property_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keychord_init_action(int nargs, char **args)
|
||||
{
|
||||
keychord_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_init_action(int nargs, char **args)
|
||||
{
|
||||
int fd;
|
||||
char tmp[PROP_VALUE_MAX];
|
||||
|
||||
if (console[0]) {
|
||||
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
|
||||
console_name = strdup(tmp);
|
||||
}
|
||||
|
||||
fd = open(console_name, O_RDWR);
|
||||
if (fd >= 0)
|
||||
have_console = 1;
|
||||
close(fd);
|
||||
|
||||
if( load_565rle_image(INIT_IMAGE_FILE) ) {
|
||||
fd = open("/dev/tty0", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
const char *msg;
|
||||
msg = "\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n" // console is 40 cols x 30 lines
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" A N D R O I D ";
|
||||
write(fd, msg, strlen(msg));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_init_properties_action(int nargs, char **args)
|
||||
{
|
||||
char tmp[PROP_VALUE_MAX];
|
||||
|
||||
if (qemu[0])
|
||||
import_kernel_cmdline(1);
|
||||
|
||||
if (!strcmp(bootmode,"factory"))
|
||||
property_set("ro.factorytest", "1");
|
||||
else if (!strcmp(bootmode,"factory2"))
|
||||
property_set("ro.factorytest", "2");
|
||||
else
|
||||
property_set("ro.factorytest", "0");
|
||||
|
||||
property_set("ro.serialno", serialno[0] ? serialno : "");
|
||||
property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
|
||||
property_set("ro.baseband", baseband[0] ? baseband : "unknown");
|
||||
property_set("ro.carrier", carrier[0] ? carrier : "unknown");
|
||||
property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
|
||||
|
||||
property_set("ro.hardware", hardware);
|
||||
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
|
||||
property_set("ro.revision", tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int property_service_init_action(int nargs, char **args)
|
||||
{
|
||||
/* read any property files on system or data and
|
||||
* fire up the property service. This must happen
|
||||
* after the ro.foo properties are set above so
|
||||
* that /data/local.prop cannot interfere with them.
|
||||
*/
|
||||
start_property_service();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int signal_init_action(int nargs, char **args)
|
||||
{
|
||||
signal_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_startup_action(int nargs, char **args)
|
||||
{
|
||||
/* make sure we actually have all the pieces we need */
|
||||
if ((get_device_fd() < 0) ||
|
||||
(get_property_set_fd() < 0) ||
|
||||
(get_signal_fd() < 0)) {
|
||||
ERROR("init startup failure\n");
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int queue_property_triggers_action(int nargs, char **args)
|
||||
{
|
||||
queue_all_property_triggers();
|
||||
/* enable property triggers */
|
||||
property_triggers_enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BOOTCHART
|
||||
static int bootchart_init_action(int nargs, char **args)
|
||||
{
|
||||
bootchart_count = bootchart_init();
|
||||
if (bootchart_count < 0) {
|
||||
ERROR("bootcharting init failure\n");
|
||||
} else if (bootchart_count > 0) {
|
||||
NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd_count;
|
||||
int s[2];
|
||||
int fd;
|
||||
struct sigaction act;
|
||||
char tmp[PROP_VALUE_MAX];
|
||||
int fd_count = 0;
|
||||
struct pollfd ufds[4];
|
||||
char *tmpdev;
|
||||
char* debuggable;
|
||||
char tmp[32];
|
||||
int device_fd_init = 0;
|
||||
int property_set_fd_init = 0;
|
||||
int signal_fd_init = 0;
|
||||
int keychord_fd_init = 0;
|
||||
|
||||
/* clear the umask */
|
||||
umask(0);
|
||||
|
@ -582,149 +754,79 @@ int main(int argc, char **argv)
|
|||
parse_config_file(tmp);
|
||||
|
||||
action_for_each_trigger("early-init", action_add_queue_tail);
|
||||
drain_action_queue();
|
||||
|
||||
INFO("device init\n");
|
||||
device_init();
|
||||
|
||||
property_init();
|
||||
|
||||
// only listen for keychords if ro.debuggable is true
|
||||
keychord_init();
|
||||
|
||||
if (console[0]) {
|
||||
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
|
||||
console_name = strdup(tmp);
|
||||
}
|
||||
|
||||
fd = open(console_name, O_RDWR);
|
||||
if (fd >= 0)
|
||||
have_console = 1;
|
||||
close(fd);
|
||||
|
||||
if( load_565rle_image(INIT_IMAGE_FILE) ) {
|
||||
fd = open("/dev/tty0", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
const char *msg;
|
||||
msg = "\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n" // console is 40 cols x 30 lines
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" A N D R O I D ";
|
||||
write(fd, msg, strlen(msg));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (qemu[0])
|
||||
import_kernel_cmdline(1);
|
||||
|
||||
if (!strcmp(bootmode,"factory"))
|
||||
property_set("ro.factorytest", "1");
|
||||
else if (!strcmp(bootmode,"factory2"))
|
||||
property_set("ro.factorytest", "2");
|
||||
else
|
||||
property_set("ro.factorytest", "0");
|
||||
|
||||
property_set("ro.serialno", serialno[0] ? serialno : "");
|
||||
property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
|
||||
property_set("ro.baseband", baseband[0] ? baseband : "unknown");
|
||||
property_set("ro.carrier", carrier[0] ? carrier : "unknown");
|
||||
property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
|
||||
|
||||
property_set("ro.hardware", hardware);
|
||||
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
|
||||
property_set("ro.revision", tmp);
|
||||
queue_builtin_action(device_init_action, "device_init");
|
||||
queue_builtin_action(property_init_action, "property_init");
|
||||
queue_builtin_action(keychord_init_action, "keychord_init");
|
||||
queue_builtin_action(console_init_action, "console_init");
|
||||
queue_builtin_action(set_init_properties_action, "set_init_properties");
|
||||
|
||||
/* execute all the boot actions to get us started */
|
||||
action_for_each_trigger("init", action_add_queue_tail);
|
||||
action_for_each_trigger("early-fs", action_add_queue_tail);
|
||||
action_for_each_trigger("fs", action_add_queue_tail);
|
||||
action_for_each_trigger("post-fs", action_add_queue_tail);
|
||||
drain_action_queue();
|
||||
|
||||
/* read any property files on system or data and
|
||||
* fire up the property service. This must happen
|
||||
* after the ro.foo properties are set above so
|
||||
* that /data/local.prop cannot interfere with them.
|
||||
*/
|
||||
start_property_service();
|
||||
|
||||
signal_init();
|
||||
|
||||
/* make sure we actually have all the pieces we need */
|
||||
if ((get_device_fd() < 0) ||
|
||||
(get_property_set_fd() < 0) ||
|
||||
(get_signal_fd() < 0)) {
|
||||
ERROR("init startup failure\n");
|
||||
return 1;
|
||||
}
|
||||
queue_builtin_action(property_service_init_action, "property_service_init");
|
||||
queue_builtin_action(signal_init_action, "signal_init");
|
||||
queue_builtin_action(check_startup_action, "check_startup");
|
||||
|
||||
/* execute all the boot actions to get us started */
|
||||
action_for_each_trigger("early-boot", action_add_queue_tail);
|
||||
action_for_each_trigger("boot", action_add_queue_tail);
|
||||
drain_action_queue();
|
||||
|
||||
/* run all property triggers based on current state of the properties */
|
||||
queue_all_property_triggers();
|
||||
drain_action_queue();
|
||||
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
|
||||
|
||||
/* enable property triggers */
|
||||
property_triggers_enabled = 1;
|
||||
|
||||
ufds[0].fd = get_device_fd();
|
||||
ufds[0].events = POLLIN;
|
||||
ufds[1].fd = get_property_set_fd();
|
||||
ufds[1].events = POLLIN;
|
||||
ufds[2].fd = get_signal_fd();
|
||||
ufds[2].events = POLLIN;
|
||||
fd_count = 3;
|
||||
|
||||
if (get_keychord_fd() > 0) {
|
||||
ufds[3].fd = get_keychord_fd();
|
||||
ufds[3].events = POLLIN;
|
||||
fd_count++;
|
||||
} else {
|
||||
ufds[3].events = 0;
|
||||
ufds[3].revents = 0;
|
||||
}
|
||||
|
||||
#if BOOTCHART
|
||||
bootchart_count = bootchart_init();
|
||||
if (bootchart_count < 0) {
|
||||
ERROR("bootcharting init failure\n");
|
||||
} else if (bootchart_count > 0) {
|
||||
NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
queue_builtin_action(bootchart_init_action, "bootchart_init");
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
int nr, i, timeout = -1;
|
||||
|
||||
for (i = 0; i < fd_count; i++)
|
||||
ufds[i].revents = 0;
|
||||
|
||||
drain_action_queue();
|
||||
execute_one_command();
|
||||
restart_processes();
|
||||
|
||||
if (!device_fd_init && get_device_fd() > 0) {
|
||||
ufds[fd_count].fd = get_device_fd();
|
||||
ufds[fd_count].events = POLLIN;
|
||||
ufds[fd_count].revents = 0;
|
||||
fd_count++;
|
||||
device_fd_init = 1;
|
||||
}
|
||||
if (!property_set_fd_init && get_property_set_fd() > 0) {
|
||||
ufds[fd_count].fd = get_property_set_fd();
|
||||
ufds[fd_count].events = POLLIN;
|
||||
ufds[fd_count].revents = 0;
|
||||
fd_count++;
|
||||
property_set_fd_init = 1;
|
||||
}
|
||||
if (!signal_fd_init && get_signal_fd() > 0) {
|
||||
ufds[fd_count].fd = get_signal_fd();
|
||||
ufds[fd_count].events = POLLIN;
|
||||
ufds[fd_count].revents = 0;
|
||||
fd_count++;
|
||||
signal_fd_init = 1;
|
||||
}
|
||||
if (!keychord_fd_init && get_keychord_fd() > 0) {
|
||||
ufds[fd_count].fd = get_keychord_fd();
|
||||
ufds[fd_count].events = POLLIN;
|
||||
ufds[fd_count].revents = 0;
|
||||
fd_count++;
|
||||
keychord_fd_init = 1;
|
||||
}
|
||||
|
||||
if (process_needs_restart) {
|
||||
timeout = (process_needs_restart - gettime()) * 1000;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
if (!action_queue_empty() || cur_command)
|
||||
timeout = 0;
|
||||
|
||||
#if BOOTCHART
|
||||
if (bootchart_count > 0) {
|
||||
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
|
||||
|
@ -735,22 +837,23 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nr = poll(ufds, fd_count, timeout);
|
||||
if (nr <= 0)
|
||||
continue;
|
||||
|
||||
if (ufds[2].revents == POLLIN) {
|
||||
handle_signal();
|
||||
continue;
|
||||
for (i = 0; i < fd_count; i++) {
|
||||
if (ufds[i].revents == POLLIN) {
|
||||
if (ufds[i].fd == get_device_fd())
|
||||
handle_device_fd();
|
||||
else if (ufds[i].fd == get_property_set_fd())
|
||||
handle_property_set_fd();
|
||||
else if (ufds[i].fd == get_keychord_fd())
|
||||
handle_keychord();
|
||||
else if (ufds[i].fd == get_signal_fd())
|
||||
handle_signal();
|
||||
}
|
||||
}
|
||||
|
||||
if (ufds[0].revents == POLLIN)
|
||||
handle_device_fd();
|
||||
|
||||
if (ufds[1].revents == POLLIN)
|
||||
handle_property_set_fd();
|
||||
if (ufds[3].revents == POLLIN)
|
||||
handle_keychord();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -109,6 +109,8 @@ struct svcenvinfo {
|
|||
|
||||
#define SVC_MAXARGS 64
|
||||
|
||||
#define COMMAND_RETRY_TIMEOUT 5
|
||||
|
||||
struct service {
|
||||
/* list of all services */
|
||||
struct listnode slist;
|
||||
|
|
|
@ -562,6 +562,24 @@ void queue_all_property_triggers()
|
|||
}
|
||||
}
|
||||
|
||||
void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
|
||||
{
|
||||
struct action *act;
|
||||
struct command *cmd;
|
||||
|
||||
act = calloc(1, sizeof(*act));
|
||||
act->name = name;
|
||||
list_init(&act->commands);
|
||||
|
||||
cmd = calloc(1, sizeof(*cmd));
|
||||
cmd->func = func;
|
||||
cmd->args[0] = name;
|
||||
list_add_tail(&act->commands, &cmd->clist);
|
||||
|
||||
list_add_tail(&action_list, &act->alist);
|
||||
action_add_queue_tail(act);
|
||||
}
|
||||
|
||||
void action_add_queue_tail(struct action *act)
|
||||
{
|
||||
list_add_tail(&action_queue, &act->qlist);
|
||||
|
@ -579,6 +597,11 @@ struct action *action_remove_queue_head(void)
|
|||
}
|
||||
}
|
||||
|
||||
int action_queue_empty()
|
||||
{
|
||||
return list_empty(&action_queue);
|
||||
}
|
||||
|
||||
static void *parse_service(struct parse_state *state, int nargs, char **args)
|
||||
{
|
||||
struct service *svc;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
struct action;
|
||||
|
||||
void drain_action_queue(void);
|
||||
struct action *action_remove_queue_head(void);
|
||||
void action_add_queue_tail(struct action *act);
|
||||
void action_for_each_trigger(const char *trigger,
|
||||
|
@ -27,5 +26,6 @@ void action_for_each_trigger(const char *trigger,
|
|||
int action_queue_empty(void);
|
||||
void queue_property_triggers(const char *name, const char *value);
|
||||
void queue_all_property_triggers();
|
||||
void queue_builtin_action(int (*func)(int nargs, char **args), char *name);
|
||||
|
||||
#endif /* PARSER_H_ */
|
||||
|
|
Loading…
Reference in New Issue