Android Question Service stops

davfla

Member
Licensed User
Longtime User
Hi all,

i have a problem with start a alarm through a service. The service should check every minute for the wake time, but it will not work. I tested it under Android 5.0, Android 4.3 (Cyanogenmod) and Android 4.3 (Tab3). On every device the same problem.

At first I tried it with a Timer in service :
Works fine. But if the device are sleeping (screen off), the timer stops until the user awake the device.

Then with StartServiceAt :
Works not steadily.

I use the Service Attribute
#StartAtBoot: True
#StartCommandReturnValue: android.app.Service.START_STICKY

In the event Service_Destroy :
StartServiceAt(Me, DateTime.Now + 5 * 1000, True)

The code :
B4X:
Dim StartTime as String = "10:30"

Sub Service_Create
    DateTime.TimeFormat = "HH:mm"
    Dim n As Notification

    'This part only prevent for killing the process through the OS
    n.Initialize
    n.Icon = Null
    n.Vibrate = False
    n.OnGoingEvent = True
    n.SetInfo("Info", "Prevent from being killed", Main)
    Service.StartForeground(0, n)

    SaveInText("Service created.")

End Sub

Sub Service_Start (StartingIntent As Intent)
    CheckForUpdate
End Sub

Sub CheckForUpdate
    Dim tmpZeit As String = DateTime.Time(DateTime.Now)     'Nowtime
    StartServiceAt("", DateTime.Now + (44 * 1000), True)    'Restart service in 44 seconds

    'Check for alarm time
    If tmpZeit = StartTime then
          'Raise alarm
    End If
    SaveInText("Service restart in : 44 seconds.")   'Log
End Sub

'Write the log in file
Private Sub SaveInText(SaveText As String)
    Dim tw As TextWriter
    Dim Tt As String
    tw.Initialize(File.OpenOutput(File.DirRootExternal, "Info.txt", True))
    Tt = DateTime.time(DateTime.Now) & " : " & SaveText
    Log(Tt)
    tw.Write(CRLF & Tt)
    tw.Flush
    tw.Close
End Sub

Here is a log file :

09:00 : Service restart in : 44 seconds.
09:03 : Service restart in : 44 seconds.
09:04 : Service restart in : 44 seconds.
09:04 : Service restart in : 44 seconds.
09:05 : Service restart in : 44 seconds.
09:06 : Service restart in : 44 seconds.
09:08 : Service restart in : 44 seconds.
09:10 : Service restart in : 44 seconds.

09:10 : Service restart in : 44 seconds.
09:11 : Service restart in : 44 seconds.
09:12 : Service restart in : 44 seconds.
09:13 : Service restart in : 44 seconds.
09:15 : Service restart in : 44 seconds.
09:16 : Service restart in : 44 seconds.
09:17 : Service restart in : 44 seconds.
09:19 : Service restart in : 44 seconds.
09:21 : Service restart in : 44 seconds.

09:22 : Service restart in : 44 seconds.
09:23 : Service restart in : 44 seconds.
09:24 : Service restart in : 44 seconds.
09:24 : Service restart in : 44 seconds.
09:26 : Service restart in : 44 seconds.

09:27 : Service restart in : 44 seconds.
09:29 : Service restart in : 44 seconds.
09:33 : Service restart in : 44 seconds.

09:34 : Service restart in : 44 seconds.
09:35 : Service restart in : 44 seconds.
09:37 : Service restart in : 44 seconds.
09:39 : Service restart in : 44 seconds.

09:39 : Service restart in : 44 seconds.
09:40 : Service restart in : 44 seconds.
09:41 : Service restart in : 44 seconds.
09:42 : Service restart in : 44 seconds.
09:44 : Service restart in : 44 seconds.
09:44 : Service restart in : 44 seconds.
09:46 : Service restart in : 44 seconds.

09:48 : Service restart in : 44 seconds.
09:49 : Service restart in : 44 seconds.
09:50 : Service restart in : 44 seconds.
09:54 : Service restart in : 44 seconds.

09:55 : Service restart in : 44 seconds.
09:56 : Service restart in : 44 seconds.
09:57 : Service restart in : 44 seconds.
09:59 : Service restart in : 44 seconds.

