Working with cron for Android and adding a shell script to autorun when the device boots





Due to the fact that mobile devices have long had extensive functionality, automation tasks can be easily transferred to them. And, as well as possible, cron is just as good for executing them. But if cron takes a little time in "regular" Linux systems, then an Android device requires more complicated work to configure it.



If you are interested in the topic of automation and you want your shell scripts to run immediately after the device boots up, and even could start on a timer - welcome to the cat!



Foreword



I am engaged in the automation of mobile devices for Android. And during the execution of automatic scripts, many unforeseen situations occur, even if the same devices are used for testing.



Most popular problems:



0. The automation script does not do what you wanted.

1. The mobile application is automatically downloaded

2. Automatic reboot of the phone

3. The mobile application does not automatically start after a restart

4. The Wi-Fi module randomly turns off, does not find the network, does not connect to the network

5. Mobile network suddenly disappeared

6. The phone went into sleep mode

7. The proxy dropped or the server itself or the server returned a strange response



Because of this, you have to constantly monitor the device and catch these unforeseen situations.







Thus, I came to the conclusion that cron with the "correct" scripts will allow you to track software failures and restore the automation script or run it again. But as it turned out, although Android contains the Linux kernel, there are special nuances that I had to deal with. So let's get started on setting up!



Cron setup



Customize the environment



  1. Install adb to access the device through the shell using a usb wire.
  2. We open the section For developers . To do this, go to the About phone section and make a few clicks on the Build number or something similar.
  3. We go to the section For developers and turn it on. We connect the device to the computer and allow access on this computer to this device.
  4. Add root for your device. The most common options are SuperSu , Magisk, and Kingroot . Go to w3bsit3-dns.com and find the root option for your device. Unfortunately, there is no universal root.
  5. We install BusyBox (it is also on w3bsit3-dns.com, for example), since it just contains a cron program.


