2121#include < sys/wait.h>
2222#include < fcntl.h>
2323#include < stdio.h>
24+ #include < errno.h>
25+ #include < time.h>
26+
27+ #ifdef DEBUG
28+ #include < android/log.h>
29+ #define LOG (...) ((void )__android_log_print(ANDROID_LOG_DEBUG, " libdaemonize" , __VA_ARGS__))
30+ #else
31+ #define LOG (...) ((void )0 )
32+ #endif
33+
34+ int sleep_ms (int ms) {
35+ struct timespec ts;
36+ ts.tv_sec = ms / 1000 ;
37+ ts.tv_nsec = (ms % 1000 ) * 1000000 ;
38+ if ((nanosleep (&ts,&ts) == -1 ) && (errno == EINTR)) {
39+ int ret = (ts.tv_sec * 1000 ) + (ts.tv_nsec / 1000000 );
40+ if (ret < 1 ) ret = 1 ;
41+ return ret;
42+ }
43+ return 0 ;
44+ }
2445
2546/* Proper daemonization includes forking, closing the current STDIN/STDOUT/STDERR, creating a new
2647 * session, and forking again, making sure the twice-forked process becomes a child of init (1) */
2748static int fork_daemon (int returnParent) {
2849 pid_t child = fork ();
29- if (child == 0 ) {
50+ if (child == 0 ) { // 1st child
3051 close (STDIN_FILENO);
3152 close (STDOUT_FILENO);
3253 close (STDERR_FILENO);
@@ -39,21 +60,46 @@ static int fork_daemon(int returnParent) {
3960
4061 setsid ();
4162 pid_t child2 = fork ();
42- if (child2 <= 0 ) return 0 ; // success child or error on 2nd fork
43- exit (EXIT_SUCCESS);
63+ if (child2 == 0 ) { // 2nd child
64+ return 0 ; // return execution to caller
65+ } else if (child2 > 0 ) { // 1st child, fork ok
66+ exit (EXIT_SUCCESS);
67+ } else if (child2 < 0 ) { // 1st child, fork fail
68+ LOG (" 2nd fork failed (%d)" , errno);
69+ exit (EXIT_FAILURE);
70+ }
71+ }
72+
73+ // parent
74+ if (child < 0 ) {
75+ LOG (" 1st fork failed (%d)" , errno);
76+ return -1 ; // error on 1st fork
77+ }
78+ while (true ) {
79+ int status;
80+ pid_t waited = waitpid (child, &status, 0 );
81+ if ((waited == child) && WIFEXITED (status)) {
82+ break ;
83+ }
4484 }
45- if (child < 0 ) return -1 ; // error on 1st fork
46- int status;
47- waitpid (child, &status, 0 );
4885 if (!returnParent) exit (EXIT_SUCCESS);
4986 return 1 ; // success parent
5087}
5188
5289extern " C" {
5390
5491int main (int argc, char *argv[], char ** envp) {
55- if (fork_daemon (0 ) == 0 ) {
56- execv (argv[1 ], &argv[1 ]);
92+ if (fork_daemon (0 ) == 0 ) { // daemonized child
93+ // On some devices in the early boot stages, execv will fail with EACCESS, cause unknown.
94+ // Retrying a couple of times seems to work. Most-seen required attempts is three.
95+ // That retrying works implies some sort of race-condition, possibly SELinux related.
96+ for (int i = 0 ; i < 16 ; i++) {
97+ execv (argv[1 ], &argv[1 ]); // never returns if successful
98+ LOG (" [%d] execv(%s, ...)-->%d" , i, argv[1 ], errno);
99+ sleep_ms (16 );
100+ }
101+ LOG (" too many failures, aborting" );
102+ exit (EXIT_FAILURE);
57103 }
58104}
59105
0 commit comments