09:59 : Service restart in : 44 seconds.
10:00 : Service restart in : 44 seconds.
10:01 : Service restart in : 44 seconds.
10:02 : Service restart in : 44 seconds.
10:03 : Service restart in : 44 seconds.
10:03 : Service restart in : 44 seconds.
10:04 : Service restart in : 44 seconds.
10:06 : Service restart in : 44 seconds.
10:08 : Service restart in : 44 seconds.

10:09 : Service restart in : 44 seconds.
10:11 : Service restart in : 44 seconds.
10:12 : Service restart in : 44 seconds.
10:13 : Service restart in : 44 seconds.
10:14 : Service restart in : 44 seconds.
10:15 : Service restart in : 44 seconds.
10:16 : Service restart in : 44 seconds.
10:17 : Service restart in : 44 seconds.
10:19 : Service restart in : 44 seconds.

10:20 : Service restart in : 44 seconds.
10:21 : Service restart in : 44 seconds.
10:22 : Service restart in : 44 seconds.
10:23 : Service restart in : 44 seconds.
10:24 : Service restart in : 44 seconds.
10:25 : Service restart in : 44 seconds.
10:25 : Service restart in : 44 seconds.
10:26 : Service restart in : 44 seconds.
10:27 : Service restart in : 44 seconds.
10:28 : Service restart in : 44 seconds.
10:29 : Service restart in : 44 seconds.
10:29 : Service restart in : 44 seconds.
10:32 : Service restart in : 44 seconds.

10:32 : Service restart in : 44 seconds.
10:33 : Service restart in : 44 seconds.
The alarm was not raised because in the alarm time the service don't checked for the time. But the service should checked the time every 44 seconds. I tried to check with more then 44 seconds. But the same result.
I know, this way is not the best for check the time. But in this example I only want to know why the service proof not every minute.

Any suggestion what matters ?

Thank you.
David

P.S. Sorry for my english
 
Last edited:

davfla

Member
Licensed User
Longtime User
Hi Erel,

thank you for your answer.
But the if-function is not the problem. I can remove this if-function and the result in the log file is the same. It looks for me the Android OS sometimes forget the wake event of the service. It is possible, that the start event fired after 1 - 4 minutes after the time in the StartServiceAt time. (see in log file from first thread).
And sometimes the service create new without ending before. All the data in the log file was created while the app runs in background.

Here is a part of a new log file from today. In this try I removed all functions. The service should only start every 44 seconds. Not more or less.

12:30:11 : Service restart in : 44 seconds.
12:30:55 : Service restart in : 44 seconds.
12:31:40 : Service restart in : 44 seconds.
12:32:24 : Service restart in : 44 seconds.
12:33:08 : Service restart in : 44 seconds.
12:33:53 : Service restart in : 44 seconds.
12:36:18 : Service restart in : 44 seconds.

12:36:19 : Service restart in : 44 seconds.
12:37:03 : Service restart in : 44 seconds.
12:37:48 : Service restart in : 44 seconds.
12:38:32 : Service restart in : 44 seconds.
12:39:16 : Service restart in : 44 seconds.

In the time between 12:33 and 12:36 no event was raised. In this time the device was sleeping.

And work with StartServiceAt with longer dimensions like 2 hours or more have the same problem.
Is it possible to get a Android event, if the time changing?

Very confused problem for me.

Thank you.

David
 
Last edited:
Upvote 0

davfla

Member
Licensed User
Longtime User
Hi,

I created a new test. Now I stop the service after proof the time and cancel all scheduled wake times for the service before sending the ServiceStartsAt command.

CancelScheduledService(Me)
StopService(Me)
ServiceStartsAt(Me, Datetime.Now + 60 * 1000, True)

In this logs the app wrotes the estimated wake time of the service (second time in the log).

09:31:52 : Next : 17/04 09:32:52*
09:34:53 : Next : 17/04 09:35:53*
09:35:53 : Next : 17/04 09:36:53*
09:38:54 : Next : 17/04 09:39:54*

09:42:54 : Next : 17/04 09:43:54*
09:43:55 : Next : 17/04 09:44:55*
09:46:30 : Next : 17/04 09:47:30*
09:50:38 : Next : 17/04 09:51:38*
09:52:20 : Next : 17/04 09:53:20*

