0

Background:
A third party app produces a file in /sdcard/content.
My app should monitor the file for changes so it can print the contents; thus i need it to be constantly running.

The problems:

  • on an android 10 device (Alcatel tablet), if i swipe all apps away, the service gets killed
  • on another android 10 device (which i don't have access to), if the app is not in focus, i.e. the user is using another app, then it's not monitoring the file. If the user switches back to my app, it starts monitoring again.

On an android 9 device that was upgraded to 10 (Galaxy A20e) the service is not killed.


In my Main activity i have a spinner and when onItemSelected is called i start the service (if it wasn't already started) and bind to it:

if(ApplicationPersistence.isServiceStarted) {
        refreshNotification()
} else {
        startService(Intent(this, MyService::class.java))
        bindService(Intent(this, MyService::class.java), this, Context.BIND_AUTO_CREATE or Context.BIND_IMPORTANT)
}

I don't think you'd need to bind to a service if you want to start it as a foreground service.

I see the notification. It gets updated if i change the spinner selection.
I see MyService's onStartCommand being called.
I see MyActivity's onServiceConnected being called, as well as MyService's onBind.

MyService's onStartCommand acts as such:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if(ApplicationPersistence.isServiceStarted) {
                return Service.START_STICKY
        }

        ApplicationPersistence.fileObserver.startWatching()

        // notification initialization here
        
        startForeground(ApplicationPersistence.notificationID, ApplicationPersistence.notification)
        ApplicationPersistence.isServiceStarted = true
        return Service.START_STICKY
}
    

ApplicationPersistence being the class that stores most persistent data (it : Application()).

This is my manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="x.y.z">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="21" /> 

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"
        android:name="x.y.z.ApplicationPersistence"
        android:directBootAware="true"
        android:persistent="true"
        android:persistableMode="persistAcrossReboots"
        android:requestLegacyExternalStorage="true">

        <activity android:name=".MyActivity">
            <intent-filter>
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
        <service
            android:name=".MyService"
            android:directBootAware="true"
            android:description="@string/notif4"
            android:stopWithTask="false"/>
        <receiver android:name=".Receiver"></receiver>
    </application>
</manifest>

I'm tagetting 19/21 because of storage permissions on android 10.


I've tried using PowerManager to no avail. A WakefulReceiver precludes an IntentService which i'm not using as it'll terminate after processing the Intent. I haven't noticed any battery optimization issues, as i've disabled all i could find. WorkManager has a 15m minimum retry time which makes it useless for this purpose. Using a separate process didn't work either and i lost information i post t to the notification.

Am i missing something obvious? Music apps can do it...


Edit1

For the Alcatel, the last action i see in the log is the MyActivity's onPause() being called when i tap the home button. I see no reaction when i swipe.
For the Samsung, when i swipe i see

D/MyActivity: onDetachedFromWindow()
D/MyService: onTaskRemoved()
    android.app.ServiceConnectionLeaked: Activity x.y.z.MyActivity has leaked ServiceConnection x.y.z.MyActivity@ce48f05 that was originally bound here
        ...
                at x.y.z.MyActivity.onItemSelected(MyActivity.kt:201) // the bindService call
        ...
D/MyService: onUnbind(null)

Edit2

If i check if the service is foreground, it apparently is not on both devices, however, adb says otherwise.

Samsung

