I am new to the notion of WakeLock and need your help.
Questions:
I assume WakeLock to be some type of lock which when held by the executing code prevents the device from sleeping. What if the device is already in sleep/standby mode, will the code execute then? Assuming that it would never acquire a WakeLock?
When a long running task(abt 7-8 sec) is done in a background thread(AsyncTask) should I be bothered about holding a WakeLock? Does AsyncTask already acquire it for me?
links to official documentations and writeup on wakelocks are appreciated.
Thanks.
1.If the phone is in full sleep mode, aside from an incoming phone call, you could use an AlarmManager intent to wake the phone up.
From the AlarmManager class documentation:
The Alarm Manager holds a CPU wake
lock as long as the alarm receiver's
onReceive() method is executing. This
guarantees that the phone will not
sleep until you have finished handling
the broadcast. Once onReceive()
returns, the Alarm Manager releases
this wake lock. This means that the
phone will in some cases sleep as soon
as your onReceive() method completes.
If your alarm receiver called
Context.startService(), it is possible
that the phone will sleep before the
requested service is launched. To
prevent this, your BroadcastReceiver
and Service will need to implement a
separate wake lock policy to ensure
that the phone continues running until
the service becomes available.
2.If you're working with an AsyncTask, you will want to publish results on to the UI thread on onPostExecute()
From the AsyncTask documentation:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
3.I suggest you have a read at the official documentation of Power Manager which gives a good introduction to the WakeLock concept.
Typically the only code that would run while the phone is sleeping is a BroadcastReceiver. Actually, the phone wakes up for a second, runs the BroadcastReceiver's code and sleeps again. Since you should never run long code in a BroadcastReceiver (use it to launch a Service instead), you can basically assume that your code is never run while the phone is sleeping. Of course, if you are using a BroadcastReceiver to start a Service, you should usually obtain a WakeLock.
With an AsyncTask initiated by the user, you don't really need to worry about WakeLocks. It is unlikely the phone will sleep while it is running. I'm not sure if they get a WakeLock, but putting my phone to sleep while running a standard AsyncTask doesn't seem to interrupt the it.
As SteD said, check this out: http://developer.android.com/reference/android/os/PowerManager.html
Basically the only time you need to worry about WakeLocks is when you either expect your task to be interrupted by sleeping (as is the case if you set an alarm that wakes the phone up briefly) or if you absolutley cannot have the task interrupted. Otherwise, just make sure that you gracefully handle any interruptions.
Related
My IntentService gets fired from 2 places, either by an Alarm or by the Activity and since the duration is related to the amount of data it needs do fetch from the web, from what I understood, I need to keep a partial wakelock.
Here's my implementation:
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeLock");
try {
wakeLock.setReferenceCounted(false);
wakeLock.acquire(3600000);
///other code here
}
catch{
}
finally{
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
My question is: will this work good enough? Will the finally make sure that the wakelock is released in any circumstances? From what I know onHandleIntent handles intent one after another, so there is no risk in having 2 intents/2 wakelocks in the same time.
Later edit:
The IntentService is called in 2 ways:
from my Activity, like
startService(new Intent(context, MyService.class).putExtra()..);
2 from a triggered Alarm using a PendingIntent
PendingIntent pendingIntent = PendingIntent.getService(context, someId, myServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Will the service have enough time to aquire wakelock when ran from the Alarm?
Whether you need to keep wake-lock or not should not be related to the amount of work your Service does - theoretically, device can go to sleep even if the amount of work is small.
Wake-locks should be considered only if you absolutely must ensure that device can't sleep while the Service is running. Cases like this are very rare. Some examples:
Alarm clock applications (need to wake you up even if the device is sleeping)
Real time messaging applications (need to notify you about new messages even if the device is sleeping)
Most applications don't have such a strict timing requirements. For example, the following are NOT good reasons to use wake locks:
Periodic synchronization of data with the server (should be delayed until device awakes)
Displaying current user's location on map (can be obtained when device awakens; but wake-lock will be needed for applications that monitor user's entire route)
If you really need to ensure that the device doesn't sleep during Service execution, then you need to acquire a wake-lock (one of the several types). Let's assume that this is the case here.
You want to be able to start the "wakeful" Service from application's UI (Activity), and using AlarmManager.
Starting from UI
Since the device should be completely awake in order for the user to interact with UI, you can safely assume that if you start the Service in response to UI interaction it will have a chance to acquire a wake-lock (but do it as soon as the Service is started).
Your solution covers this case.
Starting from AlarmManager
Unfortunately, there is no guarantee (at least no documented guarantee) that when AlarmManager starts the Service it will hold a wake lock and allow the Service to acquire its own wake-lock. This means that the device can go to sleep after alarm fired, but before your Service had a chance to acquire the wake-lock.
This means that your solution will "break" in this case.
The only documented scheme in which AlarmManager will help you with wake-locks involves broadcasts:
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes. If your alarm receiver called
Context.startService(), it is possible that the phone will sleep
before the requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a separate wake
lock policy to ensure that the phone continues running until the
service becomes available.
This is where WakefulBroadcastReceiver comes in very handy.
Note that if you use this scheme, then there is no need to support a different one for "UI initiated" case - use the same approach in both cases.
You might also want to take a look at this library developed by #CommonsWare (I didn't use it myself though).
Introduction
According to AlarmManager Documentation
The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes. If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched. To prevent this, your BroadcastReceiver and Service will need to implement a separate wake lock policy to ensure that the phone continues running until the service becomes available.
Android also provides WakefulBroadcastReceiver for solving this problem:
Helper for the common pattern of implementing a BroadcastReceiver that receives a device wakeup event and then passes the work off to a Service, while ensuring that the device does not go back to sleep during the transition.
This class takes care of creating and managing a partial wake lock for you; you must request the WAKE_LOCK permission to use it.
Starting from api level 11 BroadcastReceiver provides goAsync method which allows to keep the receiver running longer than 10 seconds and move time consuming code to background thread.
Question
If in the receiver of Alarm Manager's receiver (which inherits from BroadcastReceiver, not WakefulBroadcastReceiver) I call goAsync and start new thread for time consuming code there will the Alarm Manager keep the wake lock until I call finish on the pendingResult returned from goAsync or do I still need to acquire wake lock in the code that I run on the new thread?
"Starting from api level 11 BroadcastReceiver provides goAsync method
which allows to keep the receiver running longer than 10 seconds and
move time consuming code to background thread."
This is not true according to the documentation. To quote from the goAsync doc:
This does not change the expectation of being relatively responsive to
the broadcast (finishing it within 10s)
I have an activity with some Handlers that are being executed at intervals no more than 5 minutes. The activity is launched from a BroadcastReceiver and may be launched with the screen off waiting for the user to grab the phone and get the user input, when this happens, the activity onPause() is called so for sure CPU is in sleep mode. I have not set the activity to turn screen on because I want to save as much battery as possible.
I've tested it with my phone and works really well, while screen is off all Handlers execute all the code they have to run. If I turn the screen on and off while the activity is open everything works fine.
Now, I've read everywhere that some devices does not work as expected when screen goes off and CPU sleeps, most of the times with accelerometers. Now my question is, do I need to acquire a WakeLock so the CPU does not sleep while my activity is open? I really want to know this because, as I said before, I don't want to 'waste' battery by acquiring an expensive WakeLock.
I would prefer a detailed answer of a person that really knows how this works.
Your goal cannot be stably achieved by your approach. If you use an Handler's postDelayed() method and the CPU goes to deepsleep, the ms counter will stop and will only continue if the CPU wakes up again.
See this for more detail.
So if you want to have some kind of a cron job you will need to use wakelock.
Fortunately there is a Service implementation that does exactly that: Wakeful IntentService
From the doc:
The recommended pattern for Android's equivalent to cron jobs and Windows scheduled tasks is to use AlarmManager. This works well when coupled with an IntentService, as the service will do its work on a background thread and shut down when there is no more work to do. There's one small problem: IntentService does nothing to keep the device awake. If the alarm was a WAKEUP variant, the phone will only stay awake on its own while the BroadcastReceiver handling the alarm is in its onReceive() method. Otherwise, the phone may fall back asleep. WakefulIntentService attempts to combat this by combining the ease of IntentService with a partial WakeLock.
I want to run a thread to do some work in the background (from a service that acquired a wakelock). after my thread finish work then it will stop the service.
My concerns are :
1- Do i need to require a wakelock in the thread that was started in the service?
2- Can the system kill my thread while leaving my service running?
3- if 2 is the case how could i stop my service (can i give the service a timeout time that it will die after it)
WakeLocks are, as I understand applied to the Android component (e.g. service, activity, etc.) and all its associated threads. So you would not have to aquire a new wakelock in your thread. You could prove this by passing the aquired lock and calling isHeld from the started thread.
You should consider a partial wakelock, this will concern only keeping the CPU running, regardless of the screen or keyboard activity. Since this is a service I assume you don't care whether the screen stays on.
Note that it states here: 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.
Edit: Also, even though you can do it the way you suggested, it might be better to only aquire and release the wakelock in the child thread for battery consumption purposes. And if you are needing to use WiFi for this work a WiFiLock may also be required.
I'm looking at using the Alarm Manager, and read this in the developer docs, which I don't really understand.
"If your alarm receiver called Context.startService(),
it is possible that the phone will sleep before the
requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a
separate wake lock policy to ensure that the phone
continues running until the service becomes available."
http://developer.android.com/reference/android/app/AlarmManager.html
I am specifically asking for which situations it could possible that the phone will sleep before the service is launched (as this is the part I don't comprehend)? Is it dependent on how fast the phone can execute statements? ie. it calls startService() which opens another thread and so the original thread could complete its work before the service has been made available?
Thanks
If you're starting the service from a BroadcastReceiver, you're only guaranteed that the device will not sleep during the receiver's onReceive(). According to this question, startService() is asynchronous, which means it will not block onReceive() from finishing while the service is being started. So if you need to make sure that the service starts, you have to implement your own WakeLock.