Does a GCM-App really need a wakelock? - android

I'm not quite sure how to interpret this sentences in the GCM Client documentation:
The android.permission.WAKE_LOCK permission so the application can keep the processor from sleeping when a message is received. Optional—use only if the app wants to keep the device from sleeping.
.
If you don't hold a wake lock while transitioning the work to a service, you are effectively allowing the device to go back to sleep before the work completes. The net result is that the app might not finish processing the GCM message until some arbitrary point in the future, which is not what you want.
and
Using WakefulBroadcastReceiver is not a requirement. If you have a relatively simple app that doesn't require a service, you can intercept the GCM message in a regular BroadcastReceiver and do your processing there.
I'm not quite sure if my app needs to hold a wakelock or not (or if it requires a service).
The Push Notification part is quite important to the app and it should not be delayed for more than a few minutes. Is there a chance that the BroadcastReceiver gets suspended before receiving all the data?

Is there a chance that the BroadcastReceiver gets suspended before receiving all the data?
No. You will not get control until the entire 4K-or-less payload has been downloaded and is available to you.
However, onReceive() is called on the main application thread, and so if your work will take more than a millisecond or so, you should use WakefulBroadcastReceiver and an IntentService for that work. Or, if you prefer, use my WakefulIntentService and a regular BroadcastReceiver.

Related

Do I need to acquire wake lock when invoking a BroadcastReceiver

In the book Pro Android 4 By Satya Komatineni , Dave MacLean I've found:
Android acquires a partial wake lock when invoking a broadcast service and releases it when it returns from the service in the main thread
Does it mean that the Android OS ensures that the device will wake up for the time of going through onReceive of BroadcastReceiver? In my case the BroadcastReceiver should get an intent from Google Play Services (GoogleLocationServices and to be precise Geofences api).
Where is it documented?
EDIT: I've also found it here:
because it is guaranteed that the BroadcastReceiver.onReceive() will be always fully executed before the CPU goes to sleep
There is no such thing as a "broadcast service".
Also, you need to read the entire post containing your second quote, as that is only for a broadcast triggered by AlarmManager. It is AlarmManager, not the broadcast Intent mechanism, that holds the WakeLock. Also, as noted in that blog post, Dianne Hackborn had confirmed this behavior, and she's a core Android engineer.
Does it mean that Adnroid OS ensures that the device will wake up for the time of going thru onReceive of BroadcastReceiver?
Not generally.
In my case the BroadcastReceiver should get intent from Google Play Services (GoogleLocationServices and to be precise Geofences api).
If the Google Play Services documentation does not make any claims regarding the behavior of your receiver with respect to wakefulness, you should assume that you are not inside of a WakeLock. If the work is something that will take 1-2ms, and therefore is probably safe to do in onReceive() anyway, you're welcome to take the risk and skip a WakeLock and hope for the best.
But usually a broadcast like this triggers more work, involving disk I/O and/or network I/O, and you need to get that work off of the main application thread. Frequently, you do that by delegating to an IntentService, as it gives you a background thread with a marker service to let the OS know that you're still doing some work here. And, to ensure that the device will stay awake for that work to complete, use WakefulBroadcastReceiver or my WakefulIntentService, to hold a WakeLock from early in onReceive() until the completion of the work in onHandleIntent().
Where is it documented?
AFAIK, it isn't. Get used to it, as for complex systems, usually only a tiny fraction of the system's behavior winds up being documented.

Is there any reason to continue using IntentService for handling GCM messages?

As you know, recently Google changed their GCM documentation, and they claim that an IntentService is no longer required for handling arriving GCM messages. All the handling can be done in the BroadcastReceiver.
When trying to figure out if there is any good reason to continue using the IntentService, I came across this quote:
A Service (typically an IntentService) to which the WakefulBroadcastReceiver passes off the work of handling the GCM message, while ensuring that the device does not go back to sleep in the process. Including an IntentService is optional—you could choose to process your messages in a regular BroadcastReceiver instead, but realistically, most apps will use a IntentService.
Why would most apps use an IntentService? Are there any scenarios in which handling the GCM message directly in the BroadcastReceiver won't work?
Why would most apps use an IntentService?
Because most likely whatever you are doing in response to the message will take more than 1-2ms, which means that you want to get that work off the main application thread. A common pattern for doing that in response to a broadcast is to delegate the work to an IntentService.
So, if your work in response to the GCM message involves:
disk I/O
further network I/O (e.g., retrieving additional data from your Web service)
substantial calculations (e.g., image processing)
you will likely want to use an IntentService to perform that work.

What is the best practice for doing work after receiving a C2DM message?

