5

Work Manager on Chinese ROMs like Xiaomi and Oppo, when under battery optimization, increase the scheduled delay of work by several hours., however, I have noticed some apps are able to have scheduled jobs run quietly flawlessly even under battery optimization. There is one difference I noticed is that they show a notification every time the job runs, so would that be responsible for keeping the app alive by the battery optimizer?

And I also noticed, that after I force stopped that app, after 24 hours it started working again, but how is that possible? Can anyone shed any light on what is going on behind the scenes, and what method they would be using?

Let me know if there are any more details required.

Aviharsh Shukla
  • 143
  • 3
  • 12
  • Can you please check the behavior of your app in the Android emulator with a standard ROM to see how it behaves? This can allow to see if there's any problem in your app or if the issue is really with these OEM's ROMs – pfmaggi Jan 25 '20 at 09:17
  • It works fine with stock android and also when battery optimization is disabled, the jobs execute as wanted. – Aviharsh Shukla Jan 25 '20 at 11:00

5 Answers5

5

Xiomi MiUi 11 (chinese version of firmware) Work Manager very badly by default and runs in random order several times and after a few hours it just stops working.Further nothing happens. To solve the problem, I took 2 steps

1. Settings->Battery & perfomance -> App battery saver -> Select you application -> No restrictions

2. Settings -> Apps -> Permissions -> Autostart -> Add your application to autostart

After I added to Autostart and No restrictions battery. I rebooted the device and it worked correctly with Work Manager. I think that on Chinese devices that have heavily modified android, it is only possible to manually add launch permissions.

3

This is the more elaborate response. As mentioned by the others, yes work manager doesn't work properly. It may do the work with a delay. some times 15 minutes and in some cases 10 to 12 hours. There is no workaround for that. But, if you want to do a task on a specific hour and date, there is a way to do that. you should use an alarm manager, with a broadcast receiver and a foreground service.

So this is the IntentService class:

public class NotificationService extends IntentService {


//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.

public NotificationService() {
    super("NotificationService");
}

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    return START_STICKY;
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {

    sendNotification(intent);
}

private void sendNotification(Intent intent){

    Context context = NotificationService.this;

    PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);


    Notification.Builder builder = new Notification.Builder(context)
            .setTicker("Notification")
            .setContentTitle("Important Message")
            .setContentText("This is an example of a push notification using a Navigation Manager")
            .setSmallIcon(R.drawable.ic_add)
            .setContentIntent(pIntent);

    NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        String channelId = "Your_channel_id";
        NotificationChannel channel = new NotificationChannel(
                channelId,
                "Reminder to remind to review your notes",
                NotificationManager.IMPORTANCE_HIGH);
        channel.setDescription("Hello Dear friends"); //this is to test what this is
        notificationManager.createNotificationChannel(channel);
        builder.setChannelId(channelId);
    }


    Notification notification = builder.build();
    notification.flags = Notification.FLAG_AUTO_CANCEL;



    notificationManager.notify(0, notification);

}}

this is the Receiver class:

public class AlarmReceiver extends BroadcastReceiver {


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

    Log.d("SHIT","YESSSS");
    Intent service = new Intent(context, NotificationService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(service);
    } else {
        context.startService(service);
    }

}}

and this is where I set the the Alarm on a specific date:

 private void setNotificationAlarm(){
    //Alarm Manager

    Calendar time = Calendar.getInstance();

    time.set(Calendar.HOUR_OF_DAY,16);//set the alarm time
    time.set(Calendar.MINUTE, 50);
    time.set(Calendar.SECOND,0);
    AlarmManager am =( 
    AlarmManager)getContext().getSystemService(Context.ALARM_SERVICE);
    Intent i = new Intent(getActivity(), AlarmReceiver.class);
    i.setAction("android.intent.action.NOTIFY");
    PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, i, 
   PendingIntent.FLAG_ONE_SHOT);
   // am.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), 1000 * 60 * 10, 
  pi); // Millisec * Second * Minute



    if (Build.VERSION.SDK_INT >= 23){
        
  am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pi);


    }

    else{
        am.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pi);
    }

}

And of course you have to declare your Service and BroadcastRecevier in the manifest. This works like a charm.

Keivan.k
  • 548
  • 6
  • 21
  • you won't believe I had a terrible experience with Alarm Manager. No matter what I did, it never got triggered on some Chinese devices while it worked 100% on my Samsung and some other devices. I resorted to using WorkManger.. it seemed it worked for more devices but some don't still get it – Jayhymn Jan 18 '23 at 12:24
2

So, turns out the solution to keep the jobs running on time is to enable auto-start and disable battery optimization for the devices. Guiding your users to do so is inconvenient but as of now, this is what can be done!

Aviharsh Shukla
  • 143
  • 3
  • 12
1

Similar questions have best asked in the past here and here.

This has been also asked on WorkManager's issue tracker: are the Chinese manufacturers (Huawei, Oppo, Xiaomi...) supported?

To summarize: this is a known issue with some Android OEM that heavily modify this part of Android for battery optimization. There's nothing that WorkManager can do to solve this issue.

Aside having you application added to the whitelist, you can really only report the issue:

  • to the OEM (Xiaomi in this case) to avoid this kind of breaking changes.
  • to Google, to add a test in the CTS and avoid these behaviours by the OEMs. Please open an issue here to document the problem to Google.

You can take a look at the exact instruction to add to your app in a whitelist for the different devices on the amazing website don't kill my app, also I've seen this library on github that can be useful to simplify the process for your users.

pfmaggi
  • 6,116
  • 22
  • 43
  • I know, I have gone through the stack overflow answers and didn't find the answers so was content with it, but this same behavior should affect every app, there is this app called life360 and one named find my friends, with normal battery restriction settings and disabled autostart they are able to run periodically as intended, so I was just wondering how could they have overcome the limitation. – Aviharsh Shukla Jan 25 '20 at 11:08
  • The app maybe whitelisted by the OEMs by default. That is usually true for the most used app in a market, like WhatsApp and similar. As I wrote, there's nothing that WorkManager can do in these cases. Only option is to have the user to manually add your app to the whitelist. What Google can do (and it's already doing) is to explain to the the OEMs why it is important to not implement this kind of behavior. – pfmaggi Jan 25 '20 at 18:21
  • Okay, i had been experimenting with starting a foreground service from work and then scheduling another work from the service and stopping it, seems like it's working now, nearly as well as the other app. – Aviharsh Shukla Jan 26 '20 at 06:00
  • I think if there's some foreground work done, the OEM considers that important and prevents delayed suspensions. – Aviharsh Shukla Jan 26 '20 at 06:01
0

This is a known issue and, as commented in this other bug on Google's issuetracker, there's not much that WorkManager can do in these cases.if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched. Also you can try with the StartForgoundService() and until and unless your work is not done you need to show notification in forground.

haresh
  • 1,424
  • 2
  • 12
  • 18
  • Yes, I have read this, but as I mentioned apps like life360 and Find My friends, are able to get the scheduled job done on Chinese Roms, that's what's actually confusing me. – Aviharsh Shukla Jan 25 '20 at 07:57
  • Some apps are whitelisted by default by the OEMs. – pfmaggi Jan 25 '20 at 09:16
  • I checked the settings info of the app and it was also working under battery optimization mode, or where actually is this whitelisting done? – Aviharsh Shukla Jan 25 '20 at 11:01
  • I have an application that somehow managed to send notification on time. I don't know how is it doing this. It's not a famoud app though – Keivan.k Aug 21 '20 at 20:54