I have built an online clock radio for Android which also features an integrated music player that works as a foreground service with notification, and it has its own wakelocks - acquiring when service is started and releasing when the user presses "stop" and finishes the service.
Now I get a warning about hanging partial wakelocks for this app in Google Developer Console. It's absolutely correct to receive this warning, because if someone keeps listening to music for a longer period of time, then also the wakelocks (wifi-manager and power-manager) will be held as long as needed to keep the music playing when the screen is off.
The app works perfectly and plays for hours when the screen is off and/or in power save mode - exactly as intended.
Also:
In Developer Guidelines and best practices they state:
If you must use partial wake locks, follow these recommendations:
Make sure some portion of your app remains in the foreground. For
example, if you need to run a service, start a foreground service
instead. This visually indicates to the user that your app is still
running.
Make sure the logic for acquiring and releasing wake locks is as simple as possible. When your wake lock logic is tied to complex state
machines, timeouts, executor pools, and/or callback events, any subtle
bug in that logic can cause the wake lock to be held longer than
expected. These bugs are difficult to diagnose and debug.
I think I have taken care of this.
They tell me in dev console where the warning appears:
Keep in mind that for some apps, longer wakelocks are required to enable key features such as music streaming.
Due to that I believe everything is fine, but since the warning for "bad behavior" is still shown I would like to get advice.
The questions are:
Can I do anything to avoid getting this warning?
Will I have to fear "punishment" by Google for my app showing "bad behavior" although it's working correctly?
Streaming-service (partial) code:
#Override
public void onCreate() {
...
// WAKE LOCK && WIFI LOCK
powerManager = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag");
wakeLock.acquire();
wMgr = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, "MyWifiLock");
wifiLock.acquire();
...
// notification gets built
...
startForeground(ntfctnId, buildNotification(standardNoti));
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// player here...
...
#Override
public void onDestroy() {
...
// RELEASE WAKE LOCK && WIFI LOCK
wakeLock.release();
wifiLock.release();
...
I have not noticed anything negative - neither from Google, nor users, nor anything or anyone else.
Everything is just fine. If wakelocks cannot be avoided - and that's clearly the case for music apps - you do not need to fear any related warnings about this in the Developer Console.
Related
It seems there are a few questions related to the subject topic but I haven't found a clear yes/no answer to this.
I have a foreground service that calls setExactAndAllowWhileIdle to start a BroadcastService. Below is the code in the Broadcast Receiver.
public class StepCountUpdaterAlarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myExampleApp::UpdateSteps");
wakeLock.acquire(3);
StepCounterHandler handler = StepCounterHandler.getInstance();
new TaskRunner().executeAsync(
new SetStepsForDay(SaveSharedPreference.getMemberId(context),
handler.getCumulativeSteps()),result -> {
handler.setAlarm(context);
if(isTimeToReset())
handler.resetStepsCounter();
});
wakeLock.release();
}
In the setExactAndAllowWhileIdle documentation it states:
When the alarm is dispatched, the app will also be added to the
system's temporary power exemption list for approximately 10 seconds
to allow that application to acquire further wake locks in which to
complete its work.
but in the Doze mode documentation it states this as a restriction:
The system ignores wake locks.
Does that mean acquiring a partial wake lock for 3 minutes in the 10 second window provided by an alarm dispatched by setExactAndAllowWhileIdle in Doze mode will effectively be useless or will it work fine?
In my case, the Broadcast Receiver will send data to my remote server via that async task, and after that it will set the alarm again and reset my steps counter. Will this work and if it wont, what are my alternatives for sending a network request in doze mode and executing follow up code?
EDIT: Testing by debugging my app shows that when forcing a device into idle mode, i still have network access and can send data to my server. The Doze mode documentation states how to force to app into the idle state which i am fairly sure is synonymous with doze mode. Yet this is supposed to be a restriction so I am clueless as to how this could be working.
A WakeLock won't help you much if the device is in Doze mode. setExactAndAllowWhileIdle will wake your device up if you have used either AlarmManager.ELAPSED_REALTIME_WAKEUP or AlarmManager.RTC_WAKEUP as the alarm type.
However, from Android 12 you need SCHEDULE_EXACT_ALARM permission to set exact alarms. And if you are planning to release the app to PlayStore there are some acceptable use cases for setting an exact alarm. Make sure your app complies with these policies.
Yes, Doze will ignore your wakelock. However with setExactAndAllowWhile Idle you will be worken up at the correct time, and you'll have that 10s window to do any processing you wish.
I have some questions concerning wake lock and services
1- I try to test my service when the screen is off and not acquiring the wake lock, i was expecting that system will kill my service but it didn't happen, so what is the purpose of wake lock?
2- I want to know when then the system goes into doze mode, is it when i turn off the screen or after some time of turning it off? and what happens to my service in this case? and how to know that the system is in doze mode?
3- I know that since Android O normal background service will be killed after nearly one minute, i tried to test that by making intent service and make it running for more than one minute, it was already killed but started again and continued execution, so what is the purpose of killing it and starting it again?
4- does doze mode affect foreground service? and should i acquire wake lock in case of foreground service or is it acquired by default?
Code of Intent service
Logcat
I know they are lots of questions but i am confused with these topics
thanks in advance
The device may fall asleep if the user is inactive and nothing is keeping the device awake. A WakeLock is used to ensure the device stays awake.
You may check those links for additional information: Good answer Official Documentation
Information about Doze mode, Standby and some other things that you may be interested in:
link
Background Service Limitations: While an app is idle, there are limits to its use of background services. This does not apply to foreground services, which are more noticeable to the user.
link
Processes which have a current running foreground service are supposed to be unaffected by Doze. Bound/unbound, started/not-started, and wakelocks do not affect this whitelisting process.
link
--- Update ---
Some things could change from the moment of those questions were asked, so prefer to read documentation or search for the actual information about it. Also it's a good idea to check information about modern solutions for back ground like WorkManager.
My audio streaming app is working correctly with only WifiLock.
But some devices report that when they turn off the screen, connection is cut and audio streaming is topped. (They say this does not happen on 3G)
So, I thought maybe I can also use a Partial WakeLock. I am not sure if this fixes the issue but I think it is an option. At the same time, adding a WakeLock while a basic WifiLock is working may deplete the battery faster and may not fix the issue.
What do you think about adding a WakeLock too for this kind of issue and app?
private static WifiLock wifiLock = ((WifiManager) appInstance().getSystemService(Context.WIFI_SERVICE))
.createWifiLock((android.os.Build.VERSION.SDK_INT>=12?WifiManager.WIFI_MODE_FULL_HIGH_PERF:WifiManager.WIFI_MODE_FULL), "myappwifilock");
The newly added line:
private static WakeLock wakeLock= ((PowerManager) appInstance().getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myappwakelock");
(ofcourse I acquire and release these locks on the creation of the service and on the destruction of it.)
Use them both. The behavior I am sure varies from phone to phone. You may wish to search for the devices the reports are about + "wifi"or "wifi driver". Are you sure your audio streaming app is working correctly with only WifiLock ? This sounds very strange - the CPU will go to sleep and the service will stop - see Service, WakeLock. Something else is keeping the phone awake. So you need a wake lock
If you only use wake lock on the other hand the wifi will turn off maybe - I am not sure for you are using it - but better safe than sorry. If it does turn off waking the phone up won't wake it up - for this I am sure. Using the wifi lock has no impact on the battery - using the wifi radio has, and this you are doing anyway.
So both - and be sure your service acquires them - have a look at WakefulIntentService
I am bit confused after going through the questions & answers in Stackoverflow about WakefulIntentService. I just would like to get some knowledge on this topics to make sure my understanding is correct, please feel free to correct me, if I am wrong.
I built a small application, where I am using a background Service that keeps playing music whenever the user shakes the mobile. I tested after the device is locked and screen is turned off and it works as expected.
What I am hearing from this forum, the service might turn off as soon the device goes to asleep. Is that true? In my case, it works always, Am I missing something?
What is the need of WakeFulIntentService? When do we need to use WakefulIntentService?
I tried running a timer in a Service, though the device is locked and screen is turned off and my timer is running pretty much I can say for sure. Because I used to get notification whenever my timer trips.
What I am hearing from this forum, the service might turn off as soon the device goes to asleep. Is that true?
Yes.
In my case, it works always
Then something else on your device is keeping the device from falling asleep. Perhaps use adb shell dumpsys power to see what WakeLocks are outstanding.
What is the need of WakeFulIntent Service? When do we need to use WakefulIntentService?
The device may fall asleep if the user is inactive and nothing is keeping the device awake. A WakeLock is used to ensure the device stays awake. For transactional-type work (e.g., downloading a file), WakefulIntentService combines an IntentService and a WakeLock to make keeping the device awake as long as necessary (and only as long as necessary) relatively easy.
WakefulIntentService is not suitable for use with services that need to run indefinitely, such as a music player. For those, manage your own WakeLock.
I used the code below in an app.
Make sure your service is sticky:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//this service will run until we stop it
return START_STICKY;
}
I you want your phone to be awake constantly u can use this code below:
private WakeLock wl;
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
Don't forget the permissions in your manifest.
<uses-permission android:name="android.permission.WAKE_LOCK" />
I know that it is best practice to release a wake_lock as soon as it is no more needed, but what happens if the Activity or Service, for example, that has acquired it finishes or is stopped before you release the lock? Is it automatically released by the system? I think the system should release them automatically in that case, but I can not find anything on the API docs..
EDIT: added more info
Looking at the PowerManager.WakeLock documentation, I've seen that the wake_locks are reference counted by default (read setReferenceCounted here), i.e. if we retrieve a wake lock in an activity with PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myWakeLock"); wl.acquire(); and then the reference variable wl that holds it goes out of scope, then the wake lock is released because its reference count goes to zero... is it right?
EDIT: wrong understanding above
I think I've misunderstood the reference count concept above... it should mean that if I acquire twice the lock and release it only once, then the reference count is 1 and the lock is not yet released. If it is not reference counted, then I can acquire x times and then with a single release it is released.
There seems to be a lot of misinformation spread on the web about this. WakeLocks as exposed in the Android API have a pretty complex lifecycle and there is really no other way than be super diligent about managing it.
If an Activity or Service stops without you releasing a wakelock the state is undefined. If you inspect the code (https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/PowerManager.java, search for "class WakeLock") you will see that they are released when they are garbage collected.
This, "when they are garbage collected", however, is an extremely loose statement. In practice it seems that devices pre-Lollipop er really slow to GC the wakelocks (we can pretend it's not happening at all for practical purposes), but on post-Lollipop devices with the ART runtime it seems that stray WakeLocks are garbage collected within a few seconds.
On your questions about reference counting, you can see in the Android code that the lock is released disregarding what count it has.
If you do a blame on the Android code you can also see that it has not changed much over the years - so it all comes down to how the GC behaves. So you need to be diligent, store the lock in a field on your activity/service and release/acquire in sensible places in the app lifecycle. But if at all possible you should not be using a wakelock, but just the Force Screen On trick that Gatekeeper links to in one of the other answers.
Only if the process is destroyed then will the wakelocks be released. Just by finishing the service / Activity wake_lock will not be released.
I believe this answer will help you leaps and bounds Force Screen On
The PowerManager API states that you should release a wakelock as soon as possible, using the PowerManager API is known for draining more battery. Also in it API it states:
*If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers and even after the user presses the power
button. In all other wakelocks, the CPU will run, but the user can
still put the device to sleep using the power button.
http://developer.android.com/reference/android/os/PowerManager.html
As detailed in this answer if the process is killed then yes the wakelock is released. But if the service or activity finishes normally without releasing the answer should be no.