Android Question Avoid App Stop - High Priority Services

Marcos Alves

Well-Known Member
Licensed User
Hello all,

we have an app for business messages that must to be always active. To avoid maintaining the service in foreground, we use Firebase Cloud Messages to start it when a server event is generated, what sends a FCM to Android and then runs the message receiving routine.
I noticed that rarely we have some errors (natural from an asynchronous process receiving complex data from internet), those stop the app. In this situations, if the user doesn't restarts manually it stops to receive messages (FCM routine doesn't receive push events anymore).
Is there some way, without using a Foreground Service with icon, to garante that the app will continue to receive Firebase Cloud Messages and start, even after an error (like in old versions of android where it was possible to configure a service that where automatically restarted by system)?
I notice that, after an error, if the user doesn't restart the app, even ServiceStartAt doesn't work...
 

OliverA

Expert
Licensed User
I just noticed this with a WatchDog app (app A) I'm working on. It uses intents to communicate with another app (app B) that should constantly run. When you close out app B normally or even force stop the app, app A is able to start app B via intent. But, if app B crashes (in this case with some intentional code to see what happens), the user is given the option to restart app B. At that moment and time (when a user is given the option to restart the app) any attempts to wake up app B via app A's intents fail. It's like B is in limbo and does not process the intents. And it is not like the intents are queued and once app A runs (user restarts the app) it processes the missed intents; no, the intents are just gone. So, it seems that while an app is stuck in "restart mode" where a user is given the option to restart an app, all intents disappear into a black hole and the app is completely unresponsive.
 

Marcos Alves

Well-Known Member
Licensed User
I just noticed this with a WatchDog app (app A) I'm working on. It uses intents to communicate with another app (app B) that should constantly run. When you close out app B normally or even force stop the app, app A is able to start app B via intent. But, if app B crashes (in this case with some intentional code to see what happens), the user is given the option to restart app B. At that moment and time (when a user is given the option to restart the app) any attempts to wake up app B via app A's intents fail. It's like B is in limbo and does not process the intents. And it is not like the intents are queued and once app A runs (user restarts the app) it processes the missed intents; no, the intents are just gone. So, it seems that while an app is stuck in "restart mode" where a user is given the option to restart an app, all intents disappear into a black hole and the app is completely unresponsive.
Yes, and this behavior could be a problem with high priority apps. Depending on user to restart is a disaster: imagine a messenger which receives important information about a company and the employee must to take some action for each event. This must to be some way to garante that a high priority app is running on Android and SO MUST to restart each if it stops...

Does anybody knows how to do it (by the way, I noticed that some famous apps like WhatsApp and FB Messenger have a behavior as always running... even after a crash, some minutes later there are notifications arriving again, even without any user action... how to do this?)
 

OliverA

Expert
Licensed User
how to do this?
Disclaimer: I'm not an expert, so I may just not have the chops to pull off what FB does (both apps mentioned are FB).
I'm really starting to think that some vendors, especially the big vendors, pay Google (and Apple - I'm looking at you Dropbox) for some nice back door API access that gives them a leg up over us smaller developers. Of course, I may just suck at this.
 

moster67

Expert
Licensed User
I'm really starting to think that some vendors, especially the big vendors, pay Google (and Apple - I'm looking at you Dropbox) for some nice back door API access that gives them a leg up over us smaller developers. Of course, I may just suck at this.
This apparently happens. I have heard about some software companies, such as TeamViewer, to get some extra privileges but this was by making deals directly with manufacturers such as Samsung, Huawei etc..
 

Jmu5667

Well-Known Member
Licensed User
Yes, and this behavior could be a problem with high priority apps. Depending on user to restart is a disaster: imagine a messenger which receives important information about a company and the employee must to take some action for each event. This must to be some way to garante that a high priority app is running on Android and SO MUST to restart each if it stops...

