[Thinkpad Tablet General] doctorow:
Got to play with a Yoga 2 1050F for the past few days and was absolutely horrified how wakelocks kept the Yoga awake for about 30-50% of the time when it was supposed to be in deep sleep.

The wakelock in question is battery_wake_lock. It's not so much that it is triggered unusually often; rather, deep sleep is prevented by how long the wakelock is held with each trigger.

Lenovo implements the wakelock in the BQ27x00 battery driver that is shipped with the kernel of their Lollipop distribution. In the KitKat distribution, while it was initialized in the source code, it was never actually triggered. In fact, I have looked at multiple other source distributions, and

not a single one

uses wakelocks in the BQ27x00 battery driver. Thanks Lenovo.

In short, whenever there is a brief resume from deep sleep, for example triggered by an alarm from com.google.android.gms, the battery driver runs the bq27x00_battery_suspend_resume() function, which creates the battery_wake_lock wakelock and adds the battery polling task bq27x00_battery_poll to the kernel workqueue:

if (suspend_resume == RESUME_STR){
wake_lock(&di->wake_lock);
schedule_delayed_work(&di->work, 0);
}

The polling function bq27x00_battery_poll() would call bq27x00_update() to get new information about the battery, which would then also clear the wakelock.

Since the queued polling task is supposed to be run as soon as possible (delay = 0), the wakelock should be released immediately as well. No problem, right? Well, this would be only true if the polling task wasn't already active in the queue from a previous wakeup!

The person who added the battery_wake_lock didn't consider that bq27x00_battery_poll()

adds itself

to the kernel workqueue and is then triggered on a defined poll interval (default is 60 seconds as hardcoded in the Lenovo source). What does this mean? It means that it's possible, and highly likely, that when the Yoga briefly resumes from deep sleep, that there is still a queued battery polling job in the kernel workqueue. As a result, the code from above, even though it's meant to be triggered immediately, has to wait until the existing queued job has been executed. And that can take up to 60 seconds or to whatever the polling interval is defined. And that is why we are seeing those nasty long battery_wake_lock wakelocks that keep the device from deep sleep half the time.

Tldr: Each time the Yoga briefly resumes from deep sleep (which is normal and happens frequently - albeit it should be only briefly), the battery drivers adds a wakelock which prevents the device from going back to deep sleep for up to 60 seconds. If you have a total of 20 alarms per hour (not unusual - see com.google.android.gms - and normally not an issue since they are meant to be very brief), it means that Lenovo's battery wakelock keeps your device awake for up to 20 minutes or about 30% of the time!

Why did Lenovo add this wakelock? I am not sure, as I haven't seen it anywhere else implemented. In fact, Lenovo removed all wakelocks again from the battery driver in the Android 5.1 release for the Yoga Tab 3 series.

So what's the workaround?

If you have root, you can reduce the polling interval by modifying the poll_interval driver parameter. For example, I reduced the interval to 20 seconds:

$ cat /sys/module/bq27x00_battery_x8/parameters/poll_interval
60

$ echo 20 > /sys/module/bq27x00_battery_x8/parameters/poll_interval
$ cat /sys/module/bq27x00_battery_x8/parameters/poll_interval
20

While it seems counterproductive at first to reduce the interval and thus increase the number of battery polls, it makes perfect sense if you consider that it also allows the kernel queue to clear faster. Before it could take up to 60 seconds for the wakelock to be released; now it takes only up to 20 seconds. Ideally, when you have the device on, you'd want to set the interval parameter to a higher number again (your battery status is updated every 20 seconds now instead of every 60 seconds), although I haven't noticed any difference in performance or battery life so that's probably not an issue.

Speaking of battery life, attached you see how well my device was doing over last night. The battery charge went down by 1% - from 73% to 72% - in 8 hours! Not bad, is it?

Lastly, I am currently using the YT2-1050F-USR-S100067_1507101258_WW52_ROW firmware and haven't upgraded to the latest OTA yet. It's possible that Lenovo has fixed the issue, although I highly doubt it judging from the lack of discussions in this regard in the Lenovo forums.

Please Lenovo, fix this.