This is an issue with the com.google.android.location.ALARM_WAKEUP_LOCATOR waking up devices every 60 seconds and keeping them awake for up to 15 seconds, causing major battery drainage issues.
There's been fixes for phone uses via external apps and teaching users how to actually revoke permission for an app.
The Solution
The following provides the tools to reduce the battery usage of the app.
It's impossible to provide a customised solution for the app, as the solution depends upon the use case and business logic of the app and a cost benefit analysis of what you wish to achieve with the location updates.
Time intervals
It's no surprise there's battery performance issues. From the following settings:
mLocationRequest.setInterval(5 * 60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setMaxWaitTime(30 * 60000);
Your interval is set to update every 5 minutes (5 * 60000ms). That's 24 hours a day. If this updates successfully every 5 minutes: 12 times/hour == 288 times per day.
The fastest interval being set at 1 minute (60000). Although that is available because location is accessed elsewhere on the device, it will still use power in your app).
The maxwaittime is only 30 minutes. Which means at best the device will be woken up and polled a minimum of 48 times per day.
Increase these times.
setMaxWaitTime ... This can consume less battery and give more accurate locations,
depending on the device's hardware capabilities. You should set this
value to be as large as possible for your needs if you don't need
immediate location delivery. ...
In Android 8 Google has limited the number of requests to only a few per hour. Consider using this as a guideline in setting intervals for requests.
Limiting number of updates
The number of updates within a certain time frame can be limited. By either actively cancelling the location request once the number of updates have been used or setting an expiration on the request. This way the app can be managing by creating a request on some trigger within the app and carefully managed so that it doesn't continue endlessly. It's difficult to create a flow, as I don't know the use case for the app.
setNumUpdates (int numUpdates)
By default locations are continuously updated until the request is
explicitly removed, however you can optionally request a set number of
updates. For example, if your application only needs a single fresh
location, then call this method with a value of 1 before passing the
request to the location client.
Stop location updates
Another option is to manage stop locations updates when they are not required. The links gives examples of calling this when an activity loses focus, however it could be implemented within the app, when certain requirements are met (that's within your business logic) or even by giving the user to turn it on and off from within the app itself.
Battery optimisation
Ensure your app is not ignoring battery optimizations.
Displacement
Also managing setSmallestDisplacement (float smallestDisplacementMeters) will help to fine tune the app, depending on the business logic.
the following was written before the updated question.
How often the app updates can be set by both the developer and the user. The intervals and priorities.
You can set these when making a location request for example:
protected void createLocationRequest() {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
There is also a setting for PRIORITY_NO_POWER, which means the app will only get updates when the user asks for them.
For the user.
You will need to Prompt the User to Change Location Settings
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case CommonStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way
// to fix the settings so we won't show the dialog.
break;
}
}
});
To manage changes in user setting use a location call back.
... you can use the new LocationCallback class in place of your existing
LocationListener to receive LocationAvailability updates in addition
to location updates, giving you a simple callback whenever settings
might have changed which will affect the current set of
LocationRequests.
Google has addressed this issue in Android 8.
In an effort to reduce power consumption, Android 8.0 (API level 26)
limits how frequently background apps can retrieve the user's current
location. Apps can receive location updates only a few times each
hour.
Note: These limitations apply to all apps used on devices running
Android 8.0 (API level 26) or higher, regardless of an app's target
SDK version.
If using the Alarm Manager.
This can be related to the Alarm Manager.
It's not a simple fix, ultimately you'll need to rewrite how you are scheduling your updates.
To at least slow down the problem you'll need to debug your code and find any instances where the Alarm Manager calls or creates schedules and reduce the intervals.
After that you will need to rewrite the entire location update scheduling part of the app.
Fix the Problem
Identify the places in your app where you schedule wakeup alarms and
reduce the frequency that those alarms are triggered. Here are some
tips:
- Look for calls to the various set() methods in AlarmManager that include either the RTC_WAKEUP or ELAPSED_REALTIME_WAKEUP flag.
- We recommend including your package, class, or method name in your alarm's tag name so that you can easily identify the location in your
source where the alarm was set. Here are some additional tips:
- Leave out any personally identifying information (PII) in the name, such as an email address. Otherwise, the device logs _UNKNOWN
instead of the alarm name.
- Don't get the class or method name programmatically, for example by calling getName(), because it could get obfuscated by Proguard.
Instead use a hard-coded string.
- Don't add a counter or unique identifiers to alarm tags. The system will not be able to aggregate alarms that are set that way
because they all have unique identifiers.
After fixing the problem, verify that your wakeup alarms are working
as expected by running the following ADB command:
adb shell dumpsys alarm
This command provides information about the status of the alarm system
service on the device. For more information, see dumpsys.
If you have particular issues with any of the above, you'll need to post another question with an mcve.
To improve the app, it would involve rewriting the code as mentioned here in Best Practices. Don't use the alarm manager to schedule background tasks, and location would be considered a background task, if the phone is asleep. Plus you say it's a background task. Use JobScheduler or Firebase JobDispatcher.
If the Alarm Manager is the better choice (which it's not here) it's important to have a good read here Scheduling Repeating Alarms, but you need to Understand the Trade-offs
A poorly designed alarm can cause battery drain and put a significant load on servers.