Services, timers and deep sleep

socialnetis

Active Member
Licensed User
Longtime User
Hi, I'm in the middle of a battery saver app. Its similar to Juice Defender, the main idea is to basically turn on/off wifi/data-mobile periodically.
I've been developing all the time using my phone connected to the IDE, and using lots of logs.
I am using a service, which is running in foreground (startforeground), and using timers to turn on and off the conectivity. I also have a "night time" (during some hours, the phone wont turn on conectivity) and a "peek time" (during some hours the frequency for conectivity will be more often) which are using timers too.

Everything was ok, until I decided to test it without the cable. When the phone screen goes off, its seems that the phone enters in deep sleep, and the service is not working during that time, until I unlock the phone.
During the time that the phone is "sleeping", all the timers are like frozen, and when I turn on the screen, the timers continue working but with a "cut interval".
Like for example, if I set Timer1 to tick in 5 minutes, wait 1 minute with screen on, then turn off screen for 2 minutes, and the turn on screen, the timer will fire in 4 minutes anyway (and it should be 2 minutes).

- It seems that one solution is using Partial lock, but I dont want to have it enabled all the time, because it wont save me battery.
- Another solutions could be using StartServiceAt, but i have lots of timers (like turn on/off, check conectivity, start/finish night time, start/finish peek time, and some others)

Any ideas!?
 

socialnetis

Active Member
Licensed User
Longtime User
I'm thing about modularizing my service into three or four services (I'll have to check how many I will need).
For example I can have all the variables in a main service, which runs in foregorund, and its schedule himself to turn on/off conectivity.
Another service (no need to run in foreground I guess), that controls the night time, in which case, it will cancel the main service schedule, and schedule himself in the end of the night time, and schedule the main again to turn the connections again.
An another one for the peack time, which it will change the frequency of the main service.

What do you think about this idea? And about the ram consumption? I don't want to start doing this unless its a good idea..
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
You will have to use PartialWakeLock for the duration you are executing code, and on exit you should release that lock.
StartServiceAt may be able to start the service during sleep, but does not guarantee complete execution (especially for timers which are message based).
When the thread exits the device will go back to sleep mode if there is no lock.
 
Upvote 0

bluejay

Active Member
Licensed User
Longtime User
I have found timers too unreliable for long durations or background scheduling.

I recommend using StartServiceAt.

You should only need one service (set to foreground - which you are already doing - use an icon).

My suggestions is:
1. keep a list of triggers with durations and next start time (in process globals)
2. calculate for each trigger then next trigger time
3. set flag on tasks that trigger next and call StartServiceAt for next triger time. set DuringSleep parameter as required.
4. in service start sub act on tasks that are flagged above and ones past due time, clear flags, goto step 2

I also suggest an internal keep alive task is also scheduled with long duration to ensure service is restarted is the OS kills if for some reason (which can happen even in foreground mode). You could check screen off state and increase the keep alive delay the longer the screen is off.

The main activity would be used to change settings or stopping the service.

You may or may not need PartialWakeLock while service is running a task actions- depends on what your code does. Use it to start with then optimize later.

Hope that helps.

bluejay
 
Upvote 0

socialnetis

Active Member
Licensed User
Longtime User
Thx for answering!

Erel, Yes, the timers are process globals variables in the service module, and are initialized in service_create. However, as I say before, when the phone enters in sleep mode, the timers are frozen, and when I unlock the phone, the timers are unfrost. Its like the service is suspended during the time that the screen is off.

Thedesolatesoul, I was thinking about partialwakelock, but I am executing code all the time (like for months). I dont think that putting locks during sleep mode, would be a good idea because it will drain the battery a lot, and it will loose the sense of a battery saver.
For example, this should be a normal execution:

(Actual time: 20:00, Frequency: 15 min, Night time: 23:00 - 08:00)
20:00: Turn on wifi
20:01: Check wifi is actually connected
20:02: Turn off Wifi
20:15: Turn on Wifi
20:16: Check wifi is actually connected
20:17: Turn off wifi
20:30: Turn on Wifi
...
22:45: Turn On Wifi
22:46: Check wifi is actually connected
22:47: Turn off wifi
23:00: Night Time (no more conectivity, unless the user unlocks the phone)
08:00: Night time end, turn on wifi
08:01: Check conectivity
08:02: Turn off wifi
08:15: Turn on..
... (and so on)

I don't know which would be a good strategy using locks, maybe I'm missing something


Bluejay, thx for the idea, maybe using something like a list of triggers could do it, but I think that it would be kind of hard to apply, because I have like 10 timers, and using the StartServiceAt with 10 different times, it would be a mess.
I'm using the screen_on, screen_off, and user_present events to make some stuff, there is no problem there. The problem is just with the timers, that dont work during sleep time

I think I'll try modularizing the service into 3 or 4. I'm a little worry about the ram consumption, right now its about 5mb, but if each service needs that amount, it would be like 20mb, and for some devices that only have 512mb, that is a significant amount.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
During the time that the phone is "sleeping", all the timers are like frozen, and when I turn on the screen, the timers continue working but with a "cut interval".
Like for example, if I set Timer1 to tick in 5 minutes, wait 1 minute with screen on, then turn off screen for 2 minutes, and the turn on screen, the timer will fire in 4 minutes anyway (and it should be 2 minutes).
You can set the timer interval to 1 minute and save the last tick event time. This way you can check the actual time that passed since the last event and the "lost" time will be less significant.
 
Upvote 0

socialnetis

Active Member
Licensed User
Longtime User
I finally made it using 2 auxiliar services. They are almost empty, they just execute some code in the service_start sub, and then call themselves later (like if they were timers, using StartServiceAt). I also call StopService in service_start in orden to not keep them in the ram (the state is in the main service).
And if someone is wondering, this timer-services consume about 0.2mb ram each (but they appear and dissapear almost inmediately), so I think that is a good tool.
 
Upvote 0
Top