谁杀了我的服务?

Ruc*_*nia 7 testing algorithm service android adb

我已经阅读了关于这个主题的每个Stackoverflow答案,但它们都没有奏效.

目标:始终保持我的服务全天候运行

问题:每当我的设备处于睡眠模式一小时或更长时间时,服务就会被终止


我试图解决它:

  • 返回START_STICKYonStartCommand()使用startForeground()

        public int onStartCommand(Intent intent, int flags, int startId) {
    
            notification = makeStickyNotification(); //I've simplified the irrelevant code, obviously this would be a real notification I build
    
            startForeground(1234, notification);
            return START_STICKY;
            }
    
    Run Code Online (Sandbox Code Playgroud)

这样工作正常,它甚至可以在设备内存不足时重新启动我的服务,但这还不足以解决我的设备暂停一段时间后出现的问题.

  • onCreate()我的Activity和onStartCommand()我的服务中使用Alarm Manager 来调用调用我的服务的广播接收器

            Intent ll24 = new Intent(this, AlarmReceiver.class);
    
            PendingIntent recurringLl24 = PendingIntent.getBroadcast(this, 0, ll24, PendingIntent.FLAG_CANCEL_CURRENT);
    
            AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    
            alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000*60, recurringLl24); // Every minute
    
    Run Code Online (Sandbox Code Playgroud)

这有助于保持我的服务活跃,但同样,不能解决我的问题

  • 使用Schedule Task Executor使其保持活动状态

     if (scheduleTaskExecutor == null) {
    
            scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
    
            scheduleTaskExecutor.scheduleAtFixedRate(new mainTask(), 0, 1, TimeUnit.SECONDS);
    
        }
    ...    
    class mainTask implements Runnable {
    
    public void run() {
        // 1 Second Timer
       }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这也只是使服务保持活动状态,但在长时间睡眠后不会保持活动状态.

  • 单独的任务清单

    android:launchMode="singleTop"

这没什么

我怎样才能(1)测试这个问题,而不必让我的手机进入睡眠状态并每小时检查一次,以及(2)尽管设备进入睡眠状态仍然保持我的服务正常运行?

Khe*_*raj 15

您的服务被Android的Doze或待机模式杀死.这是在Android 6.0(API级别23)中引入的.

打盹限制

在Doze中,以下限制适用于您的应用:

  • 网络访问被暂停.
  • 系统忽略唤醒锁定.
  • 标准AlarmManager报警(包括setExact()setWindow())将推迟到下一个维护窗口.
  • 如果您需要设置在Doze中触发的警报,请使用setAndAllowWhileIdle()setExactAndAllowWhileIdle().
  • 设置的警报setAlarmClock()继续正常启动 - 系统在警报触发前不久退出Doze.
  • 系统不执行Wi-Fi扫描.
  • 系统不允许同步适配器运行.系统不允许JobScheduler运行.

所以系统忽略你的Alarm Clocks, Scheduler等等

Android Oreo发布Android中定义了后台服务的限制.

为了改善用户体验,Android 8.0(API级别26)对应用程序在后台运行时可以执行的操作施加了限制.

如果应用程序需要始终运行其服务,那么我们可以创建前台服务.

后台服务限制:当应用程序处于空闲状态时,其后台服务的使用受到限制.这不适用于前景服务,这对用户来说更加明显.

所以创建一个前台服务.在服务运行期间,您将在其中为用户发出通知.看到这个答案(还有很多其他的)

现在如果您不想要服务通知怎么办?解决方案就是这样.

您可以创建一些定期任务来启动您的服务,服务将完成其工作并自行停止.这样您的应用程序将不被视为电池耗尽.

您可以使用Alarm Manager,Job Scheduler,Evernote-JobsWork Manager创建定期任务.

我使用Work-Manager创建了永远运行的服务,这是完美的.


Ruc*_*nia 6

谋杀之谜已经解决,我知道是什么扼杀了我的服务.这是我做的:

  1. 之后我意识到startsticky,startforeground,alarmmanager,scheduleTaskExecutor,甚至 wakelock无法拯救我的服务,我意识到凶手不可能是Android系统,因为我已经采取了一切可能的措施,以防止系统杀死我的服务,它仍然会被打死.
  2. 我意识到我需要寻找另一个嫌疑人,因为该服务并没有因为系统而死亡.为此,我不得不进行调查.我运行了以下命令:

    adb shell dumpsys activity processes > tmp.txt

这将为我提供所有正在运行的进程及其系统优先级的详细日志.从本质上讲,tmp.txt将是这个谋杀之谜中的侦探.

  1. 我仔细查看了文件.看起来系统正确地优先处理了我的服务:

    Proc #31: adj=prcp /FS trm= 0 2205:servicename.service/uID (fg-service)

以上行表示在Android设备上运行的进程的确切优先级.adj=prcp表示该服务是可见的前台服务.

此时,我意识到我的服务必须在运行几个小时后遇到一些错误,所以我让它运行并死亡.它死后,我dumpsys再次制作了一个来检查错误:

  1. 此时,我的服务未在tmp.txt文件中列为任务.兴奋,我滚动到底部dumpsys,解开了神秘面纱!

com.curlybrace.ruchir.appName.MyService $ 2.onForeground(MyService.java:199)at com.rvalerio.fgchecker.AppChecker $ 2.run(AppChecker.java:118)at android.os.Handler.handleCallback(Handler.java: 751)在android.os.Handler.dispatchMessage(Handler.java:95)的android.app.Looper.loop(Looper.java:154)在android.app.ActivityThread.main(ActivityThread.java:6123)的java.来自com.android.internal.os.ZygoteInit.main的com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:867)中的lang.reflect.Method.invoke(Native Method)(ZygoteInit.java:757 )

导致我的服务被杀的堆栈跟踪就在那里显示了!从本质上讲,检查正在使用的前台应用程序的变量将在几个小时不活动后变为空,这将导致异常,并终止服务!

关键要点: 如果您的服务被杀,并且您已经尽了一切可以确保它不会被杀死,请执行dumpsys并检查设备活动过程的细节.我保证你会发现这个问题.

我仍然希望将奖金授予@Khemraj,因为对于那些没有正确开始服务的人来说,他的答案可能是一个很好的解决方案.但是,我接受这个答案,因为它是实际解决问题的解决方案.

  • :D,痛苦电影的有趣故事。谁杀死了我的服务? (2认同)