Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Still getting "Excessive network usage (background)" warning after running network code in Foreground service

Tags:

android

By referring to Proper way to tackle and resolve "Excessive network usage (background)"

After few months of debugging, we are now able to run all network related code in Foreground service.

However, we are still getting "Excessive network usage (background)" warning in Android Vital.

enter image description here

When foreground service code is executed, a notification UI will always shown in status bar area.

enter image description here

When we "quit" our app, we launch the foreground service, using WorkManager. The WorkManager will return immediately, after foreground service is launched.

public class SyncWorker extends Worker {
    @NonNull
    @Override
    public Result doWork() {
        final Intent intent = new Intent(WeNoteApplication.instance(), SyncForegroundIntentService.class);

        ContextCompat.startForegroundService(
                WeNoteApplication.instance(),
                intent
        );

        return Result.success();
    }
}

public class SyncForegroundIntentService extends IntentService {
    private static final String TAG = "com.yocto.wenote.sync.SyncIntentService";

    public SyncForegroundIntentService() {
        super(TAG);
    }

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

        final Context context = WeNoteApplication.instance();

        NotificationCompat.Builder builder = new NotificationCompat.Builder(...

        startForeground(SYNC_FOREGROUND_INTENT_SERVICE_ID, builder.build());

        // Perform networking operation within foreground service.

        stopForeground(true);

Side note

We don't think we are sending a lot of data. As you can see our latest release, we fall in the lowest range (0 - 5 MB per hour)

enter image description here


Any idea why we're still getting "Excessive network usage (background)"? Apparently, we no longer perform any networking call in background.

We utilize https://developer.android.com/reference/android/app/Service.html#startForeground(int,%20android.app.Notification) and https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)


like image 526
Cheok Yan Cheng Avatar asked Mar 04 '19 14:03

Cheok Yan Cheng


People also ask

How do I stop foreground services from activity?

To start a foreground service, call startForeground() . To stop it, call stopForeground() .

What does it mean when it says app is using foreground service?

Foreground services According to the official android documentation, a foreground service performs operations that are noticeable to the user. It shows a status bar notification, so that users are actively aware that your app is performing a task in the foreground and is consuming system resources.

How can you convert a background service to a foreground service?

Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() . This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.

What is difference between background service and foreground service?

A Background Service is a service that runs only when the app is running so it'll get terminated when the app is terminated. A Foreground Service is a service that stays alive even when the app is terminated. And a Bound Service is a service that runs only if the component it is bound to is still active.


2 Answers

You are using a Worker to invoke the ForegroundService. From the Worker's documentation:

Worker classes are instantiated at runtime by WorkManager and the doWork() method is called on a pre-specified background thread (see Configuration.getExecutor()). This method is for synchronous processing of your work, meaning that once you return from that method, the Worker is considered to be finished and will be destroyed. (...) In case the work is preempted for any reason, the same instance of Worker is not reused. This means that doWork() is called exactly once per Worker instance. A new Worker is created if a unit of work needs to be rerun.

A ForegroundService is a Service that you put in the foreground state, that means, the system will not kill the process if it needs CPU or if your app is closed. This and only that. I wasn't able to find the documentation of Android Vital proving this, so this is only my suspicion, but I'm quite positive this is the case: this means that regardless of the fact that you use ForegroundService or not, Android Vital still counts this as background work.

A proper way to move your app’s mobile-network usage to the foreground is to call DownloadManager with proper visibility setting set (as stated in the link you have provided). Please let me know if that helps - if not we'll try something different. Btw, were you able to narrow down the statistics to a specific API version? (there were some background threading changes in 9.0 and 8.0 so this can also be a clue)

like image 100
Simon Avatar answered Nov 14 '22 21:11

Simon


If you're doing this:

When we "quit" our app, we launch the foreground service, using WorkManager. The WorkManager will return immediately, after foreground service is launched.

then you're technically scheduling a worker probably with network constraints every time the user shuts the app.

From the documentation for "Excessive background network usage" link

When an app connects to the mobile network in the background, the app wakes up the CPU and turns on the radio. Doing so repeatedly can run down a device's battery

Thus, even though you're not sending the threshold data of 50MB/ 0.10% of Battery session you're getting this warning cause your app is technically waking up the CPU a lot in the background (for network pings).


Though i'm not sure if this is the problem or not, what you can do is, since even the worker documentation guide says:

WorkManager is intended for tasks that are deferrable—that is, not required to run immediately—and required to run reliably even if the app exits or the device restarts

you can try these:

  1. Scheduling a foreground service as soon as the user shuts the app, instead of scheduling a worker, checking inside the onHandleIntent whether the user is online or not (having a connection and for devices above 7, a flowing internet connection as well).

  2. You can try scheduling a worker to run periodically, lets say every few hours based on your business-side requirements, this could be problem if that's not how you wish to back-up the data, but it serves the real purpose of the worker being a deferred task and not something to be executed immediately.

  3. Not sure about this, never tried, but theoretically looks valid, you can use a Unique Work with a mode called REPLACE to replace the worker and have an initial delay of lets say 30mins, this is a hack, but this will delay running of your worker for 30mins, and in the meanwhile if the user opens and shuts the app again, it will replace the old worker with a new one. This solution has its own drawbacks as well, like sometimes the task wont be scheduled if the user is using the app constantly. But will reduce the total number of times the worker had ran.


Finally, the architecture you're using is valid, the whole thing about using a FG service and a worker to schedule it, just that you're doing it quite often. Source
like image 38
MadScientist Avatar answered Nov 14 '22 22:11

MadScientist