From: eLinux.org

Android Power Management

Notes on Power Management in Android

Contents

wakelocks

The first version of Android utilized a system called “wakelocks”, which
was a set of patches to the Linux kernel to allow a caller to prevent
the system from going to low power state.

Each wakelock is defined with a name and type. The type is one of:

  • WAKE_LOCK_IDLE, or
  • WAKE_LOCK_SUSPEND.

The name is an arbitrary ASCII string.

When a wake lock of type “IDLE” is in effect, the system will not enter
idle (low power) state, and this should make the device more responsive.
That is, it does not have to wake up from idle to respond to interrupts
or events. When a wake lock of type “SUSPEND” is held, then the system
will not suspend, which takes even longer to resume from.

You can, from user space, see the currently defined wakelocks and a
bunch of information about their status, using ‘cat /proc/wakelocks’

Below is an example of output from that command.

To see the code for this, see the file:

  1. drivers/android/power.c

NOTE: See the
Discussion
page for a note on this file.

Creating a wakelock

Kernel code can define a wakelock, and get a handle to it, by calling:

  1. #include <linux/wakelock.h>
  2. wake_lock_init(struct wakelock *lock, int type, const char *name);

From user space, a process can write a name to

  1. /sys/power/wake_lock

to create and lock a suspend lock with that name.

Using a wakelock inside the kernel

Kernel code can acquire and release the lock with one of the following:

  1. void wake_lock(struct wake_lock *lock);
  2. void wake_unlock(struct wake_lock *lock);

Kernel code can also set a timeout to specify automatic release of the
wakelock after a specific period, with:

  1. void wake_lock_timeout(struct wake_lock *lock, long timeout);

The wakelock does not need to be held prior to calling this (it will
automatically lock the wakelock and register the timeout).

Using a wakelock from user space

To release a suspend wake lock from user space, a process can write the
lock name to: /sys/power/wake_unlock

Sample ‘cat /proc/wakelocks’ output

Here are some wakelocks from my ADP1 phone, running Donut (I think):

