Thursday, April 22, 2010

Monitoring sensors in the background

Once I got the taste of making all sorts of measurements with sensors, I happily started to collect samples. Then I quickly ran into the background sensor monitoring problem. The use case is very simple: the phone is in idle state, keyguard is locked but it collects and processes sensor data. For example I wanted to record acceleration sensor data while cycling. I started the sensor application, started the measurement and locked the keyguard. On the Nexus One it means that there will be no further sensor data delivered to the application until the screen is on.

The source of the problem is that the sensor is powered down when the screen is off. This is implemented below the Android framework (either in the kernel driver or in hardware, I would be curious if anyone knows the answer) because if you recompile the latest sources from android.git.kernel.org, sensor data will be delivered nicely to the application in the emulator even if the keyguard is locked (the stock 2.1 emulator's Goldfish sensor does not emit any event, that is why you have to recompile from source) . The fact remains: if you want acceleration sensor data on the Nexus One, the screen must be on. This pretty much kills all the user-friendly applications that want to analyze sensor data in the background while the phone is idle. In the worst case, the screen must be constantly on (e.g. for a pedometer that needs to measure constantly because you never know when the user makes a step) but the situation for a simple context reasoner service is not much better. Such a service (read the vision paper for background, you need free registration to access) may want to sample the sensors periodically (e.g. collecting 5 sec. of samples in every minute). In order to perform the sampling, the screen should be switched on for this duration which would result in a very annoying flashing screen and increased power consumption.

You can observe these effects in the improved Sensors program that is able to capture sensor data in the background.

Click here to download the example program.

Start and deploy this program and you will see the familiar sensor list. If you click on any list item, the old interactive display comes up. The improvement here is that the application measures the sensor sampling frequency. The rate can be set in the settings menu, from the main activity. If, however, you long-press on the list item, the sampling will be started in the background. In this case there is no interactive display of the samples, they are always saved into the /sdcard/capture.csv file. The background sampler does respect the sampling rate setting, however. The background sampler is implemented as a service.

So far there is nothing extraordinary. You may observe the ScreenOffBroadcastReceiver class in SamplingService that intercepts ACTION_SCREEN_OFF intent broadcasts and does something weird in response. In order to understand its operation, you must be aware that the power manager deactivates all the wake locks that are stronger than PARTIAL_WAKE_LOCK when the keyguard powers the device down. Obtaining for example a SCREEN_BRIGHT_WAKE_LOCK in the broadcast receiver would be of no use because at this point the screen is still on and the wake lock would be deactivated when the screen is turned off. Instead, the broadcast receiver starts a thread, waits for 2 sec (experimental value) and then it activates the wake lock with wakeup option. Try to push the power button when the background sampling is on, the screen will go off for 2 seconds but then it is turned on again and you will see the keyguard screen. If you check the log, you will see that the sensor sampling stops for that 2 seconds then it comes back on. Don't worry, when the background sampling is stopped (by long-pressing the sensor's name in the list again) the screen will turn off correctly.

Ugly? You bet. Not only the solution is a bad hack but it also prevents the device from switching off the screen and those AMOLED displays plus the high-powered processors eat battery power like pigs. The decision that the sensors are powered down when the screen is off prevents the implementation of some of the most exciting mobile applications and significantly decreases the value of the platform.

But enough of the grunting. This is the state of the art in background sensor sampling in Android (as of version 2.1 of the platform), I will continue with signal processing algorithms.

16 comments:

Matthew said...

It's still an annoying hack, but you can get by with a PARTIAL_WAKE_LOCK. At least for the accelerometer and for my Android 2.0-2.01 device (Motorola Droid).

You need to register for the ACTION_SCREEN_OFF event and then when that fires unregister your sensor listener and then re-register it. The screen stays off, but the monitoring continues.

protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
sensorManager.unregisterListener(sensorEventListener);
sensorManager.registerListener(sensorEventListener, sensorAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
}
};

Good luck with this work-around!

