Android 10 滑动杀死前台服务

时间:2021-07-14 10:49:37

标签: android kotlin android-service android-10.0

背景:
第三方应用在 /sdcard/content 中生成文件。
我的应用程序应该监视文件的更改,以便它可以打印内容;因此我需要它不断运行。

问题:

  • 在 android 10 设备(阿尔卡特平板电脑)上,如果我将所有应用程序刷掉,该服务将被终止
  • 在另一台 android 10 设备(我无权访问)上,如果该应用程序未聚焦,即用户正在使用另一个应用程序,则它不会监视该文件。如果用户切换回我的应用,它会再次开始监控。

在升级到 10 (Galaxy A20e) 的 android 9 设备上,该服务不会被终止。


在我的主要活动中,我有一个微调器,当调用 onItemSelected 时,我启动服务(如果它尚未启动)并绑定到它:

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)
}

如果您想将其作为前台服务启动,我认为您不需要绑定到服务。

我看到了通知。如果我更改微调器选择,它会更新。
我看到调用了 MyService 的 onStartCommand
我看到调用了 MyActivity 的 onServiceConnected,以及 MyService 的 onBind

MyService 的 onStartCommand 作用如下:

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 是存储最持久数据的类(它 : Application())。

这是我的清单:

<?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>

由于 android 10 上的存储权限,我将标记为 19/21。


我尝试使用 PowerManager 无济于事。 WakefulReceiver 排除了我没有使用的 IntentService,因为它会在处理 Intent 后终止。我没有注意到任何 battery optimization 问题,因为我已经禁用了所有我能找到的。 WorkManager 有一个 15m minimum retry time 这使得它无用于此目的。使用 separate process 也不起作用,我丢失了我发布的信息 到通知。

我是否遗漏了一些明显的东西?音乐应用可以做到...


编辑 1

对于阿尔卡特,我在日志中看到的最后一个操作是当我点击主页按钮时调用 MyActivityonPause()。我刷的时候没有反应。
对于三星,当我滑动时,我看到

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

如果我检查服务 is foreground,它显然在两个设备上都不是,但是,adb 会说相反。

三星

* 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}

阿尔卡特

* 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}

vis=PRIVATE 之后有区别,仅此而已。


编辑 3

在大多数情况下,该服务似乎在前台运行。

我还在服务的 Binder 中实现了一个方法,该方法只是等待随机时间(1-2 秒)并返回等待时间。
反过来,这由线程内的绑定类(我的 : Application())使用,该线程在调用 Binder 方法之前等待 3-4 秒。
这样我每 3 秒左右就会获得一次“服务器/客户端”交互,但是如果我滑动所有应用程序,该应用程序仍然会在 Android 10 上被杀死。


编辑 4

我还通过 filter.addAction() 在我的 Activity 中注册了很多随机广播,以尝试使其保持活动状态。我使用过 filter.addAction(Intent.ACTION_TIME_TICK) 但滑动总是会杀死应用。
这意味着日志停止,没有 onMethod (我已经覆盖)被调用;通知不见了;该服务不再运行。

1 个答案:

答案 0 :(得分:0)

使用 startForeground(id, notification);

我希望它能在我的一个应用中正常工作。