Does anybody knows how to do it (by the way, I noticed that some famous apps like WhatsApp and FB Messenger have a behavior as always running... even after a crash, some minutes later there are notifications arriving again, even without any user action... how to do this?)
Hi

We are just finalizing the release of a corporate messaging app. We no not use FCM. The app is always running in the background, and so far it seems to be stable (8.0+). We have a back end B4j server to handle all the connections and message handling. By doing this were are insulated from external problems with 3rd party providers. Also as good as FCM is it is not suitable for all the scenarios that our systems are deployed in.

The B4j server took 2 days from scratch to develop, with some reusable code :) . Maybe you should consider this. If your app crashs, maybe you should consider building in watchdog service.

Regards

John.
 

OliverA

Expert
Licensed User
I notice that, after an error, if the user doesn't restart the app, even ServiceStartAt doesn't work...
There is a way to disable the restart message. See https://www.b4x.com/android/forum/threads/auto-restart-an-android-application-after-a-crash.103858/
Disclaimer: I'm not an expert, so I may just not have the chops to pull off what FB does (both apps mentioned are FB).
I'm really starting to think that some vendors, especially the big vendors, pay Google (and Apple - I'm looking at you Dropbox) for some nice back door API access that gives them a leg up over us smaller developers. Of course, I may just suck at this.
The last sentence applies. Plus, a shout out/apology to the really smart people working at other companies (that I disparaged here).
 

Marcos Alves

Well-Known Member
Licensed User
There is a way to disable the restart message. See https://www.b4x.com/android/forum/threads/auto-restart-an-android-application-after-a-crash.103858/

The last sentence applies. Plus, a shout out/apology to the really smart people working at other companies (that I disparaged here).
Hello,

In this thread he says that doesn't know what happens if a service crashes, what is exactly my problem because our app stops when it is in background... I'll test but not sure that will work...
Thanks !
 

Jmu5667

Well-Known Member
Licensed User
Hello,

In this thread he says that doesn't know what happens if a service crashes, what is exactly my problem because our app stops when it is in background... I'll test but not sure that will work...
Thanks !
How are you setting up the background service, can you show me the code in the service_create and service_start please
 

Marcos Alves