09:53:20 : Next : 17/04 09:54:20*
09:54:20 : Next : 17/04 09:55:20*
09:55:20 : Next : 17/04 09:56:20*
09:56:38 : Next : 17/04 09:57:38*
09:57:38 : Next : 17/04 09:58:38*
09:58:38 : Next : 17/04 09:59:38*
09:59:38 : Next : 17/04 10:00:38*
10:00:38 : Next : 17/04 10:01:38
10:01:38 : Next : 17/04 10:02:38*
10:02:38 : Next : 17/04 10:03:38*
10:03:39 : Next : 17/04 10:04:39*
10:04:39 : Next : 17/04 10:05:39*
10:06:14 : Next : 17/04 10:07:14*

10:07:40 : Next : 17/04 10:08:40*
10:08:40 : Next : 17/04 10:09:40*
10:11:40 : Next : 17/04 10:12:40*

Under Galaxy S5 with Android 5.0 the results looks better, but not steadily.

06:16:50 : Next : 17/04 06:17:50*
06:17:51 : Next : 17/04 06:18:51*
06:18:52 : Next : 17/04 06:19:52*
06:19:53 : Next : 17/04 06:20:53*
06:20:53 : Next : 17/04 06:21:53*
06:23:03 : Next : 17/04 06:22:54* <- very mysterious. Start the service before now time ?
06:23:03 : Next : 17/04 06:24:03

06:24:03 : Next : 17/04 06:25:03*
06:25:04 : Next : 17/04 06:26:04*

Is there any way to realize a reliable alarm watcher without the standard alarm from android ?
Maybe I can proof the wake time for plausibility. Then I check for alarm in the last minutes and raise the alarm event in my app. But this would be a workaround only.

I would be grateful for any suggestions.

Thank you
David
 
Last edited:
Upvote 0

lemonisdead

Well-Known Member
Licensed User
Longtime User
You shouldn't use ServiceStartAt as a timer. You should instead use a real timer.
I am sorry this is not my question but the advice is important for me.
Please why shouldn't a service be used as a timer with StartServiceAt ?

Because it won't be started at the right time or because it is too heavy for the system ?

Because it could be less energy spending having an action planned using StartServiceAt instead of having a long time service running

Sorry again and many thanks
 
Upvote 0

Peter Simpson

Expert
Licensed User
Longtime User
@lemonisdead I personally use StartServiceAt set to True and as a Sticky Service in all my widgets and services. I use StartServiceAt as a timer (Mainly set to every 60 seconds or 60 minutes (for my weather app)) as I find that using an actual timer is not reliable enough for me, especially for my clock app/widget.

Resources wise I've just check settings - battery usage on 4 devices running my widgets and services and not one of my widgets or services are showing up in the standard Android battery usage list :) lowest is 1%.

I will use a timer within StartServiceAt if what I'm doing with the timer falls within 60 seconds of the StartServiceAt starting...
 
Last edited:
Upvote 0

davfla

Member
Licensed User
Longtime User
You shouldn't use ServiceStartAt as a timer. You should instead use a real timer.

Thank you for this hint. First tests looks good. I will report more soon. But what suprise me, in older tests the timer was stopped if the device was sleeping. Maybe I had tried without StickyService or Service.Foreground.

Thanks
 
Upvote 0

davfla

Member
Licensed User
Longtime User
I had tested now the alarm with a timer. And there is the old problem again.

I created a timer in a service. Here is a simplified example.

B4X:
#Region  Service Attributes
   #StartAtBoot: True
   #StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

Dim Time as Timer

Sub Service_Create
   Dim n As Notification
  n.Initialize
  n.Icon = Null
  n.Vibrate = False
  n.OnGoingEvent = True
  n.SetInfo("Info", "Prevent from being killed", Main)

  Service.StartForeground(0, n)
End Sub

Sub Service_Start (StartingIntent As Intent)

   If Time.IsInitialized = False Then
     Time.Initialize("tim", 1000) : Time.Enabled = True
     Log("Restart service - Init")
   Else
     Time.Interval = 1000 : Time.Enabled = True
     Log("Restart service - Reset")
   End If
 
End Sub

Sub Service_Destroy
   Log("Service was destroyed. Restart in 5 seconds.")
   StartServiceAt("", DateTime.Now + 5 * 1000, True)
End Sub

Sub tim_Tick
   Log("Timer ticked")
   CheckForAlarm
End Sub

Sub CheckForAlarm
     'Here is code for restart the timer.
     'If the time > 30 minutes until the next wake point, then restart timer in 30 minutes.
     'Else restart at the wake time
End Sub

Now is the problem, that the service will killed by the OS without raise the "Sub Service_Destroyed".

I think it depends from the device.
I don't understand this because I use START_STICKY and Service.StartForeground.
On Samsung Galaxy S1 with Cyanogenmod (Android 4.3) the service will destroyed nearly instantly. (Low System)
On Samsung Galaxy S5 with Android 5.0 it will work 2-3 times and then the service stop. (Good System)
On Emulator with Genymotion and Cyanogenmod it works without problems. (System no matters)

If the OS would call the destroyed function then I could restart the service. But I get no request whether the service was killed or not.
Maybe a mix between StartServiceAt and the timer can be the solution, but this is very complicated.

I think, I work now with the workaround, that the service recreated himself in every minute and proof the time. If the duration of sleep bigger then the planned time, the application proof for missed alarm events. So a maximum of 5 minutes the alarm raised later. That's not a good solution, but the only I can see.
If I find a better way I will post it here.

Thanks all.

David
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Now is the problem, that the service will killed by the OS without raise the "Sub Service_Destroyed".
This is the expected behavior.

Maybe a mix between StartServiceAt and the timer can be the solution, but this is very complicated.
Yes. You need to call StartServiceAt to start your process 10 minutes (?) before the exact time and then use a timer to fire at the exact time.
 
Upvote 0

davfla

Member
Licensed User
Longtime User
Hi Erel,

You need to call StartServiceAt to start your process 10 minutes (?) before the exact time and then use a timer to fire at the exact time.

But the problem is, the timer on devices with poor hardware unpredictable interrupt. In my test with the Galaxy S1 the timer raise the Tick Event only 0-1 after the first initializing (in a service, in activity not). Then the timer stops without any message. I believe, the service will killed from the OS (without a Service_Destroyed) between the ticks. On my S5 this happends not so often, but it's possible.
With other words : The service can destroyed from the OS in the Timer mode (10 minutes in your example)

I know, devices with so old hardware configurations are not very distributed. But maybe anyone have many crapware on they device. Then it can matter, too. Because low RAM from the other apps.

My method to start every minute with proof for skipped alarms works good, but it's drained the battery a little bit. Not the ideal solution.

Maybe anyone have time and can test for get the same results.
You need only a service, start a timer with a tick duration from 60*1000 and run it on a poor real device. I'm cursious about it.

Thanks.

David
 
Upvote 0

davfla

Member
Licensed User
Longtime User
I will try it with the PhoneWakeState function and report the result. Sounds what I searched for. Thanks for this tip.
 
Upvote 0

davfla

Member
Licensed User
Longtime User
Hi,

I've tested with many different solutions and I solved the problem now.

The timer object is not a good solution. This stop every time if the device is sleeping. I tried to wake up the screen with PhoneWakeState and it works. But if the user manually do switch off the screen, the timer don't work until the screen wake up again. This is for the snooze timer not practicabel. It works not with Start_Sticky or the PhoneWakeState.

Now I realized it with a "four step" solution with two services. Here is an simplified example.

Service A:
B4X:
Dim TimeToStart as String   'i.E. 15:00
Dim TimeNow as String       'Datetime.Now
Dim Minutes as int 

Minutes = timeToStart - TimeNow

If NoWakePointToday then
     'Restart service 00:00 at next day
end if

If Minutes > 60 Minutes then         'Wake in 53 Minutes because battery drain and if the Service "forget" to start at the correct time
    'Restart Service in 53 minutes
End if

If Minutes >= 10 Minutes then       'Wake in 6 Minutes because battery drain and if the Service "forget" to start at the correct time
   'Restart Service in 6 Minutes
End if

If Minutes < 10 Minutes then
     Service B.TimeToStart = TimeToStart
     StartService(Service B)
end if

Service B:
B4X:
Dim TimeToStart as String
Dim TimeNow as String       'Datetime.Now

Sub Service_Start
     If TimeToStart = TimeNow then
            'Raise Alarm
     Else
            RestartServiceAt(Me, datetime.now + 10 * 1000, True)
            StopService(me)
     End if
End sub

With this solution the battery drain is very low until the last 10 minutes. But it works reliably on weak hardware devices.

Maybe anyone can help this. It had needed one week to get this result here.

Thanks for answers.

David
 
Last edited:
Upvote 0
Top