Manual start setting



  1. We connect to the phone using adb shell (if adb is not registered in your environment variable, then add the full path.
  2. Go to root mode with the su command
  3. We check the presence of the cron program and see the settings using the crond -h command


execution result
crond: invalid option -- h BusyBox v1.29.2-Stericson (2018-08-12 11:19:12 EDT) multi-call binary. Usage: crond -fbS -l N -d N -L LOGFILE -c DIR -f Foreground -b Background (default) -S Log to syslog (default) -l N Set log level. Most verbose 0, default 8 -d N Set log level, log to stderr -L FILE Log to FILE -c DIR Cron dir. Default:/var/spool/cron/crontabs
      
      







As you can see from the last line, the default instructions should be stored in the directory / var / spool / cron / crontabs , which is not automatically created and if we run the command
 crond -b
      
      



and then check if the process started through
 ps | grep crond
      
      



, then it may not be there, because he could not get any instructions. So let's execute the command
 crond -b -fd0
      
      



and see what is the reason. Most likely you will have a similar error:

crond: can't change directory to '/var/spool/cron/crontabs': No such file or directory



. In this case, this is normal, because in the future, we ourselves will indicate the path to the crontab executable file.



4. Create a simple crontab file:



 mkdir /data/crontab echo "*/1 * * * * echo 'text' >> /sdcard/test.txt" > /data/crontab/root
      
      





Now we have a task that will add the word text every minute to the /sdcard/test.txt file

We launch:
 crond -b -fd0 -c /data/crontab
      
      



and get the following log:



 crond: crond (busybox 1.29.2-Stericson) started, log level 0 crond: ignoring file 'root' (no such user) ...
      
      





Of course, it is a little surprising, because if we execute the whoami command, then as a result it will return root .



5. Add the root user, since crond asks:



 mount -o remount,rw /system; echo "root:x:0:0::/system/etc/crontabs:/system/bin/sh" >> /system/etc/passwd; mount -o remount,ro /system;
      
      





Due to the lack of this file, I realized that in the Android system it is not involved at all. If you are sure where you will store your crontab files, then you can replace the line / system / etc / crontabs with the one you need. Run the command again



 crond -b -fd0 -c /data/crontab
      
      





And we get the following:



 crond: user:root entry:*/1 * * * * echo 'text' >> /sdcard/test.txt 111111111111111111111111111111111111111111111111111111111111 111111111111111111111111 11111111111111111111111111111111 111111111111 1111111 crond: wakeup dt=16 crond: file root: crond: line echo 'text' >> /sdcard/test.txt crond: job: 0 echo 'text' >> /sdcard/test.txt crond: can't change directory to '/system/etc/crontabs' crond: can't change directory to '/var/spool/cron': No such file or directory crond: USER root pid 12849 cmd echo 'text' >> /sdcard/test.txt
      
      





Although, according to the log, the task was registered in crond, but in my case the file was not created. The problem can be solved very simply:



 mkdir -p /system/etc/crontabs
      
      





Well, he wants a directory to exist there, who are we to forbid him! We start again and see:



 crond: user:root entry:*/1 * * * * echo 'text' >> /sdcard/test.txt 111111111111111111111111111111111111111111111111111111111111 111111111111111111111111 11111111111111111111111111111111 111111111111 1111111 crond: wakeup dt=12 crond: file root: crond: line echo 'text' >> /sdcard/test.txt crond: job: 0 echo 'text' >> /sdcard/test.txt crond: child running /system/bin/sh crond: USER root pid 13033 cmd echo 'text' >> /sdcard/test.txt
      
      





The errors went away and the line crond: child running / system / bin / sh appeared . Finally, cron has been successfully wound up, and you can move on to the second part!



Automatic shell script loading



The Linux system has an init.d directory that is responsible for autostart immediately after the system boots, so let's try this way!



1. Check if this directory exists on your device (this is /etc/init.d or /system/etc/init.d - this is the same mounted partition etc). In my case, it is not. Well, then create:



 mount -o remount,rw /system mkdir /system/etc/init.d chmod 0755 /system/etc/init.d mount -o remount,ro /system
      
      





Now add some simple script there, for example:



 echo "echo 'Init.d is working !!!' >> /sdcard/init_test.log" > /system/etc/init.d/90my_script chmod 777 /system/etc/init.d/90my_script
      
      





We reboot the device and see if a miracle happened ... Unfortunately, my file did not appear.



We examine the system further and look for some init file that can run scripts after launch. I had a file in /init.rc on my device. Well, let's try changing it and rebooting the device:



 mount -o remount,rw / echo "echo 'Init.d is working !!!' >> /sdcard/init_test.log" >> /init.rc mount -o remount,ro / reboot
      
      





But the file was not created again. We go to look at the /init.rc file and our record disappeared and the file did not seem to change, because the creation date is quite strange (in my case, Jan 1, 70 05:00:00).



We continue to understand, and it turns out that this file is stored in boot.img , and each time it gets from it. And in order to change the functionality of the init.rc file, you need to do all this .



But there is an easier way to help solve this problem. For this method, we can use the following shell script (say thanks to Ryuinferno):



Shell script
 #!/system/bin/sh #Script to enable init.d by Ryuinferno @ XDA error_msg(){ echo "You do not need this mod..." sleep 1 echo "If you are reapplying, please delete these files if present:" echo "/system/bin/sysinit" sleep 1 echo "/system/etc/install-recovery.sh" sleep 1 echo "/system/etc/install-recovery-2.sh" sleep 1 echo "And run again..." sleep 1 echo "If init.d is still not working, read the FAQ part in my thread..." sleep 1 echo "Aborting..." mount -o remount,ro -t auto /system echo "" echo "Ryuinferno @ XDA" exit 1 } echo "Init.d Enabler by Ryuinferno @ XDA" echo "" sleep 1 id=`id`; id=`echo ${id#*=}`; id=`echo ${id%%\(*}`; id=`echo ${id%% *}` if [ "$id" != "0" ] && [ "$id" != "root" ]; then echo "Script NOT running as root!" sleep 1 echo "Superuser access not granted!" sleep 1 echo "Please type 'su' first before running this script..." exit 1 else echo "Hello Supaa User! :P" echo "" sleep 1 fi if [ ! "'which busybox'" ]; then echo "busybox NOT INSTALLED!" sleep 1 echo "Please install busybox first!" exit 1 else echo "busybox found!" sleep 1 fi bbb=0 if [ ! "`which grep`" ]; then bbb=1 echo "grep applet NOT FOUND!" sleep 1 else echo "Awesome! grep found! :D" sleep 1 fi if [ ! "`which run-parts`" ]; then bbb=1 echo "run-parts applet NOT FOUND!" sleep 1 else echo "Good! run-parts found! :)" echo "" sleep 1 fi if [ $bbb -eq 1 ] ; then echo "" echo "Required applets are NOT FOUND!" echo "" sleep 1 echo "Please reinstall busybox!" exit 1 fi echo "Great! Let's proceed..." echo "" sleep 1 echo "Press enter to continue..." read enterKey clear sleep 1 echo "Mounting system as rewritable..." mount -o remount,rw -t auto /system sleep 1 echo "Removing old sysinit file" rm /system/bin/sysinit sleep 1 echo "" echo "Checking for the presence of sysinit in /system/bin..." sleep 1 if [ -e /system/bin/sysinit ]; then echo "sysinit found..." if [ -z "`cat /system/bin/sysinit | grep "init.d"`" ]; then echo "Adding lines to sysinit..." echo "" >> /system/bin/sysinit echo "# init.d support" >> /system/bin/sysinit echo "" >> /system/bin/sysinit echo "export PATH=/sbin:/system/sbin:/system/bin:/system/xbin" >> /system/bin/sysinit echo "run-parts /system/etc/init.d" >> /system/bin/sysinit echo "" >> /system/bin/sysinit else echo "" echo "Your sysinit should already be running the scripts in init.d folder at boot..." error_msg fi else echo "sysinit not found, creating file..." echo "#!/system/bin/sh" > /system/bin/sysinit echo "# init.d support" >> /system/bin/sysinit echo "" >> /system/bin/sysinit echo "export PATH=/sbin:/system/sbin:/system/bin:/system/xbin" >> /system/bin/sysinit echo "run-parts /system/etc/init.d" >> /system/bin/sysinit echo "" >> /system/bin/sysinit fi sleep 1 echo "Setting correct permissions and ownership for sysinit..." chmod 755 /system/bin/sysinit chown 0.2000 /system/bin/sysinit sleep 1 echo "" echo "Checking for the presence of install-recovery.sh..." sleep 1 if [ -f /system/etc/install-recovery.sh ] && [ -z "`cat /system/etc/install-recovery.sh | grep "daemon"`" ]; then if [ ! -z "`cat /system/etc/install-recovery.sh | grep "init.d"`" ];then echo "Your install-recovery.sh seems to be already modified for init.d..." error_msg fi echo "install-recovery.sh found, renaming it as install-recovery-2.sh..." mv /system/etc/install-recovery.sh /system/etc/install-recovery-2.sh echo "Recreating install-recovery.sh..." echo "#!/system/bin/sh" > /system/etc/install-recovery.sh echo "# init.d support" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh echo "/system/bin/sysinit" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh echo "# excecuting extra commands" >> /system/etc/install-recovery.sh echo "/system/etc/install-recovery-2.sh" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh elif [ -f /system/etc/install-recovery.sh ] && [ ! -z "`cat /system/etc/install-recovery.sh | grep "daemon"`" ]; then if [ -f /system/etc/install-recovery-2.sh ] && [ ! -z "`cat /system/etc/install-recovery-2.sh | grep "init.d"`" ];then echo "Your install-recovery-2.sh seems to be already modified for init.d..." error_msg fi echo "install-recovery.sh is used for superuser, using install-recovery-2.sh instead..." if [ -f /system/etc/install-recovery-2.sh ]; then echo "" >> /system/etc/install-recovery-2.sh echo "# init.d support" >> /system/etc/install-recovery-2.sh echo "/system/bin/sysinit" >> /system/etc/install-recovery-2.sh echo "" >> /system/etc/install-recovery-2.sh else echo "#!/system/bin/sh" > /system/etc/install-recovery-2.sh echo "# init.d support" >> /system/etc/install-recovery-2.sh echo "" >> /system/etc/install-recovery-2.sh echo "/system/bin/sysinit" >> /system/etc/install-recovery-2.sh echo "" >> /system/etc/install-recovery-2.sh fi if [ -z "`cat /system/etc/install-recovery.sh | grep "install-recovery-2.sh"`" ]; then echo "" >> /system/etc/install-recovery.sh echo "# extra commands" >> /system/etc/install-recovery.sh echo "/system/etc/install-recovery-2.sh" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh fi else echo "install-recovery.sh not found, creating it..." echo "#!/system/bin/sh" > /system/etc/install-recovery.sh echo "# init.d support" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh echo "/system/bin/sysinit" >> /system/etc/install-recovery.sh echo "" >> /system/etc/install-recovery.sh fi sleep 1 echo "Setting the correct permissions and ownership for install-recovery.sh..." echo "Also for install-recovery-2.sh if it exists..." chmod 755 /system/etc/install-recovery.sh chown 0.0 /system/etc/install-recovery.sh if [ -f /system/etc/install-recovery-2.sh ]; then chmod 755 /system/etc/install-recovery-2.sh chown 0.0 /system/etc/install-recovery-2.sh fi sleep 1 echo "" echo "Checking for the presence of the init.d folder..." sleep 1 if [ -d /system/etc/init.d ]; then echo "init.d folder found..." else echo "init.d folder not found, creating the folder..." mkdir /system/etc/init.d fi sleep 1 echo "" echo "Creating basic init.d scripts..." echo "#!/system/bin/sh" > /system/etc/init.d/08setperm echo "#set correct permissions to /system/etc/init.d folder" >> /system/etc/init.d/08setperm echo "" >> /system/etc/init.d/08setperm echo "mount -o remount,rw -t auto /system" >> /system/etc/init.d/08setperm echo "chmod -R 777 /system/etc/init.d" >> /system/etc/init.d/08setperm echo "mount -o remount,ro -t auto /system" >> /system/etc/init.d/08setperm echo "" >> /system/etc/init.d/08setperm echo "#!/system/bin/sh" > /system/etc/init.d/00test echo "#init.d test" >> /system/etc/init.d/00test echo "" >> /system/etc/init.d/00test echo "if [ -f /data/Test.log ]; then" >> /system/etc/init.d/00test echo "rm /data/Test.log" >> /system/etc/init.d/00test echo "fi" >> /system/etc/init.d/00test echo "" >> /system/etc/init.d/00test echo 'echo "Init.d is working !!!" >> /data/Test.log' >> /system/etc/init.d/00test echo 'echo "excecuted on $(date +"%d-%m-%Y %r" )" >> /data/Test.log' >> /system/etc/init.d/00test echo "" >> /system/etc/init.d/00test sleep 1 echo "Creating permissive SELinux script..." sleep 1 echo "#!/system/bin/sh" >> /system/etc/init.d/01permissive echo "#Init.d Permissive SELinux" >> /system/etc/init.d/01permissive echo "" >> /system/etc/init.d/01permissive echo "busybox mount -o remount,rw -t auto /system" >> /system/etc/init.d/01permissive echo "" >> /system/etc/init.d/01permissive echo "setenforce 0" >> /system/etc/init.d/01permissive echo "SELINUX=permissive" >> /system/etc/init.d/01permissive echo "" >> /system/etc/init.d/01permissive sleep 1 echo "Setting correct permissions and ownership for init.d folder and scipts..." chmod 777 /system/etc/init.d chmod 777 /system/etc/init.d/08setperm chmod 777 /system/etc/init.d/00test chmod 777 /system/etc/init.d/01permissive chown 0.0 /system/etc/init.d chown 0.0 /system/etc/init.d/08setperm chown 0.0 /system/etc/init.d/00test chown 0.0 /system/etc/init.d/01permissive sleep 1 echo "" echo "Mounting system as read-only..." mount -o remount,ro -t auto /system sleep 1 echo "" echo "Done!!!" sleep 1 echo "Please reboot at least twice before checking /data..." sleep 1 echo "If init.d is working, you will see a Test.log in /data..." sleep 1 echo "" echo "Enjoy!!! =)" echo "Ryuinferno @ XDA 2013" exit
      
      







Getting started with the script! In my case, it will be called init.sh.

1. Download the file to the sdcard of the mobile device:

 adb push /tmp/init.sh /sdcard
      
      





2. Copy to the memory of the mobile device and set the necessary rights:

 adb shell su cp /sdcard/init.sh /data/init.sh chmod 777 /data/init.sh
      
      





3. Run for execution:

 /data/init.sh
      
      





And pay attention to the log, which is displayed. Here is my log:

Run log
 Init.d Enabler by Ryuinferno @ XDA Hello Supaa User! :P busybox found! Awesome! grep found! :D Good! run-parts found! :) Great! Let's proceed... Press enter to continue... Mounting system as rewritable... Removing old sysinit file rm: /system/bin/sysinit: No such file or directory Checking for the presence of sysinit in /system/bin... sysinit not found, creating file... Setting correct permissions and ownership for sysinit... Checking for the presence of install-recovery.sh... install-recovery.sh not found, creating it... Setting the correct permissions and ownership for install-recovery.sh... Also for install-recovery-2.sh if it exists... Checking for the presence of the init.d folder... init.d folder found... Creating basic init.d scripts... Creating permissive SELinux script... Setting correct permissions and ownership for init.d folder and scipts... Mounting system as read-only... Done!!! Please reboot at least twice before checking /data... If init.d is working, you will see a Test.log in /data... Enjoy!!! =) Ryuinferno @ XDA 2013
      
      







