2

My Alarm App keeps being late, although I'm starting a ForegroundService from the BroadcastReceiver and the onCreate() of the Service gehts called in time, but the onStartCommand() is called with delay (sometimes), which I assume is coming from the phone falling into doze again before it can execute it...

As You can see from Log.d the Service is started in time and is calling the PlayerActivity in time - but this one is actually starting 1:40min later in this case. Plus the Service does not enter foreground and does not start streaming music before that random delay time has passed (maintenance window?)

How are we supposed to keep a device awake long enough to actually start the foreground service AND ENTER FOREGROUND in time?

I'm using setExactAndAllowWhileIdle() to call the AlarmReceiver - this works for a 100% of the cases perfectly. The delay happens after starting the service.

Should I start the service 15 minutes earlier to ensure it has entered foreground by the actual alarm time and actually start streaming music and calling the Activity at the avtual alarm time?

BroadcastReceiver

public class AlarmReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    Log.d("Ben", "Alarmreceiver HELLO");

    String label = context.getText(R.string.defaultLabel).toString();
    int id = 1909;

    Bundle extras = intent.getExtras();

    if (extras != null) {

// kill running alarm activity
        if (extras.containsKey("autoKill")) {

            Log.d("Ben", "AlarmReceiver killing running alarm NOW.");

            Intent bc = new Intent("PLAYER_STOP_SELF");
            LocalBroadcastManager.getInstance(context).sendBroadcast(bc);

            context.stopService(new Intent(context, StreamService.class));
            return;
        }

        label = extras.getString("label");
        id = extras.getInt("id");
    }

    Log.d("Ben", "AlarmReceiver ok!");


// CALC NEXT ALARM and start StreamingService...

    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(new Intent(context, StreamService.class));
        context.startForegroundService(new Intent(context, CalcNextAlarmService.class));
        Log.d("Ben", "SDK >= 26 *** context.startForegroundServices");
    }
    else {
        context.startService(new Intent(context, StreamService.class));
        context.startService(new Intent(context, CalcNextAlarmService.class));
        Log.d("Ben", "SDK < 26 *** context.startServices");
    }
}

Service

@Override
public void onCreate() {


// initializing variables, shared preferences,... not shown

    Log.d("Ben", "StreamService calling PlayerActivity now...");

    startActivity(new Intent(this, PlayerActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

// NOTI AND FOREGROUND!
    Notification noti = createForegroundNotification();
    startForeground(ntfctnId, noti);
// It doesn't even get to here before the delay...
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d("Ben", "StreamService onStartCommand");

The according Log.d:

07-14 14:30:01.335 D/Ben: Alarmreceiver HELLO
07-14 14:30:01.364 D/Ben: AlarmReceiver ok! (label: Alarm 1 - id: 10001)
07-14 14:30:01.372 D/Ben: SDK < 26 *** context.startServices
07-14 14:30:01.378 D/Ben: StreamService calling PlayerActivity now...
07-14 14:31:41.116 D/Ben: StreamService onStartCommand
07-14 14:31:41.224 D/Ben: StreamService wakeLock.isHeld()
    StreamService wifiLock.isHeld()
    *** onStartCommand ELSE ***
07-14 14:31:41.227 D/Ben: preparing player - start streaming in 2 seconds...
07-14 14:31:41.365 D/Ben: wakeLock.isHeld()
    wifiLock.isHeld()
07-14 14:31:41.366 D/Ben: PlayerActivity.onCreate()
07-14 14:31:43.229 D/Ben: Start Streaming now! (normal alarm)
07-14 14:31:43.241 D/Ben: buffering
07-14 14:31:43.242 D/Ben: buffering
07-14 14:31:44.345 D/Ben: ready

The alarm works great in 95% of the used times, but SOMETIMES this dozing appears and starts the alarm 1-15 minutes late - I've been debugging this for more than 2 weeks now, rewrote the whole service and Receiver classes 2 times and start getting crazy, please help.

EDIT

I ended up using a wakeful BroadcastReceiver and a wakeful service (for all API < 26) which then takes care of calling the other services accordingly (what I did in the AlarmReceiver before - and still do for API >= 26)

So far it seems working fine - only on one of my test devices with Lineage running the alarm goes off late sometimes, on my own daily-use-phone I'm running Lineage too, but there it's just doing fine. Maybe the SGS 4 mini is just too old (I don't really believe this, but as long nobody complains I'll have to assume it's working as expected for them)

Thanks for your help @Elletlar.

Ben
  • 265
  • 3
  • 13
  • Doze does not help. But this implementation will not work on pre-doze devices either because startService can sleep before onStartCommand is called on those devices as well. On pre API 22 devices, it is handled by acquiring a static partial Wakelock in a BroadcastReceiver and releasing it from the service. For API 22 - 25 devices it is handled by using a WakefulBroadcastReceiver. If you read the bottom section of this document it will explain the improvements that need to be made for your pre-26 implementation: [Keep Device Awake](https://developer.android.com/training/scheduling/wakelock) – Elletlar Jul 14 '18 at 19:16
  • Now for 26+ doze devices.It might be good if your service is in a separate process. This is standard practice for Google apps because it prevents the resources for the UI from being loaded into memory and bloating the service process, but it also caused Google to miss a serious defect on some devices which is that foreground services that run in the main process can be dozed. – Elletlar Jul 14 '18 at 19:37
  • The important parts for the 26+ implementation are: 1. "When the alarm is dispatched, the app will also be added to the system's temporary whitelist for approximately 10 seconds to allow that application to acquire further wake locks in which to complete its work." 2. The minimum interval between 2 doze alarms is typically ~9 minutes. [Doze mode handling](https://stackoverflow.com/questions/41485308/doze-mode-handling) – Elletlar Jul 14 '18 at 19:45
  • This might be useful regarding startForegroundService [startForegroundService did not call startForeground](https://stackoverflow.com/questions/50347101/startforegroundservice-did-not-call-startforeground-but-it-did), must have a notification channel and non zero ID. – Elletlar Jul 14 '18 at 21:56
  • Thanks for the details. I read about the separate process, but wasn't sure how to do it, I was about to specify it in the manifest, but am I completely free in choosing a process name? Didn't find a useful answer via Google. Different package name? Can I use "mySeparateProcess" as process name and will that be it? --- Pre doze devices work perfectly for me than 7 months now, I think I leave them out and change things only for Android 6+ --- wanted to avoid wakeful BR, because of deprecation, but will give it a try now for sdk 22-25. – Ben Jul 15 '18 at 10:22
  • Android 8+: the foreground notification has a correct id and a channel. So everything is good to go as is on Android 8+? (The delay was noticed on an Android 7 device, don't have a real 8 device. Because I acquire wakelocks in onStartCommand, which should be done within 10 seconds easily) -- Will I need further changes on Android 8+? – Ben Jul 15 '18 at 10:27
  • And one more question regarding WakefulBroadcastReceiver: Can I use my foreground service **as is** when I only call a different (wakeful) broadcast receiver on 22-25? Or should I then rather use an IntentService and startWakfulService? – Ben Jul 15 '18 at 10:35
  • You can definitely call the process anything you like because I recently inherited a project using a service process name of 'whatever' which I quickly changed, but the standard default name android:process=":remote". But the process name can be seen by users when they go into the settings so it is probably best to pick one they may understand. I think the gotchas with processes are not to create too many because even an empty process uses up a substantial amount of the app's memory quota. The other thing is that SharedPreferences becomes difficult because it is not safe across processes. – Elletlar Jul 15 '18 at 11:45
  • To be honest, I'm really not sure. My concern is that if you just call startService on those older devices you'll run into the problems that the WakefulBroadcastReceiver is meant to solve. But at the same time I don't want to encourage you to use a deprecated component if it isn't necessary. There is also ContextCompat.startForegroundService which doesn't have the best documentation, but I suspect it might just call 'startService' on older devices. – Elletlar Jul 15 '18 at 13:15
  • Another thing that worries me, calling startForegroundService service twice. I wouldn't trust the framework to be able to handle that. I schedule my alarms in the main service, but in a separate class: 'Scheduler' for example. – Elletlar Jul 15 '18 at 13:20

0 Answers0