* ServiceRecord{92e7bc9 u0 x.y.z/.MyService}
  intent={cmp=x.y.z/.MyService}
  packageName=x.y.z
  processName=x.y.z
  baseDir=/data/app/x.y.z-3i0pcMiZVFi-apzWGR-5hw==/base.apk
  dataDir=/data/user/0/x.y.z
  app=ProcessRecord{8f822ce 20490:x.y.z/u0a210}
  isForeground=true foregroundId=1 foregroundNoti=Notification(channel=x.y.z pri=2 contentView=null vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 category=service vis=PRIVATE semFlags=0x0 semPriority=0 semMissedCount=0)
  createTime=-13m56s837ms startingBgTimeout=--
  lastActivity=-13m56s829ms restartTime=-13m56s837ms createdFromFg=true
  startRequested=true delayedStop=false stopIfKilled=false callStart=true lastStartId=1
  Bindings:
  * IntentBindRecord{b830b66 CREATE}:
    intent={cmp=x.y.z/.MyService}
    binder=android.os.BinderProxy@b291ea7
    requested=true received=true hasBound=true doRebind=false
    * Client AppBindRecord{4031f54 ProcessRecord{8f822ce 20490:x.y.z/u0a210}}
      Per-process Connections:
        ConnectionRecord{8ee48fc u0 CR IMP x.y.z/.MyService:@595c5ef}
  All Connections:
    ConnectionRecord{8ee48fc u0 CR IMP x.y.z/.MyService:@595c5ef}

Alcatel

* ServiceRecord{7872f83 u0 x.y.z/.MyService}
  intent={cmp=x.y.z/.MyService}
  packageName=x.y.z
  processName=x.y.z
  baseDir=/data/app/x.y.z-tB_tv4YEDBranjBzPXNqeg==/base.apk
  dataDir=/data/user/0/x.y.z
  app=ProcessRecord{bc00038 7463:x.y.z/u0a182}
  isForeground=true foregroundId=1 foregroundNoti=Notification(channel=x.y.z pri=2 contentView=null vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 category=service vis=PRIVATE)
  createTime=-26m9s402ms startingBgTimeout=--
  lastActivity=-26m9s397ms restartTime=-26m9s402ms createdFromFg=true
  startRequested=true delayedStop=false stopIfKilled=false callStart=true lastStartId=1
  Bindings:
  * IntentBindRecord{5de8688 CREATE}:
    intent={cmp=x.y.z/.MyService}
    binder=android.os.BinderProxy@1ece821
    requested=true received=true hasBound=true doRebind=false
    * Client AppBindRecord{b1f1446 ProcessRecord{bc00038 7463:x.y.z/u0a182}}
      Per-process Connections:
        ConnectionRecord{3c96139 u0 CR IMP x.y.z/.MyService:@75b5500}
  All Connections:
    ConnectionRecord{3c96139 u0 CR IMP x.y.z/.MyService:@75b5500}

There's a difference after vis=PRIVATE but that's it.


Edit3

For the most part, the service seems to be running in the foregroud.

I've also implemented a method in the Service's Binder that simply waits a random amount of time (1-2s) and returns the wait time.
This, in turn, is used by the binding class (my : Application()) inside a thread that waits 3-4s before calling the Binder method.
This way i get "server/client" interaction every 3s or so, but the app is still killed on Android 10 if i swipe all apps.


Edit 4

I've also registered a lot of random broadcasts in my Activity via filter.addAction() to try and keep it alive. I've used filter.addAction(Intent.ACTION_TIME_TICK) but swipe always kills the app.
Meaning the log stops, no onMethod (that I've overriden) is called; the notification is gone; the service is no longer running.

vesperto
  • 804
  • 1
  • 6
  • 26

1 Answers1

0

Use startForeground(id, notification);

I hope It will work correctly as it's working in one of my app.

Dev4Life
  • 2,328
  • 8
  • 22
  • 2nd block of code in the original post, 4 lines from the bottom. – vesperto Jul 30 '21 at 11:01
  • 1
    Well, then you have to keep some things running constantly in background, otherwise system will kill the service. Like sending broadcast after every x minute or something like that. – Dev4Life Jul 30 '21 at 12:47
  • @SweetDev well... I guess I could... It just seems even hackier than I'd expect. Doesn't `bindService()` kind of do that? Then again G Corp never assured all started foreground services would stay alive indefinitely, so... maybe I'll give it a try. – vesperto Jul 30 '21 at 13:17
  • Ok. give it a try and tell me if it's working. And Yes! I am using `bindService()` in my app, so try it also. – Dev4Life Jul 30 '21 at 16:18
  • neither seems to work. Are you using Android 10? – vesperto Aug 04 '21 at 10:38