As you can see from the log, there are no errors, so feel free to reboot the device! Maybe someone already worked and you could find the /data/Test.log file, but I don’t have it. Check the directory /system/etc/init.d using the ls command :



 00test 01permissive 08setperm
      
      





As you can see, the tasks have been successfully created. You may still have to change boot.img , but let's check at the beginning, where is the install-recovery.sh file with the command



 find / -name "install-recovery.sh" ... /system/bin/install-recovery.sh /system/etc/install-recovery.sh ...
      
      





As we can see, we have 2 files that lie in different places. By the date of creation, we can notice that the script created the file in the directory /system/etc/install-recovery.sh , although, perhaps, in some cases it should create it in / system / etc. Let's rename the file to bin and copy the file from etc:



 mount -o remount,rw /system mv /install-recovery.sh /system/bin/install-recovery2.sh cp /install-recovery.sh /system/bin/
      
      





And again we reboot the device ... And now, finally, the long-awaited SUCCESS! The file /data/Test.log has appeared!



Once everything works, go to /system/etc/init.d and create a shell script. And in it, just run our crond to execute:



 echo "#!/system/bin/sh crond -b -L /sdcard/error.log -c /data/crontab" > /system/etc/init.d/99cronstart chmod 777 /system/etc/init.d/99cronstart reboot
      
      





After downloading, check if crond has started:



 ps | grep crond root 414 1 9532 236 hrtimer_na 000dcf90 S crond
      
      





And we could finish it already, but let's wait a minute and see if there was a record in our file ... Well, as you already understood, again, nothing worked. The fact is that this process needs to be launched from a super user. Change the script in the 99cronstart file:



 echo "#!/system/bin/sh su -c crond -b -L /sdcard/error.log -c /data/crontab" > /system/etc/init.d/99cronstart reboot
      
      





Now our Android device supports cron tasks and may contain shell scripts for automatic launch!



And finally, a script that will run our application if it is not in the processes and save information about what was on the main screen before launching our application:



 proc=$(ps | grep "com.test.app") if [ "$proc" == "" ]; then dumpsys window | grep CurrentFocus > /sdcard/current_focus.dump sleep 1 am start -n com.test.app/com.test.app.activities.MainActivity fi
      
      






All Articles