Gabor Paller said...

sorry, mathew, i tried it on the nexus and re-registration does not work.

Matthew said...

I haven't tried it since I was upgraded to 2.1 on my Droid, so maybe it's an OS version difference. From what I saw, Google developers acknowledge that this is a problem that shouldn't exist, so I'd hope it didn't get worse going into 2.1.

I'll re-try my own app and see how it does on my upgraded Droid.

Gabor Paller said...

i am very much convinced that the problem is below the android framework. i suspect the kernel power driver. is the kernel also upgraded during the update process?

kosiakk said...

There is known firmare bug describing this problem:
http://code.google.com/p/android/issues/detail?id=3708

More information on

http://www.smart-alarm-clock.com/supported-phones

Gabor Paller said...

kosiakk, my understanding is that it is not a bug, it is an intentional decision from Google's part to protect users against power-hungry background applications. This, however. goes against the Android philosophy (everything is possible if the user is aware of it).

Creating appropriate permissions or more sophisticated power management framework where apps could declare how power-hungry they are and let the users decide would be a better approach.

Kevin McDonagh said...

On a related hardware sleeping note, upon waking from sleep, something to be aware of is that is that the radio hardware may be turned off, connecting to network hubs and allocating IPs might take a little time and so a connection is active without an actual internet connection. Granular privileged intents will be difficult to manage in the community but are inevitable.

kosiakk said...

Gabor, nope.

I talked to one of Android managers directly, Reto Meier, and he confirmed that this is threated as a bug. "If you hold wake lock - you should receive sensor events" and promised that the fix is already there, but delivery depends on cellular providers, as usual.

Another question is who and why added this 'bug'. I agree that this might be the part of power-saving effort. But we will newer know for sure =)

There's an permission for accessing wake lock - Prevent phone from sleeping.

No nothing should be changed, but the bug itself.

Gabor Paller said...

kosiakk, would partial wake lock be enough? Because it does not help if you need to turn on the screen just to be able to receive sensor events.

Gabor Paller said...

Could you elaborate about this one? :-)
"Granular privileged intents will be difficult to manage in the community but are inevitable."

Calle said...

Very interesting blogpost Gabor. I am actually working with a similar task and have a question about background monitoring. I perform tests with a HTC Desire which behave very similar as the N1. Have you heard anything on how this matter has changed in the 2.1 version? Again, thanks for very interesting reading on your blog.

Gabor Paller said...

Calle, I don't know more than what is explained by kosiakk here in the comments. According to him, it is a fault and simple partial wake lock should be enough to keep the sensors running. I have 2.1 on my N1 and the problem is present, loud and clear.

The solution presented here is a bad hack but I am not aware of anything better at this moment. :-/

Jordan said...

For what it's worth, I just installed the Froyo FRF50 build that has been kicking around on the internets for the last few days. On my Nexus One, it now seems that the sensors remain on when the screen is locked (ie., off). I've bitched about this a bunch on the Android Developers mailing list, and I'm hoping that they have taken the bait, and at least in the next update they will allow sensors to work once again when the screen is locked.

It's also possible that this leaked build that I'm running is not what will eventually be released, and they'll go and disable the sensors again and piss of a whole bunch of developers... time will tell...

David Shellabarger said...

I know this is not a problem on the myTouch 3G because I have killed battery's that way with older versions of Smart Lock.
I know register my Sensors with ACTION_SCREEN_ON.
I had reports that Nexus One users had the same battery draining problem, but I recently upgraded myTouch 3G to 2.1 (cyanogenMod) so I'll test out the sensor responsiveness with the screen off and get back to you.

blazivic said...

great post!

quick question: what does the numbers on the left column of the capture.csv represent?

another if i may: the sampling frequency, does it varies during the measurement? or we can assume that the value 17hz (in UI mode) is constant throughout the measurement?

Anonymous said...

AS of 2014, Issue 3708 is still unfixed. The workaround mentioned above by first poster only works on certain devices. It's not a universal fix.