Well-Known Member
Licensed User
How are you setting up the background service, can you show me the code in the service_create and service_start please
Hello @Jmu5667 ... follows my service_create
B4X:
Sub Service_Create
    
    'This is the program entry point.
    'This is a good place to load resources that are not specific to a single activity.
    Permissions = Non_Authorized_Runtime_Permissions
    Kvs.Initialize(File.DirInternal,"riolivre")
    NativeMe.InitializeContext
    
    SdkVersion = Phone1.SdkVersion
    'Kvs.DeleteAll
    'File.Delete(File.DirInternal,"nexphone.db")
    
    'Values from 0 to 30... from 0 to 1, reduce, above 1, aplify
    If Not(Kvs.ContainsKey("miclevelradio")) Then
        Kvs.Put("miclevelradio",10)
        Kvs.put("speakerlevelradio",10)
        Kvs.Put("miclevelphone",12)
        Kvs.Put("speakerlevelphone",10)
    End If
    
    If File.Exists(File.DirInternal,"voice_note_start.wav") = False Then
        File.Copy(File.DirAssets,"voice_note_start.wav",File.DirInternal,"voice_note_start.wav")
        File.Copy(File.DirAssets,"voice_note_stop.wav",File.DirInternal,"voice_note_stop.wav")
        File.Copy(File.DirAssets,"voice_note_error.wav",File.DirInternal,"voice_note_error.wav")
    End If

    If Not(File.Exists(File.DirInternal,"placedetails.db")) Then
        File.Copy(File.DirAssets,"placedetails.db",File.DirInternal,"placedetails.db")
    End If

    If Not(File.Exists(File.DirInternal,"profile.png")) Then
        File.Copy(File.DirAssets,"actionbar_button_person_dark.png",File.DirInternal,"profile.png")
    End If

    If Not(File.Exists(File.DirInternal,"genericnotify.png")) Then
        File.Copy(File.DirAssets,"actionbar_button_person_dark.png",File.DirInternal,"genericnotify.png")
    End If

    If Not(Kvs.ContainsKey("country")) Then
        Kvs.Put("country","br")
    End If
    
    If Not(Kvs.ContainsKey("radiocallstarted")) Then
        Kvs.Put("radiocallstarted",False)
    End If
    
    Kvs.Put("chamadaemcurso",False)
    If Not(Kvs.ContainsKey("radioactive")) Then
        Kvs.Put("radioactive",False)
    End If
    
    'Nb.Initialize
    
    Sql1.Initialize(File.DirInternal,"nexphone.db",True)
    Dim Query As String
    'Query = "drop table radiohistory"
    'Sql1.ExecNonQuery(Query)
    'Query = "drop table busca"
    'Sql1.ExecNonQuery(Query)
    'Query = "drop table contacts"
    'Sql1.ExecNonQuery(Query)
    'Query = "drop table indications"
    'Sql1.ExecNonQuery(Query)
    Dim DbUpdate As Boolean = False
    If Kvs.ContainsKey("database-done") = False Then
        DbUpdate = True
    Else
        If Kvs.Get("database-done") <> "43.1.0" Then DbUpdate = True
    End If
    
    If DbUpdate = True Then
        Kvs.Put("database-done","43.1.0")
        
        Query = "create table if not exists radiohistory (id integer PRIMARY KEY,iduser integer,login text,nome text,company text,mobile text,googleid text,start real,answer real,end real,status text)"
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists busca (id integer PRIMARY KEY,login text,nome text,company text,mobile text,datahora real,googleid text)"
        Sql1.ExecNonQuery(Query)

        Query = "create table if not exists contacts (id integer PRIMARY KEY,login text,nome text,company text,mobile text,datahora real,googleid text) "
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists indications (googleid text PRIMARY KEY,photoreference text,company text,nome text,telefone text,celular text,datahora real,enviada integer default 0) "
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists addedplaces (googleid text PRIMARY KEY,latitude text,longitude text,accuracy text,name text,phone_number text,address text,types text,website text,language text,datahora real)"
        Sql1.ExecNonQuery(Query)


        Query = "create table if not exists chats (id text primary key,title text,description text,logofile text,created real,id_creator integer,is_active int," _
        & "is_pro int,daysofweek text,starthour int,startminute int,endhour int,endminute int,chat_active real)"
        Sql1.ExecNonQuery(Query)

        Query = "create table if not exists messages (id text primary key,chatid text,source int,target int,msgcreated real, msgsent real, msgreceived real,msgread real,media_url text " _
        & ",media_mime_type,media_size int,media_name text,media_caption text,media_duration int,latitude real,longitude real,thumb_image text,msgdata text)"
        Sql1.ExecNonQuery(Query)

        Query = "create table if not exists messagestemp (id text primary key,chatid text,source int,target int,msgcreated real, msgsent real, msgreceived real,msgread real,media_url text " _
        & ",media_mime_type,media_size int,media_name text,media_caption text,media_duration int,latitude real,longitude real,thumb_image text,msgdata text)"
        Sql1.ExecNonQuery(Query)

        '#### TODO - CREATE UNIQUE STATEMENT     
        Query = "create table if not exists chat_users (iduser int,idchat text,starttime real,endtime real,isadmin int,primary key (iduser,idchat) )"
        Sql1.ExecNonQuery(Query)
        
        Try
            Query = "alter table chat_users add nome text"
            Sql1.ExecNonQuery(Query)   
            Query = "alter table chat_users add login text"
            Sql1.ExecNonQuery(Query)   
            Query = "alter table chat_users add company text"
            Sql1.ExecNonQuery(Query)
        Catch
            Log(LastException)
        End Try

        Try
            Query = "create index idx_msgcreated on messages (msgcreated)"
            Sql1.ExecNonQuery(Query)
            Query = "create index idx_chatid on messages (chatid)"
            Sql1.ExecNonQuery(Query)
        Catch
            Log(LastException)
        End Try

        '### TODO - END UNIQUE STATEMENT
        
        Query = "create table if not exists msgqueue (id int,iduser int,msgdata text,datetime real)"
        Sql1.ExecNonQuery(Query)
        
        'Query = "delete from upmediaqueue"
        'Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists upmediaqueue (id int,iduser int,msgdata text,datetime real)"
        Sql1.ExecNonQuery(Query)

        Query = "create table if not exists compressmediaqueue (id int,mediatype text,chatid text,messageid text,msgstring text,situation text,datetime real)"
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists chatselected (id int primary key)"
        Sql1.ExecNonQuery(Query)
        
        Query = "alter table chatselected add idchat text"
        Try
            Sql1.ExecNonQuery(Query)
        Catch
            Log(LastException)
        End Try
        
        Query = "create table if not exists downqueue (id int,msgdata text,datetime real)"
        Sql1.ExecNonQuery(Query)
        
        Query = "alter table contacts add lastuse real default 0"
        Try
            Sql1.ExecNonQuery(Query)
        Catch
            Log(LastException)
        End Try
        
        Query = "create table if not exists messagestatus (messageid text,chatid text,userid int,msgdelivered real,msgread real,primary key (messageid,userid))"
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists downmediaqueue (id int primary key,chatid text,medialink text,mediafile text,mimetype text)"
        Sql1.ExecNonQuery(Query)
        
        Query = "create table if not exists userselected (id int primary key,login text,nome text,company text)"
        Sql1.ExecNonQuery(Query)

        Query = "create table if not exists messageselected (id text primary key,chatid text,media_mime_type text)"
        Sql1.ExecNonQuery(Query)
    End If
    
    Dim ExtenFolder As String = rp.GetSafeDirDefaultExternal("shared")

    File.copy(File.DirAssets,"radioshort.wav", ExtenFolder ,"radioshort.wav")
    File.copy(File.DirAssets,"radiolong.wav",ExtenFolder ,"radiolong.wav")
    File.copy(File.DirAssets,"radiook.wav",ExtenFolder ,"radiook.wav")
    File.copy(File.DirAssets,"radiorefuse.wav",ExtenFolder ,"radiorefuse.wav")
    File.copy(File.DirAssets,"radiostart.wav",ExtenFolder ,"radiostart.wav")
    File.copy(File.DirAssets,"msgting.mpeg",ExtenFolder ,"msgting.mpeg")
    File.Copy(File.DirAssets,"missed_radio.png",ExtenFolder,"missed_radio.png")
    File.Copy(File.DirAssets,"largecall.png",ExtenFolder,"largecall.png")
    File.Copy(File.DirAssets,"oncall.png",ExtenFolder,"oncall.png")
    
    Initialize_Voip

End Sub
And service_start
B4X:
Sub Service_Start (StartingIntent As Intent)

    If Kvs.ContainsKey("username") Then
        Dim Username As String = Kvs.Get("username")
        Dim Password As String = Kvs.Get("password")
        'Phone.register ("falegratis.com.br", Username, Password, 600)
        CallSubDelayed2(FirebaseMessaging, "SubscribeIndividual",Username)
    End If

End Sub
What are u looking for ?
 

Marcos Alves

Well-Known Member
Licensed User
Do you want to keep this running all the time ?
No. The problem isn't related to foreground service state... the service is automatically called by firebase push service. If it's started as a foreground service a icon will be showed on notifications bar and the battery consumption will be high, what's not good.
The problem is when the app crashes (and doesn't matter how hard you try, a complex app will always crash in some moments), the push service doesn't work anymore and arriving messages aren't notified.
So the question is: how to automatically restart a background service in Android without showing the error message to the user?
It's something like this : https://medium.com/@ssaurel/how-to-...r-a-crash-or-a-force-close-error-1a361677c0ce
But I don't know hoe to implement in b4a yet...
 

DonManfred

Expert
Licensed User
the service is automatically called by firebase push service. If it's started as a foreground service a icon will be showed on notifications bar and the battery consumption will be high, what's not good.
I am using FCM Pushnotifications. My Service is NOT started in Foreground when a Message arrives! I don´t have any problem here.
Even after weeks a push-message will start the FirebaseMessaging service. But, again, it will not be started a a Foreground service. And i don´think that the Notification will eat much battery...........

Sure, if you start it as a foreground service there will be an Icon in the notificationbar.
The battery assumptiion does not come from the notification. More it is your service which consumes battery.
 

Marcos Alves

Well-Known Member
Licensed User
I am using FCM Pushnotifications. My Service is NOT started in Foreground when a Message arrives! I don´t have any problem here.
Even after weeks a push-message will start the FirebaseMessaging service. But, again, it will not be started a a Foreground service. And i don´think that the Notification will eat much battery...........

Sure, if you start it as a foreground service there will be an Icon in the notificationbar.
The battery assumptiion does not come from the notification. More it is your service which consumes battery.
Hello @DonManfred ,

YES, I'm either using FCM Push service and Foreground is not needed. The problem occurs when the app has any error (a complex app receiving asynchronous requests from web will sometimes crash). And then an error message is shown to the user and app is closed... after this, if the user doesn't restarts the app manually, the FCM will not work (it's the same effect of opening app manager and click "Force Stop" button).
I read some workarounds for this problem here: https://medium.com/@ssaurel/how-to-...r-a-crash-or-a-force-close-error-1a361677c0ce
But I really don't know how to implement it... hide the error message from user and restart automatically the app is really a good idea... how can I do this ? (even because sometimes the Android shows a horrible message "The app X is crashing continuously" ... or something like this - it's the path to uninstall)
 

Marcos Alves

Well-Known Member
Licensed User
Hi, do you have a log of the actual error ?
Hello,
the error occurs due asynchronous requests thru internet... It's not possible to fix because it's not possible to preview every event. To illustrate, this program has about 45 activities, 20 services using FCM, SIP, 2 or 3 native libs calling 60 API methods communicating with a remote server. This means that some error will occur sometimes... I need to hide the error message and restart silently ... (of course that every recurrent error I will fix, but it's not possible to track and fix all the errors)
 

walterf25

Expert
Licensed User
Hello,
the error occurs due asynchronous requests thru internet... It's not possible to fix because it's not possible to preview every event. To illustrate, this program has about 45 activities, 20 services using FCM, SIP, 2 or 3 native libs calling 60 API methods communicating with a remote server. This means that some error will occur sometimes... I need to hide the error message and restart silently ... (of course that every recurrent error I will fix, but it's not possible to track and fix all the errors)
Why would you have 20 different Services using FCM?

I think that's the problem, why not just use one, You can subscribe to different topics using only one Service.

Walter
 

Marcos Alves

Well-Known Member
Licensed User
Why would you have 20 different Services using FCM?

I think that's the problem, why not just use one, You can subscribe to different topics using only one Service.

Walter
Hello @walterf25 ,

To clarify: I use FCM (one service) calling other 19 services (those don't receive FCM PUSH directly) depending on the content of received message. What I want to say also is : it's impossible to garante that a complex app connected thru internet to a remote server will not crash. Today our "crash level" is less than 1 per 100.000 transactions/messages. But one single app/user could receive more than 20.000 messages/day (including system messages), and eventually the app will crash (and it's not good because the message on screen and because the app depends on the user to restart).
So, the question is: "how can I avoid the error message on the screen and restart silently the app".... that´s it. Erros will occur.
 
Top