Note: I widened the columns and adjusted the title row to make the
columns line up better.

  1. $ cat /proc/wakelocks
  2. name count expire_count active_since
  3. wake_count total_time sleep_time max_time last_change
  4. "PowerManagerService" 3580 0 0 0 1706674438454 1354421173104 62626251221 31701936996687
  5. "mddi_link_active_idle_lock" 4641 0 0 0 26749877925 0 253234863 31701903732527
  6. "msmfb_idle_lock" 2549 0 0 0 28889923076 0 266601563 31701902633894
  7. "SMD_RPCCALL" 8913 0 34 0 9038391159 6843658471 176025391 31690316543807
  8. "audio_pcm_idle" 12 0 0 0 68230224609 0 27459259033 31690315567244
  9. "audio_pcm" 12 0 0 0 68230285646 12423248292 27459289551 31690315567244
  10. "rpc_read" 60 0 0 0 3112792 823974 91553 31690315048445
  11. "adsp" 12 0 0 0 67035552978 11988464355 27387664794 31690282791365
  12. "rpc_read" 12 0 0 0 671387 213624 91553 31686582229842
  13. "usb_mass_storage" 0 0 0 0 0 0 0 0
  14. "rpc_read" 137 0 0 0 8972160 6744383 122070 31685788467635
  15. "rpc_server" 277 0 0 0 406372060 320922839 41412354 31685787887801
  16. "rpc_read" 277 0 0 0 117919940 111480725 94848633 31685787826766
  17. "alarm" 1220 0 0 0 27851074219 25716247547 382141114 31669270950545
  18. "rpc_read" 4909 0 0 0 375915506 347930899 16021729 31376427078475
  19. "gpio_input" 0 0 0 0 0 0 0 0
  20. "mddi_idle_lock" 54 0 0 0 8752532958 0 249603271 31154190719832
  21. "SMD_DATA5" 862 862 377 0 620518382572 567607416986 6926910400 31153421737899
  22. "alarm_rtc" 177 10 0 0 47826019299 47825439463 1801544190 31152471695175
  23. "KeyEvents" 13271 0 0 0 11482665934 343322752 503204346 30525886245957
  24. "evdev" 4437 0 0 0 4980529833 98724365 506927490 30525884811631
  25. "evdev" 188 0 6 0 3093719493 2680358890 393676758 30522918777697
  26. "rpc_read" 18 0 0 0 1464840 0 335693 30520425552599
  27. "gpio_kp" 68 0 14 0 14835723878 2092010498 933135987 30445059005968
  28. "evdev" 52 0 0 0 98999026 0 24139405 30438128067247
  29. "rpc_read" 596 0 0 0 745910654 211212166 491180420 30046209060900
  30. "rpc_read" 1331 0 0 0 286651593 169342025 112518310 30046203598253
  31. "rpc_read" 10 0 0 0 1495361 427247 274658 3596980453801
  32. "qmi0" 2 2 0 0 996235351 0 501717529 173250290527
  33. "qmi2" 1 1 0 0 490385742 0 490385742 173250290527
  34. "qmi1" 1 1 0 0 493193359 0 493193359 173250290527
  35. "evdev" 0 0 0 0 0 0 0 0
  36. "evdev" 0 0 0 0 0 0 0 0
  37. "rpc_read" 2 0 0 0 427247 0 274659 7461350097
  38. "mt9t013" 0 0 0 0 0 0 0 0
  39. "gpio_input" 0 0 0 0 0 0 0 0
  40. "gpio_input" 0 0 0 0 0 0 0 0
  41. "SMD_DATA7" 0 0 0 0 0 0 0 0
  42. "SMD_DATA6" 0 0 0 0 0 0 0 0
  43. "msm_serial_hs_rx" 0 0 0 0 0 0 0 0
  44. "unknown_wakeups" 0 0 0 0 0 0 0 0
  45. "deleted_wake_locks" 36 0 0 0 2593991 518798 1068114 0
  46. "radio-interface" 329 0 0 549499512 437556091307 299558441157 2895507812 31701540695418
  47. "vbus_present" 3 2 0 16399444580 26400295008545 25248585083008 25852771240234 31685690780867
  48. "main" 27 0 0 547991455078 4674244259033 0 627599700928 31154098800887
  49. "mmc_delayed_work" 796 796 172 0 405246968975 396150246568 689067383 31153556991805
  50. "SMD_DS" 682 681 192 558929443 486005943591 268692961407 2368892822 31701531357039

Patch submission controversy

Arve Hjønnevå (of Google) sent patches to the linux-pm mailing list in
of 2009, but they were rejected. See this
thread

for the submission and resulting discussion. This was the third version
of the patches submitted for review by the kernel community.

The reasons for the rejection are described in the LWN.NET article
Wakelocks and the embedded problem.

Wakelock documentation (from patch)

