为什么当进程被杀死我的Android服务得到重新启动,即使我用START_NOT_STICKY?(W

2019-08-01 01:33发布

我的应用程序使用,我开始与服务模式上下文#startService()以及绑定到它与上下文#bindService() 。 这是这样,我可以从任何客户端是否是当前绑定到其独立控制服务的生命周期。 不过,我最近注意到,每当我的应用程序被系统杀死,它很快就重新启动正在运行的任何服务。 此时,该服务将永远不会被告知停止,这也是造成电池耗尽时,它会发生。 这里有一个小例子:

我发现有人有类似的问题在这里 ,但它没有以往诊断或解决。

服务:

@Override
public void onCreate() {
    Toast.makeText(this, "onCreate", Toast.LENGTH_LONG).show();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_NOT_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    return new Binder();
}

活动:

@Override
protected void onStart() {
    super.onStart();
    Intent service = new Intent(this, BoundService.class);
    startService(service);
    bindService(service, mServiceConnection, 0);
}

@Override
protected void onStop() {
    unbindService(mServiceConnection);
    Toast.makeText(this, "unbindService", Toast.LENGTH_SHORT).show();
    super.onStop();
}

为了测试它,我推出的应用程序,它启动了服务,并绑定到它。 然后,我退出了应用程序,这解除绑定(但离开服务运行)的。 然后我做

$ adb shell am kill com.tavianator.servicerestart

果然,5秒钟后,出现“的onCreate”敬酒,表示该服务再次启动。 logcat中显示了这个:

$ adb logcat | grep BoundService
W/ActivityManager(  306): Scheduling restart of crashed service com.tavianator.servicerestart/.BoundService in 5000ms
I/ActivityManager(  306): Start proc com.tavianator.servicerestart for service com.tavianator.servicerestart/.BoundService: pid=20900 uid=10096 gids={1028}

如果我更换BIND_AUTO_CREATE的startService()模式,不会出现问题(即使我崩溃的应用程序,同时它还是绑定的服务)。 它也可以,如果我从来没有绑定到服务。 但在此,绑定和取消绑定的组合似乎从来没有让我的服务模具。

使用dumpsys查杀应用程序显示在此之前:

$ adb shell dumpsys activity services com.tavianator.servicerestart
ACTIVITY MANAGER SERVICES (dumpsys activity services)
  Active services:
  * ServiceRecord{43099410 com.tavianator.servicerestart/.BoundService}
    intent={cmp=com.tavianator.servicerestart/.BoundService}
    packageName=com.tavianator.servicerestart
    processName=com.tavianator.servicerestart
    baseDir=/data/app/com.tavianator.servicerestart-2.apk
    dataDir=/data/data/com.tavianator.servicerestart
    app=ProcessRecord{424fb5c8 20473:com.tavianator.servicerestart/u0a96}
    createTime=-20s825ms lastActivity=-20s825ms
    executingStart=-5s0ms restartTime=-20s825ms
    startRequested=true stopIfKilled=true callStart=true lastStartId=1
    Bindings:
    * IntentBindRecord{42e5e7c0}:
      intent={cmp=com.tavianator.servicerestart/.BoundService}
      binder=android.os.BinderProxy@42aee778
      requested=true received=true hasBound=false doRebind=false

Answer 1:

看看这个文件部分:服务生命周期的变化(自1.6)

更新

一些调查(已创建的项目,运行命令说明一步一步,等)后,我发现代码工作完全按“服务生命周期的变化”说明

我发现了什么:
adb shell am kill com.tavianator.servicerestart杀死什么
(尝试adb shell ,然后在外壳am kill com.tavianator.servicerestart
你将面临着错误信息Error: Unknown command: kill

所以,
运行应用程序,
运行adb shell
在壳运行ps命令
找到你的应用程序的PID号
在壳运行命令kill <app_xx_PID>
哪里是你的PID号
重复步骤查杀服务(如果它在自己的进程中运行)
检查服务是否正在运行(应该),5-7秒后重新启动
更新
一个解决方案(不够好,但在某些情况下可用)是stopSelf()例如:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();
    stopSelf();
    return START_NOT_STICKY;
}


更新
更新的解决方案

void writeState(int state) {
    Editor editor = getSharedPreferences("serviceStart", MODE_MULTI_PROCESS)
            .edit();
    editor.clear();
    editor.putInt("normalStart", state);
    editor.commit();
}

int getState() {
    return getApplicationContext().getSharedPreferences("serviceStart",
            MODE_MULTI_PROCESS).getInt("normalStart", 1);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (getState() == 0) {
        writeState(1);
        stopSelf();
    } else {
        writeState(0);
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();
    }
    return START_NOT_STICKY;
}

为什么当进程被终止服务得到restrted?

根据此文件 :

当服务启动时,它有一个生命周期中的自主启动它,服务可以在后台运行无限期的成分,即使启动它的成分被破坏。 因此,服务应停止本身时,其工作是通过调用stopSelf(完成),或其他部件可以通过调用stopService停止它()。
注意 :重要的是,你的应用程序停止其服务,当它完成的工作,以避免浪费系统资源和消耗电池电量。 如果需要的话,其它部件可以通过调用stopService停止服务()。 即使您启用服务绑定,你必须自己停止该服务,如果它曾经接到一个电话到onStartCommand()

从另一方面文件说:

* START_NOT_STICKY * - 如果系统onStartCommand()返回后杀死服务,不重新创建服务,除非有未决的意图传递。 这是为了避免运行服务时,没有必要的,当你的应用程序可以简单地重新启动任何未完成作业的最安全的选择。

所以,在阅读这份文件和一些实验后,我觉得体系将手动杀死服务,未完成(崩溃:@see W/ActivityManager(306): Scheduling restart of crashed service ),并重新启动它,尽管由onStartCommand返回值。


stopSelf()或stopService() - 不重启 ,为什么不如果完成任务?



Answer 2:

我相信这里的问题是,这是通过调用启动的服务startService()内部会计其绑定(受调用bindService() / unbindService()在某种程度上防止服务被后正确地放倒定于重新启动时,进程被终止。

根据您的喜好,似乎有三种选择,以避免此问题(你提到你的问题前两个的话):

  • 使用startService() / stopService()只,不使用bindService() / unbindService()在所有。

  • 使用bindService() / unbindService()只(含BIND_AUTO_CREATE ),不要使用startService() / stopService()在所有。

  • 如果您需要startService() / stopService() bindService() / unbindService()覆盖onUnbind()方法,在服务和呼叫stopSelf()从它:

     @Override public boolean onUnbind(Intent intent) { stopSelf(); return super.onUnbind(intent); } 

从我的测试:

  • 使用第一种选择将打印在日志中这一行:

    W / ActivityManager(NNN):在5000毫秒坠毁服务XXXX的计划重启

    但服务不会真的后重新启动。

  • 第二种选择将导致摧毁了你的服务,你(在活动的解除绑定后onStop()在你的例子)。

  • 第三种方法基本上都会使你的代码的行为像第二个选择(而无需通过太多去改变它)。

希望这可以帮助!



Answer 3:

如何重新考虑你的格局

该START_NOT_STICKY标志出现在Android的进化过程中的一些点(1.6以后?)。 最可能的是,你所面对的服务生命周期,这是当时引入了一些微妙的回归。 所以,即使同样微妙找到解决方案现在 - 和神奇验证在所有可能的设备上工作 - 它并不一定会在新的Android版本。

无论如何,生命周期模式看起来不寻常的,这可能是由于这个原因你的跑步到这个异国情调的问题。

让我们考虑两种情况。

  1. 普通(?)。 有些活动启动服务。 它获取绑定不久之后,使用未绑定 - 然后呢? 不知何故何时休? 为什么没有显著电池消耗在这种情况下?

  2. 不正常。 服务于一些(随机?)点杀。 当重新启动时,它实现了一些错误的假设,并保持活跃,做一些消耗电池电量?

这一切看起来很奇怪。

我会分析你的产品的并发进程。 所有显著案例。 一些图表等最有可能的,因此,非常需要这样的模式将被淘汰。

否则,它看起来像什么解决办法将是一个脆弱的黑客攻击。



文章来源: Why does my Android service get restarted when the process is killed, even though I used START_NOT_STICKY?