Can somebody explain the common way to handle C2DM intents work?
I have an app that does intelligent polling - it's essentially a messaging application - so it polls the server to check your inbox for new messages. There is an activity UI, and a background Service that polls conservatively.
Now to supplement the polling I have included C2DM - presumably to push inbox content that sits unread for 30 minutes.
So when I receive a C2DM RECEIVE intent, I am telling my background service to go poll.
How will this work?
I assume C2DM's main use case is an "idle" phone (i.e. in your pocket, screen off). So you get a RECEIVE intent, grab a wake lock, and fire off the background service to go poll; returning wake lock once you send an intent to the background service.
How long will the background service stay alive?
Won't android just kill it off right away?
Should I just try to do 1 server ping and then die?
I'm just confused about how much processing I can do after getting a C2DM intent.
The approach you're suggesting sounds solid. To use C2DM as a way to supplement polling is a good appraochapproach. C2DM on its own is not 100% reliable (it never will be) and your design protects against that.
The service will run until it finishes its work. I expect it would show a notification to the user, or update a message list.
I'd set the service up to do an exponential-back-off retry, and have it try X times before failing. If it fails, then the next time a poll occurs it'll be brought up to date. I wouldn't want the background service to try for too long, as that's what the polling code is there to do.
Your service will keep going unless the OS needs memory badly. You could force the service to be a foreground service (with notification icon) but I don't expect that's necessary.
I'm assuming your service is polling the service regularly, so it will make up for any failure in the C2DM message to make a server request.

Android Sticky Service Stops Sending HTTP Requests

I'm writing an Android app whose main Activity starts a Service that makes itself sticky. The Service makes repeated HTTP POSTs to a server, exchanging some information. This process works perfectly as long as the phone's screen is on, but once I turn the screen off, the service stops after a while. Is there any way to guarantee that my Service keeps running indefinitely?
Is there any way to guarantee that my Service keeps running indefinitely?
No.
Furthermore, you should not want your service to be "running indefinitely". Certainly your users do not want your service "running indefinitely", as that is why they will attack you with task killers, the force-stop operation in Manage Services in Settings, and so on. Not to mention all the lovely one-star ratings on the Market, choice comments in discussion boards, and the like that such applications will trigger.
Moreover, your problem here is not that your service is not running, per se, but that the device is falling asleep. This is perfectly normal. Users want their device to fall asleep -- otherwise, their battery life will be horrific.
The Service makes repeated HTTP POSTs to a server, exchanging some information.
The proper way to do this is to use AlarmManager, to trigger your code to execute periodically. Your user should be able to control the period (perhaps via a SharedPreference), including an option of "I'll manually request the data transfer, thanks". And, via an IntentService or similar means, you arrange for your code to be started by AlarmManager, do its work, and then shut down to get out of RAM.
Getting AlarmManager to wake up the device out of sleep mode is not that difficult (use a _WAKEUP flavor of alarm), but keeping the device awake long enough for you to do your HTTP request can be. The HTTP request cannot be performed on the main application thread, as it may take too long. One recipe is to use my WakefulIntentService component, which is an IntentService that keeps the device awake long enough for your work to be complete, then shuts down and allows the device to fall back asleep.
First Way: What you can also do to make HTTP POSTS to a server continuously is, you can make a timer and inside the task of the timer ie. in run() of class TimerTask you can make startService() and as soon as you are done with the HTTP POST work you destroy the service. Thus on a periodic basis, the timer will start the service and there won't be any background service.
Second: You can also use the PowerManager.WakeLock
Third: You can use AlarmManager as discussed in the previous answer.

How to inform your (not started) app from a Boot_completed receiver?

I have registered a BOOT_COMPLETED Receiver in my application, i want to listen for changes on SMS Database.
The BroadcastReceiver starts a temporary Service which registers the ContentObserver.
Now i want to notify my main activity (which is not started) that the Observer was registered successful.
(I want to do this, because if a user installs the app for the first time he don't restart his phone but needs the ContentObserver too. If you have another idea how to do that you can post it. I just want the information that the observer is registered already)
My idea was to notify the activity with a static attribute:
MyActivity.sObserverRegistered = true
But i think that is not good and doesn't work because the activity isn't started and this is ignored. Any idea how to solve the problem?
thanks
You have much bigger problems than that.
i want to listen for changes on SMS
Database.
There is no "SMS database", or even an SMS content provider, in the Android SDK. Attempting to access the private proprietary undocumented not-to-be-touched SMS application contents will break on some devices, will break in future versions of Android, will not work with third-party SMS applications, and is generally a bad idea.
The BroadcastReceiver starts a
temporary Service which registers the
ContentObserver.
There is no such thing as a temporary Service which registers a ContentObserver.
It might be that the Service is not temporary, so your ContentObserver remains registered and your Service is not shut down. This would occur, for example, if your BroadcastReceiver called startService() and your Service does not call stopSelf() (e.g., it is not an IntentService). This is not great, because you are now tying up a process. But, if you can convince your users that it is OK that you are tying up a process, this is the best answer, and your activity can just (re-)start the service when the activity starts up, to ensure that the ContentObserver is registered.
It might be that your ContentObserver is not registered long, because the temporary Service unregisters it right away when the Service is shut down, and the Service is shut down right away. This is great from a memory consumption standpoint, but it probably isn't that effective for your goals.
Or, it might be that you are leaking memory, because you register the ContentObserver and shut down the Service without unregistering the ContentObserver. This is horrible, because the only way the ContentObserver will ever get cleaned up is if Android terminates the process. Moreover, it will do this whenever it feels like, because as far as it is concerned, you aren't using the process anymore, despite the thread and ContentObserver and Service you leaked. This will result in unreliable code at best.

Categories

Resources