The 3rd version of the wakelock patch included the following
/Documentation/power/wakelock.txt file

  1. Wakelocks
  2. =========
  3. A locked wakelock, depending on its type, prevents the system from entering
  4. suspend or other low-power states. When creating a wakelock, you can select
  5. if it prevents suspend or low-power idle states. If the type is set to
  6. WAKE_LOCK_SUSPEND, the wakelock prevents a full system suspend. If the type
  7. is WAKE_LOCK_IDLE, low-power states that cause large interrupt latencies, or
  8. that disable a set of interrupts, will not be entered from idle until the
  9. wakelocks are released. Unless the type is specified, this document refers
  10. to wakelocks with the type set to WAKE_LOCK_SUSPEND.
  11. If the suspend operation has already started when locking a wakelock, it will
  12. abort the suspend operation as long it has not already reached the suspend_late
  13. stage. This means that locking a wakelock from an interrupt handler or a
  14. freezeable thread always works, but if you lock a wakelock from a suspend_late
  15. handler you must also return an error from that handler to abort suspend.
  16. Wakelocks can be used to allow user-space to decide which keys should wake the
  17. full system up and turn the screen on. Use set_irq_wake or a platform specific
  18. api to make sure the keypad interrupt wakes up the cpu. Once the keypad driver
  19. has resumed, the sequence of events can look like this:
  20. - The Keypad driver gets an interrupt. It then locks the keypad-scan wakelock
  21. and starts scanning the keypad matrix.
  22. - The keypad-scan code detects a key change and reports it to the input-event
  23. driver.
  24. - The input-event driver sees the key change, enqueues an event, and locks
  25. the input-event-queue wakelock.
  26. - The keypad-scan code detects that no keys are held and unlocks the
  27. keypad-scan wakelock.
  28. - The user-space input-event thread returns from select/poll, locks the
  29. process-input-events wakelock and then calls read in the input-event device.
  30. - The input-event driver dequeues the key-event and, since the queue is now
  31. empty, it unlocks the input-event-queue wakelock.
  32. - The user-space input-event thread returns from read. It determines that the
  33. key should not wake up the full system, releases the process-input-events
  34. wakelock and calls select or poll.
  35. Key pressed Key released
  36. | |
  37. keypad-scan ++++++++++++++++++
  38. input-event-queue +++ +++
  39. process-input-events +++ +++
  40. Driver API
  41. ==========
  42. A driver can use the wakelock api by adding a wakelock variable to its state
  43. and calling wake_lock_init. For instance:
  44. struct state {
  45. struct wakelock wakelock;
  46. }
  47. init() {
  48. wake_lock_init(&state->wakelock, WAKE_LOCK_SUSPEND, "wakelockname");
  49. }
  50. Before freeing the memory, wake_lock_destroy must be called:
  51. uninit() {
  52. wake_lock_destroy(&state->wakelock);
  53. }
  54. When the driver determines that it needs to run (usually in an interrupt
  55. handler) it calls wake_lock:
  56. wake_lock(&state->wakelock);
  57. When it no longer needs to run it calls wake_unlock:
  58. wake_unlock(&state->wakelock);
  59. It can also call wake_lock_timeout to release the wakelock after a delay:
  60. wake_lock_timeout(&state->wakelock, HZ);
  61. This works whether the wakelock is already held or not. It is useful if the
  62. driver woke up other parts of the system that do not use wakelocks but
  63. till need to run. Avoid this when possible, since it will waste power
  64. if the timeout is long or may fail to finish needed work if the timeout is
  65. short.

Motorola quickwakeup feature

Jocelyn Falempe of Motorola proposed (in November, 2009) a quickwakeup
feature to make it possible to reduce the time for a periodic job to
resume, do a small amount of work, and suspend again.

http://patchwork.kernel.org/patch/58064/

From the patch:

  1. The purpose of this feature is to drastically reduce the suspend/resume
  2. time for device driver which needs to do periodic job.
  3. In our use case (android smartphone), the system is most of the time in
  4. suspend to RAM, and needs to send a low level command every 30s. With
  5. current framework it takes about 500ms on omap3430 to resume the full
  6. system, and then suspend again. With quickwakup feature, in the resume
  7. process after resuming sysdev and re-enabling irq, the driver handler is
  8. executed, and then it suspends again.
  9. This new path takes 20ms for us, which leads to good power-saving.

Earlysuspend

Arve’s patches also included something referred to as “earlysuspend”,
but I haven’t reviewed this yet to see what it is.

May 2010 patch submission - “Suspend blockers”

Arve refactored the patches and did a name change, and submitted them
again in April and May of 2010. There was a LOT of discussion on the
linux-pm mailing list, which many developers participated in. The
discussion raised lots of questions, and lots of responses were given.
People interested in Android power management may get more enlightenment
by reading the thread.

http://groups.google.com/group/linux.kernel/browse_frm/thread/b6fed7e38365c259/c92d8b4a41f87902?hl=en&tvc=1&q=linux.kernel+suspend+block+api+(version+6)#c92d8b4a41f87902#c92d8b4a41f87902)

Category: