CAT S60 boot loop fix (#P17F1)

Good fucking Lord, that was a ride.
Last Sunday, my phone went out of juice and failed to come back to life. I had some issues with VERY high standby power consumption the entire week before, which caused the 3.8Ah battery to go flat within a work day. And so it did on Sunday when nobody was using it and nobody cared.

Long story short: A friggen weather app created an invalid (cron?) job, which caused the OS to reset indefinitely.

Long version: Boys and girls, root your phones. Even if some idiot banks (1822direkt, *cough*) will block you from running their apps “for security reasons”, having the option to fully backup and restore your phone outweighs that by far.

As ranted previously, I did change my phone not too long ago, so in addition to having the backup from back then, I was also able to make a full backup of the faulty system. And to reset it, and to do other backup and restore tasks in my six day journey of making the damn thing work again without data loss.

Now, for Android phones there’s a safe mode that can usually be selected by some power and volume key combination on power-on. Apparently that doesn’t work with the S60, because why should it, this thing only has 4 function keys, three navigation buttons and a hidden SOS button. Eight hardware buttons in a world of touchy-touch button phones. Jeez.

From a minimal clean installation, I ran two tests, did backups and reverted to the original state. One doing nothing but a clean shutdown, one activating the safe mode from the power-off menu (a little bit like Start -> Shutdown in Windows). Turns out it’s as simple as creating /data/property/persist.sys.safemode with file content “1”, and the phone will boot in safe mode next time. Now that I know this it’s easy to find on the web, but I didn’t manage to do that before. Besides, the usual way of doing that over USB via adb shell su -c 'echo "1" > /data/property/persist.sys.safemode' wouldn’t work for me, as it never got to the point where ADB would be available. Without root, it’d be rather difficult to do that. Second issue: That didn’t fix my problem…

So my second guess was that this was caused by a recent update. Again, I had power consumption issues before, so the last full reboot wasn’t that long ago, and I only install updates manually. Yet wiping the apps (via time stamps from the backup of the faulty state) didn’t change anything, wiping their data didn’t, and doing both was just more pain in the butt as I had to do this via the TWRP recovery terminal. This confirmed that this issue was not caused by an app update although the very last thing that showed before rebooting was some app optimization notification. It had to be on the system level.

Finally I took the time on a day off (for a shared work phone! Idiot me…) to run smaller batches of recovery. TWRP does allow for recovery of single partitions like system, data or EFS from a full backup, but that was too coarse. My system went into boot loop when restoring the data partition – a chunk of roughly 8GB. TWRP backups are just tar files (called “data.ext4.win000” and so on, though), so this is pretty convenient. Restoring the first three of those independent 1.5GB files did work as expected, as this just restored APK, ODEX and some other binary-related files that I ruled out before. The fourth one contained some more data from elsewhere, mostly the /data/data directory, which also turned out to be fine. And the fifth one was a convenient 400MB in size and actually caused the boot loop after restore. Which, I should mention, is done via the terminal again, just running tar -xvf [file] while being in the root directory. tar on Android does not care about the recording of the absolute path that TWRP does, and ark on my main machine totally craps itself, so I needed to perform any changes to the archive on a Windows machine with 7zip. WinRAR also has some issues with it…

A couple of tries later I was down to /data/system* causing the loop, and I found that there’s helpful log files inside of /data/system/dropbox/. “Dropbox”, WHY? Totally ignored that folder because I do not use it and the phone does not have the app installed. Yet there’s logs in there that everybody on the interwebs says aren’t there, one needs to run ADB logcat – which didn’t friggen work for me. So aside from “system_app_wtf@41348.txt” files that log in nice 30min increments that some system phone app dies pretty frequently, there’s also files like “system_server_crash@536041.txt”. That one says the following:

Process: system_server
Build: Cat/CatS60/CatS60:6.0.1/MMB29M/LTE_D0201121.0_S60_0.038.00:user/release-keys

java.lang.RuntimeException: Failed to create service com.android.server.job.JobSchedulerService: service constructor threw an exception
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:100)
at com.android.server.SystemServer.startOtherServices(SystemServer.java:897)
at com.android.server.SystemServer.run(SystemServer.java:272)
at com.android.server.SystemServer.main(SystemServer.java:170)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance(Native Method)
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:89)
... 6 more
Caused by: java.lang.IllegalArgumentException: You're trying to build a job with no constraints, this is not allowed.
at android.app.job.JobInfo$Builder.build(JobInfo.java:451)
at com.android.server.job.JobStore$ReadJobMapFromDiskRunnable.restoreJobFromXml(JobStore.java:638)
at com.android.server.job.JobStore$ReadJobMapFromDiskRunnable.readJobMapImpl(JobStore.java:491)
at com.android.server.job.JobStore$ReadJobMapFromDiskRunnable.run(JobStore.java:429)
at com.android.server.job.JobStore.readJobMapFromDisk(JobStore.java:265)
at com.android.server.job.JobStore.(JobStore.java:117)
at com.android.server.job.JobStore.initAndGet(JobStore.java:86)
at com.android.server.job.JobSchedulerService.(JobSchedulerService.java:325)
... 8 more

Okay, I do hate Java error messages, but there seems to be something wrong with “jobs”, as similar messages are repeated in other files that also match the current date/time. I’m familiar with cron jobs, not with Android jobs, so constraints is a somewhat diffuse concept. But that’s something we can build on.

Very conveniently, there’s not THAT much in /data/system/, /data/system_app and /data/system_priv_app left, but there is a “job” subfolder with one file, “/data/data/system/job/jobs.xml”. And lo and behold, before and after some other job entries that do have no constraints but at least mention delays or extras, there’s this bastard on line 282ff:

<job jobid="42613" package="com.weawow" class="io.huq.sourcekit.wifi.HICellularJobService" uid="10088">
<constraints />
<one-off />
<extras />
</job>

No constraints, not a one-time job, no extras. Yup – restore the full “faulty” backup, remove the lines from this very file, and the thing boots up as if nothing ever happened. Fuck you, com.weawow.

As I cannot spot a plethora of angry users over there, this either means nobody made the connection to this app yet, or this was a one-off glitch, maybe caused by a corrupted update download or really bad luck when writing the jobs file. In any case, this shit left me without a usable phone for a week and also made me miss last weeks blog post. And it made me dig deep into Android, much further than I ever intended to.

Well – root your devices, and make backups. Maybe automate them if you’re the type of person that likes to skip pesky but vital tasks of the modern era. Do however think about if want to save them “into the cloud”, which is, as we all know, just a fancy term for someone else’s computer…


Leave a Reply

Your email address will not be published. Required fields are marked *

:mrgreen: 
:neutral: 
:twisted: 
:arrow: 
:shock: 
:smile: 
:???: 
:cool: 
:evil: 
:grin: 
:idea: 
:oops: 
:razz: 
:roll: 
;-) 
:cry: 
:eek: 
:lol: 
:mad: 
:sad: 
:suspect: 
:!: 
:?: 
:bye: 
:good: 
:negative: 
:scratch: 
:wacko: 
:yahoo: 
:heart: 
B-) 
:rose: 
:whistle: 
:yes: 
:cry2: 
:mail: 
:-(( 
:unsure: 
:wink: