START_STICKY在Android KitKat上不起作用

START_STICKY在Android KitKat上不起作用,android,android-service,sticky,Android,Android Service,Sticky,我的一个应用程序有一个后台服务,它使用START\u STICKY从onStartCommand返回代码,在系统终止时自动重新启动。 这似乎不再适用于Android KitKat。 有什么解决办法吗? 我应该在Kitkat上做些不同的事情来保持服务运行吗 注意:Android开发者组也有类似的讨论,讨论从最近的应用列表中刷取应用。这两个问题是否相关? 编辑:看到Android问题跟踪器上存在开放的bug: Edit2:即使服务在单独的进程中使用startForeground运行,并且在An

我的一个应用程序有一个后台服务,它使用
START\u STICKY
onStartCommand
返回代码,在系统终止时自动重新启动。 这似乎不再适用于Android KitKat。 有什么解决办法吗? 我应该在Kitkat上做些不同的事情来保持服务运行吗

注意:Android开发者组也有类似的讨论,讨论从最近的应用列表中刷取应用。这两个问题是否相关?

编辑:看到Android问题跟踪器上存在开放的bug:

Edit2:即使服务在单独的进程中使用
startForeground
运行,并且在AndroidManifest.xml文件中使用标记
android:stopWithTask=“false”
,也会发生同样的情况

Edit3:Android问题跟踪器上的更多相关bug:


是否有某种解决方法来获得以前的行为?

似乎这是Android 4.4中存在的一个bug,通过以下方法解决了它:

@Override
public void onTaskRemoved(Intent rootIntent) {
    Intent restartService = new Intent(getApplicationContext(),
            this.getClass());
    restartService.setPackage(getPackageName());
    PendingIntent restartServicePI = PendingIntent.getService(
            getApplicationContext(), 1, restartService,
            PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);

}
I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task

中找到此答案此处的问题似乎不会发生在基于AOSP的ROM上。也就是说,我可以很容易地在基于CyanogenMod 11的ROM上重新创建它,但在AOSP ROM(和模拟器)上,START_STICKY的行为完全符合我的预期。这就是说,我看到Nexus5上的人的报告似乎看到了这种行为,所以这可能仍然是AOSP中的一个问题

在模拟器和AOSP ROM上,当我对进程执行“kill 5838”时,我从logcat中看到以下内容(如我所料):

如果通过从“最近的任务”列表中“滑动”结束任务,我会看到相同的重新启动行为。所以这一切都是好的——这意味着核心AOSP代码的行为与以前的级别一样

我正在查看Cyanogenmod服务代码,试图找出为什么事情没有按计划重新启动-还没有运气。看来它应该重新安排时间。Cyanogenmod使用AOSP没有的服务地图-但不清楚这是否是一个问题(可疑)

您可以做的一个相当黑客的解决方法是使用与onTaskRemoved AlarmService类似的机制,在X分钟后启用警报。然后,当你的应用程序启动并运行时,每隔几分钟,你就可以重置警报——因此只有当事情真的被终止而没有重新启动时,警报才会熄灭。这并不是万无一失的——与使用实时的报警服务相比,使用处理程序可以为您提供正常运行时间,因此,即使您的报警设置的时间比“重置”处理程序长,也有可能触发报警。但是如果您设置了一个额外的intent,那么如果您的服务已经启动并运行,您可以选择忽略onstart命令,从而将其变成noop

我一点也不喜欢下面的黑客程序——但它不应该造成任何真正的伤害。如果用户执行显式强制关闭,则报警管理器将销毁所有设置的报警,以便服务不会重新启动(这是用户想要的)

首先,创建一个helper方法,该方法将设置20分钟的警报,从而触发服务的onStartCommand。每2分钟配备一个处理器,该处理器将重置20分钟警报。如果处理器在实时20分钟内运行,警报将永远不会发出。如果设备处于休眠状态(这很好),则不能保证处理程序运行

在onCreate中,可以调用此方法。另外-在onstart命令中,如果您的服务已经启动并正在运行,请确保忽略此选项。例如:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    ...
    if ((intent != null) && (intent.getBooleanExtra("ALARM_RESTART_SERVICE_DIED", false)))
    {
        Log.d(TAG, "onStartCommand after ALARM_RESTART_SERVICE_DIED");
        if (IS_RUNNING)
        {
            Log.d(TAG, "Service already running - return immediately...");
            ensureServiceStaysRunning();
            return START_STICKY;
        }
    }
    // Do your other onStartCommand stuff..
    return START_STICKY;
}

这不是一个100%有效的解决方案,但它是迄今为止最好的,因为它几乎完全消除了问题。到目前为止,我集成了此解决方案以及覆盖
onTaskRemoved
(请参阅)和保持活动状态通知(请参阅)。 额外的答案非常感谢

经过进一步的调查,这个bug似乎已经存在于Jelly Bean中,并且看起来有一个解决方案(至少在我的案例中是这样的。如果需要,我们将继续测试并更新答案)

据我观察,这种情况只发生在接收由
AlarmManager
设置的广播的服务上

要复制错误,请执行以下步骤:

  • 启动应用程序
  • 从应用程序中启动前台服务(使用
    startForeground
  • 从“最近的应用”列表中滑动应用
  • 发送由服务处理的广播
  • 服务被杀了 使用
    adb shell dumpsys>C:\dumpsys.txt
    可以监视不同步骤之间的服务状态。(在dumpsys输出中查找
    处理LRU列表
    ) 在步骤2和3中,您将看到如下内容:

    Proc # 2: prcp  F/S/IF trm: 0 11073:<your process name>/u0a102 (fg-service)
    
    @Override
    public void onDestroy() {
    Intent intent = new Intent("restartApps");
    sendBroadcast(intent);
    super.onDestroy();
    stopThread();
    }
    
    导致这种行为的原因似乎是,接收到的广播将服务从前台状态移出,然后被终止

    为了避免这种情况,在为
    AlarmManager
    创建
    PendingEvent
    时,您可以使用此简单解决方案(来源:)

    请注意以下步骤:

  • 在intent上调用addFlags并使用
  • 在PendingEvent.getBroadcast中使用非零请求代码
  • 如果你离开这些步骤中的任何一个,它都不会起作用

    请注意,这个错误是在API 16(Jelly Bean)上添加的,所以当这个错误第一次出现时就有意义了

    最有可能的是KitKat在杀死进程时更具攻击性,这就是为什么KitKat强调了这一点,但看起来这已经与果冻豆有关

    注意2:注意问题中关于服务配置的详细信息-作为前台服务在单独的进程中运行,清单中的endWithTask设置为false

    注3:当应用程序收到
    android.appwidget.action.appwidget\u CONFIGURE
    消息并显示新小部件的配置活动时,也会发生同样的情况(将上面的步骤4替换为创建新的widge)
    I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task
    
    AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent("YOUR_ACTION_NAME");
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 0);
    
    public class RestartService extends BroadcastReceiver {
    
    private static final String TAG = "RestartService";
    
    public RestartService() {
    }
    
    @Override
    public void onReceive(Context context, Intent intent) {
    Log.e(TAG, "onReceive");
    context.startService(new Intent(context, YourService.class));
    }
    }
    
    <receiver
        android:name=".RestartService"
        android:enabled="true" >
        <intent-filter>
            <action android:name="restartApps" />
        </intent-filter>
    </receiver>
    
    @Override
    public void onDestroy() {
    Intent intent = new Intent("restartApps");
    sendBroadcast(intent);
    super.onDestroy();
    stopThread();
    }