Merge lp:~phablet-team/powerd/dbus-stuff into lp:powerd

Proposed by Matt Fischer
Status: Merged
Approved by: Michael Frey
Approved revision: 37
Merged at revision: 10
Proposed branch: lp:~phablet-team/powerd/dbus-stuff
Merge into: lp:powerd
Diff against target: 2175 lines (+1749/-104)
29 files modified
CMakeLists.txt (+43/-4)
cmake/COPYING-CMAKE-SCRIPTS (+22/-0)
cmake/UseGdbusCodegen.cmake (+35/-0)
data/com.canonical.powerd.xml (+25/-0)
debian/changelog (+14/-0)
debian/control (+3/-2)
debian/install (+1/-0)
debian/powerd.conf (+24/-0)
debian/upstart (+4/-2)
libsuspend/CMakeLists.txt (+12/-0)
libsuspend/autosleep.c (+49/-0)
libsuspend/common.h (+35/-0)
libsuspend/earlysuspend.c (+55/-0)
libsuspend/legacy.c (+82/-0)
libsuspend/libsuspend.c (+78/-0)
libsuspend/libsuspend.h (+35/-0)
libsuspend/mocksuspend.c (+49/-0)
libsuspend/sysfs.c (+62/-0)
libsuspend/sysfs.h (+26/-0)
src/CMakeLists.txt (+18/-0)
src/power-request.c (+446/-0)
src/powerd-internal.h (+63/-0)
src/powerd-object.c (+125/-0)
src/powerd-object.h (+60/-0)
src/powerd.cpp (+134/-96)
src/powerd.h (+41/-0)
testclient/CMakeLists.txt (+37/-0)
testclient/testclient.c (+120/-0)
tester.sh (+51/-0)
To merge this branch: bzr merge lp:~phablet-team/powerd/dbus-stuff
Reviewer Review Type Date Requested Status
Michael Frey (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+164811@code.launchpad.net

Commit message

Massive influx of changes including:
1) control file cleanup and new deps
2) support for listening for power requests on dbus
3) tie in to seth's low level libsuspend code
4) a simple C based test client for the power requests

Description of the change

Massive influx of changes including:
1) control file cleanup and new deps
2) support for listening for power requests on dbus
3) tie in to seth's low level libsuspend code
4) a simple C based test client for the power requests

What did not land:
1) full internal use of power state requests, for example, the activity timer could hold an active request until it expired. Seth is working on this now, but it will not impact the functionality

We have more work to do before we move on to display power states but we should merge this and release now or the merges will get larger and larger.

No new changelog entry, we can discuss whether we're releasing this tomorrow.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:32
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~phablet-team/powerd/dbus-stuff/+merge/164811/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/powerd-ci/4/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/powerd-raring-armhf-ci/4

Click here to trigger a rebuild:
http://s-jenkins:8080/job/powerd-ci/4/rebuild

review: Needs Fixing (continuous-integration)
lp:~phablet-team/powerd/dbus-stuff updated
33. By Matt Fischer

removing bzrignore which should not be committed

34. By Matt Fischer

merging seth's changes also remove the debug line from the find function, it's too chatty

35. By Matt Fischer

Adding more debug info by printing the string and not the number in most
places, some whitespace cleanup

36. By Matt Fischer

fixing merge mistake

37. By Matt Fischer

update changelog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:36
http://jenkins.qa.ubuntu.com/job/powerd-ci/5/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/powerd-raring-armhf-ci/5

Click here to trigger a rebuild:
http://s-jenkins:8080/job/powerd-ci/5/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:37
http://jenkins.qa.ubuntu.com/job/powerd-ci/6/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/powerd-raring-armhf-ci/6

Click here to trigger a rebuild:
http://s-jenkins:8080/job/powerd-ci/6/rebuild

review: Approve (continuous-integration)
Revision history for this message
Michael Frey (mfrey) wrote :

Tested. All working well. Approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-02-13 17:41:38 +0000
3+++ CMakeLists.txt 2013-05-21 14:54:26 +0000
4@@ -1,39 +1,78 @@
5 project(powerd)
6+cmake_minimum_required(VERSION 2.8.9)
7+
8+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}")
9+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb -g")
10+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -ggdb -g")
11+
12+set(GDBUS_NAME powerd-dbus)
13+
14+find_package(PkgConfig)
15+pkg_check_modules(GLIB glib-2.0)
16+pkg_check_modules(GUDEV gudev-1.0)
17+pkg_check_modules(GIO gio-2.0)
18+pkg_check_modules(GIO-UNIX gio-unix-2.0)
19+
20+set(POWERD_GENERATED_SOURCES
21+ ${GDBUS_NAME}.c
22+)
23+set(POWERD_GENERATED_HEADERS
24+ ${GDBUS_NAME}.h
25+)
26+SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/src/${POWERD_GENERATED_SOURCES} PROPERTIES GENERATED 1)
27
28 set(
29 SRCS
30
31 src/powerd.cpp
32+ src/powerd-object.c
33+ src/power-request.c
34+ src/${GDBUS_NAME}.c
35 )
36
37-find_package(PkgConfig)
38-pkg_check_modules(GLIB glib-2.0)
39-pkg_check_modules(GUDEV gudev-1.0)
40-
41 link_directories(
42 ${GLIB_LIBRARY_DIRS}
43+ ${GIO_LIBRARY_DIRS}
44+ ${GIO-UNIX_LIBRARY_DIRS}
45 ${GUDEV_LIBRARY_DIRS}
46 )
47
48 include_directories(
49 ${GLIB_INCLUDE_DIRS}
50+ ${GIO_INCLUDE_DIRS}
51+ ${GIO-UNIX_INCLUDE_DIRS}
52 ${GUDEV_INCLUDE_DIRS}
53+ ${PROJECT_SOURCE_DIR}/libsuspend
54+ ${CMAKE_CURRENT_BINARY_DIR}/src
55 )
56
57+add_subdirectory(libsuspend)
58+add_subdirectory(src)
59+add_subdirectory(testclient)
60+
61 add_executable(
62 powerd
63
64 ${SRCS}
65 )
66
67+add_dependencies(
68+ powerd
69+
70+ dbus_bindings
71+)
72+
73 target_link_libraries(
74 powerd
75+ suspend
76
77 is
78 sf
79 hybris_ics
80 ${GLIB_LIBRARIES}
81 ${GUDEV_LIBRARIES}
82+ ${GIO_LIBRARIES}
83+ ${GIO-UNIX_LIBRARIES}
84 )
85
86 install(
87
88=== added directory 'cmake'
89=== added file 'cmake/COPYING-CMAKE-SCRIPTS'
90--- cmake/COPYING-CMAKE-SCRIPTS 1970-01-01 00:00:00 +0000
91+++ cmake/COPYING-CMAKE-SCRIPTS 2013-05-21 14:54:26 +0000
92@@ -0,0 +1,22 @@
93+Redistribution and use in source and binary forms, with or without
94+modification, are permitted provided that the following conditions
95+are met:
96+
97+1. Redistributions of source code must retain the copyright
98+ notice, this list of conditions and the following disclaimer.
99+2. Redistributions in binary form must reproduce the copyright
100+ notice, this list of conditions and the following disclaimer in the
101+ documentation and/or other materials provided with the distribution.
102+3. The name of the author may not be used to endorse or promote products
103+ derived from this software without specific prior written permission.
104+
105+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
106+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
107+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
108+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
109+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
110+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
111+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
112+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
113+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
114+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
115
116=== added file 'cmake/UseGdbusCodegen.cmake'
117--- cmake/UseGdbusCodegen.cmake 1970-01-01 00:00:00 +0000
118+++ cmake/UseGdbusCodegen.cmake 2013-05-21 14:54:26 +0000
119@@ -0,0 +1,35 @@
120+cmake_minimum_required(VERSION 2.6)
121+if(POLICY CMP0011)
122+ cmake_policy(SET CMP0011 NEW)
123+endif(POLICY CMP0011)
124+
125+find_program(GDBUS_CODEGEN NAMES gdbus-codegen DOC "gdbus-codegen executable")
126+if(NOT GDBUS_CODEGEN)
127+ message(FATAL_ERROR "Excutable gdbus-codegen not found")
128+endif()
129+
130+function(add_gdbus_codegen)
131+ set(_one_value OUTFILES NAME PREFIX NAMESPACE SERVICE_XML)
132+ set(_multi_value DEPENDS)
133+ cmake_parse_arguments (arg "" "${_one_value}" "${_multi_value}" ${ARGN})
134+
135+ if(arg_PREFIX)
136+ set(PREFIX --interface-prefix ${arg_PREFIX})
137+ endif()
138+
139+ if(arg_NAMESPACE)
140+ set(NAMESPACE --c-namespace ${arg_NAMESPACE})
141+ endif()
142+
143+ add_custom_command(
144+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.h" "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c"
145+ COMMAND "${GDBUS_CODEGEN}"
146+ --generate-c-code "${arg_NAME}"
147+ ${PREFIX}
148+ ${NAMESPACE}
149+ "${arg_SERVICE_XML}"
150+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
151+ DEPENDS ${arg_DEPENDS} "${arg_SERVICE_XML}"
152+ )
153+ set(${arg_OUTFILES} ${${arg_OUTFILES}} "${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}.c" PARENT_SCOPE)
154+endfunction(add_gdbus_codegen)
155
156=== added directory 'data'
157=== added file 'data/com.canonical.powerd.xml'
158--- data/com.canonical.powerd.xml 1970-01-01 00:00:00 +0000
159+++ data/com.canonical.powerd.xml 2013-05-21 14:54:26 +0000
160@@ -0,0 +1,25 @@
161+<?xml version="1.0" encoding="UTF-8"?>
162+<node name="/">
163+ <interface name="com.canonical.powerd">
164+ <!-- Properties -->
165+
166+ <!-- Functions -->
167+ <method name="requestSysState">
168+ <arg type="i" name="state" direction="in" />
169+ <arg type="i" name="pid" direction="in" />
170+ <arg type="u" name="cookie" direction="out" />
171+ </method>
172+
173+ <method name="clearSysState">
174+ <arg type="u" name="cookie" direction="in" />
175+ </method>
176+
177+ <!-- for debug/testing -->
178+ <method name="listSysRequests">
179+ <arg type="a(si)" name="requestList" direction="out" />
180+ </method>
181+
182+ <!-- Signals -->
183+ <!-- None -->
184+ </interface>
185+</node>
186
187=== modified file 'debian/changelog'
188--- debian/changelog 2013-02-13 17:41:38 +0000
189+++ debian/changelog 2013-05-21 14:54:26 +0000
190@@ -1,3 +1,17 @@
191+powerd (0.6) raring; urgency=low
192+
193+ [ Michael Frey ]
194+ * Automatically suspend the device when inactive
195+
196+ [ Matthew Fischer ]
197+ * Add dbus methods for requesting system power states
198+
199+ [ Seth Forshee ]
200+ * Add a low-level platform-neutral suspend library
201+ * Modify code internally to use system power requests
202+
203+ -- Matthew Fischer <matthew.fischer@canonical.com> Tue, 21 May 2013 08:45:06 -0600
204+
205 powerd (0.5) quantal; urgency=low
206
207 * Dim / un-dim screen on suspend / resume.
208
209=== modified file 'debian/control'
210--- debian/control 2013-02-20 15:52:29 +0000
211+++ debian/control 2013-05-21 14:54:26 +0000
212@@ -8,11 +8,12 @@
213 libgudev-1.0-dev,
214 libhybris-dev,
215 libgles2-mesa-dev,
216+ python
217 Standards-Version: 3.9.3
218-Vcs-Bzr: lp:phablet-powerd
219+Vcs-Bzr: lp:powerd
220
221 Package: powerd
222-Architecture: armel armhf
223+Architecture: armhf
224 Depends: ${misc:Depends}, ${shlibs:Depends}
225 Description: Power daemon to monitor power button events.
226 This daemon provides monitoring capabilities for the ubuntu phone
227
228=== added file 'debian/install'
229--- debian/install 1970-01-01 00:00:00 +0000
230+++ debian/install 2013-05-21 14:54:26 +0000
231@@ -0,0 +1,1 @@
232+debian/powerd.conf etc/dbus-1/system.d/
233
234=== added file 'debian/powerd.conf'
235--- debian/powerd.conf 1970-01-01 00:00:00 +0000
236+++ debian/powerd.conf 2013-05-21 14:54:26 +0000
237@@ -0,0 +1,24 @@
238+<!-- This configuration file specifies the required security policies
239+ for powerd daemon to work. -->
240+
241+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
242+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
243+<busconfig>
244+
245+ <!-- ../system.conf have denied everything, so we just punch some holes -->
246+
247+ <policy user="root">
248+ <allow own="com.canonical.powerd"/>
249+ <allow send_destination="com.canonical.powerd"/>
250+ <allow send_interface="com.canonical.powerd"/>
251+ </policy>
252+
253+ <policy at_console="true">
254+ <allow send_destination="com.canonical.powerd"/>
255+ </policy>
256+
257+ <policy context="default">
258+ <deny send_destination="com.canonical.powerd"/>
259+ </policy>
260+
261+</busconfig>
262
263=== modified file 'debian/upstart'
264--- debian/upstart 2012-11-01 04:56:16 +0000
265+++ debian/upstart 2013-05-21 14:54:26 +0000
266@@ -24,8 +24,10 @@
267 export ANDROID_ROOT=/system
268 export EXTERNAL_STORAGE=/mnt/sdcard
269 export QT_PLUGIN_PATH=/opt/qt5/plugins
270-
271-
272+# for debugging purposes, remove when closer to shipping (mfisch)
273+export G_MESSAGES_DEBUG=all
274+
275+
276 exec /usr/bin/powerd
277
278 end script
279
280=== added directory 'libsuspend'
281=== added file 'libsuspend/CMakeLists.txt'
282--- libsuspend/CMakeLists.txt 1970-01-01 00:00:00 +0000
283+++ libsuspend/CMakeLists.txt 2013-05-21 14:54:26 +0000
284@@ -0,0 +1,12 @@
285+set(CMAKE_C_FLAGS "-Wall -Werror -Wextra")
286+
287+add_library(
288+ suspend
289+
290+ libsuspend.c
291+ sysfs.c
292+ autosleep.c
293+ earlysuspend.c
294+ legacy.c
295+ mocksuspend.c
296+)
297
298=== added file 'libsuspend/autosleep.c'
299--- libsuspend/autosleep.c 1970-01-01 00:00:00 +0000
300+++ libsuspend/autosleep.c 2013-05-21 14:54:26 +0000
301@@ -0,0 +1,49 @@
302+/*
303+ * Copyright 2013 Canonical Ltd.
304+ *
305+ * This file is part of powerd.
306+ *
307+ * powerd is free software; you can redistribute it and/or modify
308+ * it under the terms of the GNU General Public License as published by
309+ * the Free Software Foundation; version 3.
310+ *
311+ * powerd is distributed in the hope that it will be useful,
312+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314+ * GNU General Public License for more details.
315+ *
316+ * You should have received a copy of the GNU General Public License
317+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
318+ */
319+
320+#include <stdio.h>
321+#include "common.h"
322+#include "sysfs.h"
323+
324+static const char autosleep_path[] = "/sys/power/autosleep";
325+static const char mem_str[] = "mem";
326+static const char off_str[] = "off";
327+
328+static int autosleep_enter(void)
329+{
330+ int ret = sysfs_write(autosleep_path, mem_str, ARRAY_SIZE(mem_str) - 1);
331+ return ret < 0 ? ret : 0;
332+}
333+
334+static int autosleep_exit(void)
335+{
336+ int ret = sysfs_write(autosleep_path, mem_str, ARRAY_SIZE(off_str) - 1);
337+ return ret < 0 ? ret : 0;
338+}
339+
340+static const struct suspend_handler autosleep_handler = {
341+ .enter = autosleep_enter,
342+ .exit = autosleep_exit,
343+};
344+
345+const struct suspend_handler *autosleep_detect(void)
346+{
347+ if (!sysfs_file_exists(autosleep_path))
348+ return NULL;
349+ return &autosleep_handler;
350+}
351
352=== added file 'libsuspend/common.h'
353--- libsuspend/common.h 1970-01-01 00:00:00 +0000
354+++ libsuspend/common.h 2013-05-21 14:54:26 +0000
355@@ -0,0 +1,35 @@
356+/*
357+ * Copyright 2013 Canonical Ltd.
358+ *
359+ * This file is part of powerd.
360+ *
361+ * powerd is free software; you can redistribute it and/or modify
362+ * it under the terms of the GNU General Public License as published by
363+ * the Free Software Foundation; version 3.
364+ *
365+ * powerd is distributed in the hope that it will be useful,
366+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
367+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
368+ * GNU General Public License for more details.
369+ *
370+ * You should have received a copy of the GNU General Public License
371+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
372+ */
373+
374+#ifndef SUSPENDIF_H
375+#define SUSPENDIF_H
376+
377+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
378+
379+struct suspend_handler {
380+ int (*prepare)(void);
381+ int (*enter)(void);
382+ int (*exit)(void);
383+};
384+
385+const struct suspend_handler *autosleep_detect(void);
386+const struct suspend_handler *earlysuspend_detect(void);
387+const struct suspend_handler *legacy_detect(void);
388+const struct suspend_handler *mocksuspend_detect(void);
389+
390+#endif /* SUSPENDIF_H */
391
392=== added file 'libsuspend/earlysuspend.c'
393--- libsuspend/earlysuspend.c 1970-01-01 00:00:00 +0000
394+++ libsuspend/earlysuspend.c 2013-05-21 14:54:26 +0000
395@@ -0,0 +1,55 @@
396+/*
397+ * Copyright 2013 Canonical Ltd.
398+ *
399+ * This file is part of powerd.
400+ *
401+ * powerd is free software; you can redistribute it and/or modify
402+ * it under the terms of the GNU General Public License as published by
403+ * the Free Software Foundation; version 3.
404+ *
405+ * powerd is distributed in the hope that it will be useful,
406+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
407+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
408+ * GNU General Public License for more details.
409+ *
410+ * You should have received a copy of the GNU General Public License
411+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
412+ */
413+
414+#include <stdio.h>
415+#include "common.h"
416+#include "sysfs.h"
417+
418+static const char state_path[] = "/sys/power/state";
419+static const char wakelock_path[] = "/sys/power/wake_lock";
420+static const char autosleep_path[] = "/sys/power/autosleep";
421+
422+static const char mem_str[] = "mem";
423+static const char on_str[] = "on";
424+
425+static int earlysuspend_enter(void)
426+{
427+ int ret = sysfs_write(state_path, mem_str, ARRAY_SIZE(mem_str) - 1);
428+ return ret < 0 ? ret : 0;
429+}
430+
431+static int earlysuspend_exit(void)
432+{
433+ int ret = sysfs_write(state_path, on_str, ARRAY_SIZE(on_str) - 1);
434+ return ret < 0 ? ret : 0;
435+}
436+
437+static const struct suspend_handler earlysuspend_handler = {
438+ .enter = earlysuspend_enter,
439+ .exit = earlysuspend_exit,
440+};
441+
442+const struct suspend_handler *earlysuspend_detect(void)
443+{
444+ if (!sysfs_file_exists(autosleep_path) &&
445+ sysfs_file_exists(wakelock_path) &&
446+ sysfs_file_exists(state_path))
447+ return &earlysuspend_handler;
448+
449+ return NULL;
450+}
451
452=== added file 'libsuspend/legacy.c'
453--- libsuspend/legacy.c 1970-01-01 00:00:00 +0000
454+++ libsuspend/legacy.c 2013-05-21 14:54:26 +0000
455@@ -0,0 +1,82 @@
456+/*
457+ * Copyright 2013 Canonical Ltd.
458+ *
459+ * This file is part of powerd.
460+ *
461+ * powerd is free software; you can redistribute it and/or modify
462+ * it under the terms of the GNU General Public License as published by
463+ * the Free Software Foundation; version 3.
464+ *
465+ * powerd is distributed in the hope that it will be useful,
466+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
467+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
468+ * GNU General Public License for more details.
469+ *
470+ * You should have received a copy of the GNU General Public License
471+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
472+ */
473+
474+#include <stdio.h>
475+#include <string.h>
476+#include "common.h"
477+#include "sysfs.h"
478+
479+static const char state_path[] = "/sys/power/state";
480+static const char wakelock_path[] = "/sys/power/wake_lock";
481+static const char wakeup_count_path[] = "/sys/power/wakeup_count";
482+static const char mem_str[] = "mem";
483+
484+#define WAKEUP_COUNT_LEN 64
485+
486+static int wakeup_count_supported, wakeup_count_valid;
487+static char wakeup_count[WAKEUP_COUNT_LEN];
488+
489+static int legacy_prepare(void)
490+{
491+ int ret;
492+
493+ if (wakeup_count_supported) {
494+ ret = sysfs_read(wakeup_count_path, wakeup_count, WAKEUP_COUNT_LEN);
495+ if (ret < 0) {
496+ wakeup_count_valid = 0;
497+ return ret;
498+ }
499+ wakeup_count_valid = 1;
500+ }
501+
502+ return 0;
503+}
504+
505+static int legacy_enter(void)
506+{
507+ int ret;
508+
509+ if (wakeup_count_supported && wakeup_count_valid) {
510+ wakeup_count_valid = 0;
511+
512+ ret = sysfs_write(wakeup_count_path, wakeup_count,
513+ strlen(wakeup_count));
514+ if (ret < 0) {
515+ /* Wakup happened since reading wakeup_count */
516+ return ret;
517+ }
518+ }
519+
520+ ret = sysfs_write(state_path, mem_str, ARRAY_SIZE(mem_str) - 1);
521+ return ret < 0 ? ret : 0;
522+}
523+
524+static const struct suspend_handler legacy_handler = {
525+ .prepare = legacy_prepare,
526+ .enter = legacy_enter,
527+};
528+
529+const struct suspend_handler *legacy_detect(void)
530+{
531+ if (sysfs_file_exists(state_path) && !sysfs_file_exists(wakelock_path)) {
532+ wakeup_count_supported = sysfs_file_exists(wakeup_count_path);
533+ return &legacy_handler;
534+ }
535+
536+ return NULL;
537+}
538
539=== added file 'libsuspend/libsuspend.c'
540--- libsuspend/libsuspend.c 1970-01-01 00:00:00 +0000
541+++ libsuspend/libsuspend.c 2013-05-21 14:54:26 +0000
542@@ -0,0 +1,78 @@
543+/*
544+ * Copyright 2013 Canonical Ltd.
545+ *
546+ * This file is part of powerd.
547+ *
548+ * powerd is free software; you can redistribute it and/or modify
549+ * it under the terms of the GNU General Public License as published by
550+ * the Free Software Foundation; version 3.
551+ *
552+ * powerd is distributed in the hope that it will be useful,
553+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
554+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
555+ * GNU General Public License for more details.
556+ *
557+ * You should have received a copy of the GNU General Public License
558+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
559+ */
560+
561+#include <stdio.h>
562+#include <errno.h>
563+#include "libsuspend.h"
564+#include "common.h"
565+
566+const struct suspend_handler *handler;
567+
568+void libsuspend_init(int force_mock)
569+{
570+ if (!force_mock) {
571+ handler = autosleep_detect();
572+ if (handler)
573+ return;
574+
575+ handler = earlysuspend_detect();
576+ if (handler)
577+ return;
578+
579+ handler = legacy_detect();
580+ if (handler)
581+ return;
582+
583+ printf("No suspend interface detected, using mock suspend\n");
584+ }
585+
586+ handler = mocksuspend_detect();
587+}
588+
589+int libsuspend_prepare_suspend(void)
590+{
591+ if (!handler)
592+ return -ENODEV;
593+
594+ if (handler->prepare)
595+ return handler->prepare();
596+
597+ return 0;
598+}
599+
600+int libsuspend_enter_suspend(void)
601+{
602+ if (!handler)
603+ return -ENODEV;
604+
605+ if (handler->enter)
606+ return handler->enter();
607+
608+ return 0;
609+}
610+
611+int libsuspend_exit_suspend(void)
612+{
613+ if (!handler)
614+ return -ENODEV;
615+
616+ if (handler->exit)
617+ return handler->exit();
618+
619+ return 0;
620+}
621
622=== added file 'libsuspend/libsuspend.h'
623--- libsuspend/libsuspend.h 1970-01-01 00:00:00 +0000
624+++ libsuspend/libsuspend.h 2013-05-21 14:54:26 +0000
625@@ -0,0 +1,35 @@
626+/*
627+ * Copyright 2013 Canonical Ltd.
628+ *
629+ * This file is part of powerd.
630+ *
631+ * powerd is free software; you can redistribute it and/or modify
632+ * it under the terms of the GNU General Public License as published by
633+ * the Free Software Foundation; version 3.
634+ *
635+ * powerd is distributed in the hope that it will be useful,
636+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
637+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
638+ * GNU General Public License for more details.
639+ *
640+ * You should have received a copy of the GNU General Public License
641+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
642+ */
643+
644+#ifndef LIBSUSPEND_H
645+#define LIBSUSPEND_H
646+
647+#ifdef __cplusplus
648+extern "C" {
649+#endif
650+
651+void libsuspend_init(int force_mock);
652+int libsuspend_prepare_suspend(void);
653+int libsuspend_enter_suspend(void);
654+int libsuspend_exit_suspend(void);
655+
656+#ifdef __cplusplus
657+}
658+#endif
659+
660+#endif /* LIBSUSPEND_H */
661
662=== added file 'libsuspend/mocksuspend.c'
663--- libsuspend/mocksuspend.c 1970-01-01 00:00:00 +0000
664+++ libsuspend/mocksuspend.c 2013-05-21 14:54:26 +0000
665@@ -0,0 +1,49 @@
666+/*
667+ * Copyright 2013 Canonical Ltd.
668+ *
669+ * This file is part of powerd.
670+ *
671+ * powerd is free software; you can redistribute it and/or modify
672+ * it under the terms of the GNU General Public License as published by
673+ * the Free Software Foundation; version 3.
674+ *
675+ * powerd is distributed in the hope that it will be useful,
676+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
677+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
678+ * GNU General Public License for more details.
679+ *
680+ * You should have received a copy of the GNU General Public License
681+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
682+ */
683+
684+#include <stdio.h>
685+#include "common.h"
686+
687+static int mocksuspend_prepare(void)
688+{
689+ printf("mocksuspend prepare\n");
690+ return 0;
691+}
692+
693+static int mocksuspend_enter(void)
694+{
695+ printf("mocksuspend enter\n");
696+ return 0;
697+}
698+
699+static int mocksuspend_exit(void)
700+{
701+ printf("mocksuspend exit\n");
702+ return 0;
703+}
704+
705+static const struct suspend_handler mocksuspend_handler = {
706+ .prepare = mocksuspend_prepare,
707+ .enter = mocksuspend_enter,
708+ .exit = mocksuspend_exit,
709+};
710+
711+const struct suspend_handler *mocksuspend_detect(void)
712+{
713+ return &mocksuspend_handler;
714+}
715
716=== added file 'libsuspend/sysfs.c'
717--- libsuspend/sysfs.c 1970-01-01 00:00:00 +0000
718+++ libsuspend/sysfs.c 2013-05-21 14:54:26 +0000
719@@ -0,0 +1,62 @@
720+/*
721+ * Copyright 2013 Canonical Ltd.
722+ *
723+ * This file is part of powerd.
724+ *
725+ * powerd is free software; you can redistribute it and/or modify
726+ * it under the terms of the GNU General Public License as published by
727+ * the Free Software Foundation; version 3.
728+ *
729+ * powerd is distributed in the hope that it will be useful,
730+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
731+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
732+ * GNU General Public License for more details.
733+ *
734+ * You should have received a copy of the GNU General Public License
735+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
736+ */
737+
738+#include <sys/types.h>
739+#include <sys/stat.h>
740+#include <fcntl.h>
741+#include <unistd.h>
742+#include <errno.h>
743+
744+int sysfs_file_exists(const char *path)
745+{
746+ return !access(path, F_OK);
747+}
748+
749+int sysfs_read(const char *path, void *buf, int len)
750+{
751+ int fd;
752+ ssize_t ret;
753+
754+ fd = open(path, O_RDONLY);
755+ if (fd == -1)
756+ return -errno;
757+
758+ ret = read(fd, buf, len);
759+ if (ret == -1)
760+ ret = -errno;
761+
762+ close(fd);
763+ return ret;
764+}
765+
766+int sysfs_write(const char *path, const void *buf, int len)
767+{
768+ int fd;
769+ ssize_t ret;
770+
771+ fd = open(path, O_WRONLY);
772+ if (fd == -1)
773+ return -errno;
774+
775+ ret = write(fd, buf, len);
776+ if (ret == -1)
777+ ret = -errno;
778+
779+ close(fd);
780+ return ret;
781+}
782
783=== added file 'libsuspend/sysfs.h'
784--- libsuspend/sysfs.h 1970-01-01 00:00:00 +0000
785+++ libsuspend/sysfs.h 2013-05-21 14:54:26 +0000
786@@ -0,0 +1,26 @@
787+/*
788+ * Copyright 2013 Canonical Ltd.
789+ *
790+ * This file is part of powerd.
791+ *
792+ * powerd is free software; you can redistribute it and/or modify
793+ * it under the terms of the GNU General Public License as published by
794+ * the Free Software Foundation; version 3.
795+ *
796+ * powerd is distributed in the hope that it will be useful,
797+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
798+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
799+ * GNU General Public License for more details.
800+ *
801+ * You should have received a copy of the GNU General Public License
802+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
803+ */
804+
805+#ifndef SYSFS_H
806+#define SYSFS_H
807+
808+int sysfs_file_exists(const char *path);
809+int sysfs_read(const char *path, void *buf, int len);
810+int sysfs_write(const char *path, const void *buf, int len);
811+
812+#endif /* SYSFS_H */
813
814=== added file 'src/CMakeLists.txt'
815--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
816+++ src/CMakeLists.txt 2013-05-21 14:54:26 +0000
817@@ -0,0 +1,18 @@
818+include(UseGdbusCodegen)
819+include_directories(${CMAKE_CURRENT_BINARY_DIR})
820+
821+set(GDBUS_NAME powerd-dbus)
822+
823+set(POWERD_GENERATED_SOURCES
824+ ${GDBUS_NAME}.c
825+)
826+set(POWERD_GENERATED_HEADERS
827+ ${GDBUS_NAME}.h
828+)
829+
830+add_gdbus_codegen(
831+ OUTFILES POWERD_GENERATED_SOURCES
832+ NAME ${GDBUS_NAME}
833+ SERVICE_XML ${CMAKE_CURRENT_SOURCE_DIR}/../data/com.canonical.powerd.xml
834+)
835+ADD_CUSTOM_TARGET(dbus_bindings DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${POWERD_GENERATED_SOURCES})
836
837=== added file 'src/power-request.c'
838--- src/power-request.c 1970-01-01 00:00:00 +0000
839+++ src/power-request.c 2013-05-21 14:54:26 +0000
840@@ -0,0 +1,446 @@
841+/*
842+ * Copyright 2013 Canonical Ltd.
843+ *
844+ * This file is part of powerd.
845+ *
846+ * powerd is free software; you can redistribute it and/or modify
847+ * it under the terms of the GNU General Public License as published by
848+ * the Free Software Foundation; version 3.
849+ *
850+ * powerd is distributed in the hope that it will be useful,
851+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
852+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
853+ * GNU General Public License for more details.
854+ *
855+ * You should have received a copy of the GNU General Public License
856+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
857+ */
858+
859+#include <glib.h>
860+
861+#include <stddef.h>
862+#include <stdio.h>
863+#include <stdlib.h>
864+#include <unistd.h>
865+#include <fcntl.h>
866+#include <errno.h>
867+#include <string.h>
868+
869+#include <glib-object.h>
870+#include <gio/gio.h>
871+#include "powerd-internal.h"
872+#include "powerd-dbus.h"
873+
874+#include "libsuspend.h"
875+
876+struct SysStateRequest {
877+ GString *owner;
878+ int pid; /* uint? left as int so we can use -1 for implying that
879+ the request comes from no app specifically */
880+ enum SysPowerStates state;
881+ uint cookie;
882+};
883+
884+/* Current system power state */
885+static enum SysPowerStates current_system_state = POWERD_SYS_STATE_ACTIVE;
886+
887+/*
888+ * Lists for system power state requests, with one list for each power
889+ * level. Requests for the suspend state are not allowed, so the actual
890+ * number of lists is POWERD_NUM_POWER_STATES - 1.
891+ */
892+static GSList *sys_state_requests[POWERD_NUM_POWER_STATES - 1];
893+
894+#define INVALID_STATE -1
895+static GQueue queued_state_changes;
896+static enum SysPowerStates pending_system_state = INVALID_STATE;
897+
898+/*
899+ * Monotonically increasing value for use in generating unique cookies
900+ * for power state requests.
901+ *
902+ * XXX: Consider whether we might need something more random (i.e. not
903+ * guessable) for security purposes.
904+ */
905+static guint power_requeust_next_cookie;
906+
907+/* simple helper for debugging */
908+const gchar *
909+state_to_string(int state)
910+{
911+ switch (state) {
912+ case POWERD_SYS_STATE_ACTIVE: return "ACTIVE";
913+ case POWERD_SYS_STATE_SUSPEND: return "SUSPEND";
914+ default: return "UNKNOWN";
915+ }
916+}
917+
918+/* Returns TRUE if the state request is valid, FALSE otherwise.
919+ * Nobody can request the SUSPEND state. */
920+static gboolean
921+is_valid_state_request(int state)
922+{
923+ return state > POWERD_SYS_STATE_SUSPEND && state < POWERD_NUM_POWER_STATES;
924+}
925+
926+static GSList **
927+sys_request_list(int state)
928+{
929+ if (!is_valid_state_request(state))
930+ return NULL;
931+ return &sys_state_requests[state - 1];
932+}
933+
934+/* internal callers should pass in NULL for the builder, its only used
935+ * by dbus callers. Returns TRUE if there are any elements in any list,
936+ * FALSE otherwise. */
937+static gboolean
938+list_sys_requests_internal(GVariantBuilder *builder)
939+{
940+ gboolean ret = FALSE;
941+ GSList **list, *iterator = NULL;
942+ int i;
943+
944+ for (i = POWERD_SYS_STATE_SUSPEND + 1; i < POWERD_NUM_POWER_STATES; i++) {
945+ list = sys_request_list(i);
946+
947+ g_message("Requests for %s state:", state_to_string(i));
948+ if (*list == NULL) {
949+ g_message(" no requests active");
950+ }
951+ else {
952+ for (iterator = *list; iterator; iterator = iterator->next) {
953+ struct SysStateRequest *sr = (struct SysStateRequest *)iterator->data;
954+ // XXX - we should probably not dump the cookie here, it's a
955+ // security risk
956+ g_message(" Owner: %s, Pid: %d, Cookie: %u",
957+ sr->owner->str, sr->pid, sr->cookie);
958+ ret = TRUE;
959+ if (builder) {
960+ g_variant_builder_add(builder, "(si)", sr->owner->str, sr->pid);
961+ }
962+ }
963+ }
964+ }
965+ return ret;
966+}
967+
968+/* Dump the requests to stdout and return the list via dbus */
969+gboolean
970+handle_list_sys_requests(PowerdSource *obj, GDBusMethodInvocation *invocation)
971+{
972+ GVariant *list, *tuple = NULL;
973+ GVariantBuilder *builder;
974+ gboolean ret;
975+
976+ // XXX - fix me, we should be returning an empty list when there are
977+ // no elements
978+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
979+ ret = list_sys_requests_internal(builder);
980+ if (ret) {
981+ list = g_variant_builder_end(builder);
982+ // XXX - is a tuple with the first element as a list correct here? seems odd
983+ tuple = g_variant_new_tuple(&list,1);
984+ g_dbus_method_invocation_return_value(invocation, tuple);
985+ }
986+ else {
987+ g_dbus_method_invocation_return_value(invocation, NULL);
988+ }
989+ return TRUE;
990+}
991+
992+static gint
993+find_request_by_cookie(gconstpointer a, gconstpointer b) {
994+ struct SysStateRequest *sr_a = (struct SysStateRequest *)a;
995+ struct SysStateRequest *sr_b = (struct SysStateRequest *)b;
996+ return (sr_a->cookie == sr_b->cookie) ? 0 : 1;
997+}
998+
999+/* Note: invocation is NULL for internal usage */
1000+gboolean
1001+request_sys_state_internal(GDBusMethodInvocation *invocation, int state, int pid, uint *cookie)
1002+{
1003+ GSList **list, *item = NULL;
1004+ struct SysStateRequest *sr = NULL;
1005+
1006+ if (cookie == NULL) {
1007+ g_error("you need to pass in memory for a cookie");
1008+ return FALSE;
1009+ }
1010+
1011+ if (!is_valid_state_request(state))
1012+ {
1013+ g_warning("invalid state requested: %d",state);
1014+ if (invocation) {
1015+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
1016+ G_DBUS_ERROR_INVALID_ARGS,"Invalid state requested %d",state);
1017+ }
1018+ return FALSE;
1019+ }
1020+
1021+ list = sys_request_list(state);
1022+ if (!list) {
1023+ /* Should never hit this code since we've already verified that
1024+ * the state is valid */
1025+ g_error("Could not get request list for state %d (%s)", state,
1026+ state_to_string(state));
1027+ if (invocation) {
1028+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
1029+ G_DBUS_ERROR_INVALID_ARGS, "Invalid state requested %d",state);
1030+ }
1031+ return FALSE;
1032+ }
1033+
1034+ sr = g_new(struct SysStateRequest, 1);
1035+ sr->state = (enum SysPowerStates)state;
1036+ sr->pid = pid;
1037+ if (invocation) {
1038+ sr->owner = g_string_new(g_dbus_method_invocation_get_sender(invocation));
1039+ }
1040+ else {
1041+ sr->owner = g_string_new("internal");
1042+ }
1043+
1044+ // The request is valid at this point, create a cookie and insert into list
1045+ *cookie = g_atomic_int_add(&power_requeust_next_cookie, 1);
1046+ sr->cookie = *cookie;
1047+ *list = g_slist_append(*list, sr);
1048+ update_system_state();
1049+ return TRUE;
1050+}
1051+
1052+gboolean
1053+handle_request_sys_state (PowerdSource *obj, GDBusMethodInvocation *invocation, int state, int pid)
1054+{
1055+ gboolean retval = FALSE;
1056+ GVariant *gvCookie, *ret = NULL;
1057+ guint cookie;
1058+
1059+ g_debug("handle_requestSysState from %s: %d - %s (%d)",
1060+ g_dbus_method_invocation_get_sender(invocation), pid,
1061+ state_to_string(state), state);
1062+
1063+ retval = request_sys_state_internal(invocation, state, pid, &cookie);
1064+ if (retval == TRUE) {
1065+ gvCookie = g_variant_new_uint32(cookie);
1066+ ret = g_variant_new_tuple(&gvCookie,1);
1067+ g_debug("handle_requestSysState - SUCCESS");
1068+ g_dbus_method_invocation_return_value(invocation, ret);
1069+ }
1070+ return retval;
1071+}
1072+
1073+gboolean
1074+clear_sys_state_internal(GDBusMethodInvocation *invocation, uint cookie)
1075+{
1076+ struct SysStateRequest *tmpsr = NULL;
1077+ GSList **list, *matched_requests = NULL;
1078+ int i;
1079+
1080+ tmpsr = g_new(struct SysStateRequest, 1);
1081+ tmpsr->cookie = cookie;
1082+
1083+ for (i = POWERD_SYS_STATE_SUSPEND + 1; i < POWERD_NUM_POWER_STATES; i++) {
1084+ list = sys_request_list(i);
1085+ if (!list)
1086+ continue;
1087+
1088+ matched_requests = g_slist_find_custom(*list, tmpsr, find_request_by_cookie);
1089+
1090+ if (matched_requests)
1091+ break;
1092+ }
1093+ g_free(tmpsr);
1094+
1095+ if (matched_requests == NULL)
1096+ {
1097+ g_warning("request (%u) not found", cookie);
1098+ if (invocation)
1099+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1100+ "No request with cookie: %u", cookie);
1101+ return FALSE;
1102+ }
1103+
1104+ for ( ; matched_requests; matched_requests = matched_requests->next) {
1105+ struct SysStateRequest *sr = (struct SysStateRequest *)matched_requests->data;
1106+ g_debug("removing an element: %u",sr->cookie);
1107+ *list = g_slist_remove_all(*list, sr);
1108+ }
1109+
1110+ g_slist_free_full(matched_requests, sys_state_request_destroy);
1111+ update_system_state();
1112+ return TRUE;
1113+}
1114+
1115+gboolean
1116+handle_clear_sys_state (PowerdSource *obj, GDBusMethodInvocation *invocation, uint cookie)
1117+{
1118+ gboolean retval = FALSE;
1119+ g_debug("handle_clearSysState from %s, cookie: %u",
1120+ g_dbus_method_invocation_get_sender(invocation), cookie);
1121+
1122+ retval = clear_sys_state_internal(invocation, cookie);
1123+ if (retval == TRUE) {
1124+ g_dbus_method_invocation_return_value(invocation, NULL);
1125+ }
1126+ return retval;
1127+}
1128+
1129+gboolean any_active_sys_state_requests(void)
1130+{
1131+ GSList **list = sys_request_list(POWERD_SYS_STATE_ACTIVE);
1132+ if (list && *list)
1133+ return TRUE;
1134+ return FALSE;
1135+}
1136+
1137+static enum SysPowerStates max_requested_state(void)
1138+{
1139+ int i;
1140+ GSList **list;
1141+
1142+ for (i = POWERD_NUM_POWER_STATES - 1; i > POWERD_SYS_STATE_SUSPEND; i--) {
1143+ list = sys_request_list(i);
1144+ if (list && *list)
1145+ return i;
1146+ };
1147+
1148+ return POWERD_SYS_STATE_SUSPEND;
1149+}
1150+
1151+static void check_queued_state_changes(void)
1152+{
1153+ enum SysPowerStates new_state;
1154+ int ret;
1155+
1156+ /*
1157+ * If state change in progress we'll process the next queued state
1158+ * change when finished.
1159+ */
1160+ if (pending_system_state != INVALID_STATE) {
1161+ g_debug("state change in progress, delaying");
1162+ return;
1163+ }
1164+
1165+ if (g_queue_is_empty(&queued_state_changes)) {
1166+ g_debug("no pending state changes");
1167+ return;
1168+ }
1169+
1170+ pending_system_state = (enum SysPowerStates)g_queue_pop_head(&queued_state_changes);
1171+ if (pending_system_state == current_system_state) {
1172+ g_debug("pending state == current state, discarding");
1173+ pending_system_state = INVALID_STATE;
1174+ return;
1175+ }
1176+
1177+ /*
1178+ * XXX: This code needs to be split up. Here's what it needs to do:
1179+ *
1180+ * 1. If going to suspend, possibly delay a few seconds to see if
1181+ * any new active requests come in. If so, abort the suspend
1182+ * transition.
1183+ * 2. Send out the signal to prepare for the state change.
1184+ * 3. Wait for acks or the timeout period to elapse.
1185+ * 4. Complete the state transition. If going to suspend, check to
1186+ * be sure that there's not a queued request to transition to a
1187+ * higher state, and if not tell the kernel to suspend.
1188+ */
1189+ if (current_system_state == POWERD_SYS_STATE_SUSPEND) {
1190+ g_debug("exiting suspend");
1191+ ret = libsuspend_exit_suspend();
1192+ if (ret)
1193+ g_warning("Failed to exit suspend: %d\n", ret);
1194+ } else if (pending_system_state == POWERD_SYS_STATE_SUSPEND &&
1195+ g_queue_is_empty(&queued_state_changes)) {
1196+ g_debug("entering suspend");
1197+ ret = libsuspend_prepare_suspend();
1198+ if (ret)
1199+ g_warning("Failed to prepare for suspend: %d\n", ret);
1200+ /* XXX: Here is where notifications should be sent out */
1201+ ret = libsuspend_enter_suspend();
1202+ if (ret)
1203+ g_warning("Failed to enter suspend: %d\n", ret);
1204+ }
1205+
1206+ current_system_state = pending_system_state;
1207+ pending_system_state = INVALID_STATE;
1208+}
1209+
1210+/*
1211+ * XXX: Currently the coalescing is very simplistic and may need
1212+ * improvement.
1213+ */
1214+static void enqueue_state_change(enum SysPowerStates state)
1215+{
1216+ gboolean queue_empty;
1217+
1218+ g_debug("Enqueue state change to %s", state_to_string(state));
1219+
1220+ /*
1221+ * If the new request is the same as the one we're currently
1222+ * processing we can drop all pending requests (including the
1223+ * new one).
1224+ */
1225+ if (pending_system_state == state) {
1226+ g_debug("State == pending state, discarding");
1227+ g_queue_clear(&queued_state_changes);
1228+ return;
1229+ } else if (pending_system_state == INVALID_STATE) {
1230+ queue_empty = g_queue_is_empty(&queued_state_changes);
1231+
1232+ /*
1233+ * If no state changes are pending or in progress and the
1234+ * requested state is the same as the current state, do nothing.
1235+ */
1236+ if (queue_empty && state == current_system_state) {
1237+ g_debug("queue empty && state == current, discarding");
1238+ return;
1239+ }
1240+
1241+ /*
1242+ * If we aren't processing a request and the current request is
1243+ * the same as the next reques in the queue, all intermediate
1244+ * requests can be dropped. We do this by clearing the queue and
1245+ * then adding in the new request.
1246+ *
1247+ * XXX: This situation is probably impossible currently.
1248+ */
1249+ if (!queue_empty &&
1250+ (enum SysPowerStates)g_queue_peek_tail(&queued_state_changes) == state) {
1251+ g_debug("new state == next queued state, discarding all intermediate requests");
1252+ g_queue_clear(&queued_state_changes);
1253+ }
1254+ }
1255+
1256+ g_queue_push_tail(&queued_state_changes, (gpointer)state);
1257+ check_queued_state_changes();
1258+}
1259+
1260+void update_system_state(void)
1261+{
1262+ enqueue_state_change(max_requested_state());
1263+}
1264+
1265+void power_request_init(void)
1266+{
1267+ g_queue_init(&queued_state_changes);
1268+}
1269+
1270+// Destructor for the state request object
1271+void sys_state_request_destroy(gpointer data)
1272+{
1273+ struct SysStateRequest *sr = (struct SysStateRequest *)data;
1274+ if (sr->owner) {
1275+ g_free(sr->owner);
1276+ sr->owner = NULL;
1277+ }
1278+}
1279+
1280+void power_request_deinit(void)
1281+{
1282+ int i;
1283+ for (i = POWERD_SYS_STATE_SUSPEND + 1; i < POWERD_NUM_POWER_STATES; i++)
1284+ g_slist_free_full(sys_state_requests[i-1], sys_state_request_destroy);
1285+ g_queue_clear(&queued_state_changes);
1286+}
1287
1288=== added file 'src/powerd-internal.h'
1289--- src/powerd-internal.h 1970-01-01 00:00:00 +0000
1290+++ src/powerd-internal.h 2013-05-21 14:54:26 +0000
1291@@ -0,0 +1,63 @@
1292+/*
1293+ * Copyright 2013 Canonical Ltd.
1294+ *
1295+ * This file is part of powerd.
1296+ *
1297+ * powerd is free software; you can redistribute it and/or modify
1298+ * it under the terms of the GNU General Public License as published by
1299+ * the Free Software Foundation; version 3.
1300+ *
1301+ * powerd is distributed in the hope that it will be useful,
1302+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1303+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1304+ * GNU General Public License for more details.
1305+ *
1306+ * You should have received a copy of the GNU General Public License
1307+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1308+ */
1309+
1310+#ifndef __POWERD_INTERNAL_H__
1311+#define __POWERD_INTERNAL_H__
1312+
1313+#include "powerd-object.h"
1314+#include "powerd.h"
1315+
1316+#ifdef __cplusplus
1317+extern "C" {
1318+#endif
1319+
1320+void powerd_exit(void);
1321+
1322+/* System power state requests */
1323+gboolean handle_list_sys_requests(PowerdSource *obj,
1324+ GDBusMethodInvocation *invocation);
1325+gboolean handle_request_sys_state(PowerdSource *obj,
1326+ GDBusMethodInvocation *invocation,
1327+ int state, int pid);
1328+gboolean handle_clear_sys_state(PowerdSource *obj,
1329+ GDBusMethodInvocation *invocation,
1330+ uint cookie);
1331+gboolean request_sys_state_internal(GDBusMethodInvocation *invocation,
1332+ int state, int pid, uint *cookie);
1333+gboolean clear_sys_state_internal(GDBusMethodInvocation *invocation,
1334+ uint cookie);
1335+gboolean any_active_sys_state_requests(void);
1336+void update_system_state(void);
1337+void power_request_init(void);
1338+void power_request_deinit(void);
1339+void sys_state_request_destroy(gpointer data);
1340+const gchar * state_to_string(int state);
1341+
1342+/* dbus callbacks */
1343+void powerd_bus_acquired_cb(GDBusConnection *connection, const gchar *name,
1344+ gpointer user_data);
1345+void powerd_name_acquired_cb(GDBusConnection *connection, const gchar *name,
1346+ gpointer user_data);
1347+void powerd_name_lost_cb(GDBusConnection *connection, const gchar *name,
1348+ gpointer user_data);
1349+
1350+#ifdef __cplusplus
1351+}
1352+#endif
1353+
1354+#endif
1355
1356=== added file 'src/powerd-object.c'
1357--- src/powerd-object.c 1970-01-01 00:00:00 +0000
1358+++ src/powerd-object.c 2013-05-21 14:54:26 +0000
1359@@ -0,0 +1,125 @@
1360+/*
1361+ * Copyright 2013 Canonical Ltd.
1362+ *
1363+ * This file is part of powerd.
1364+ *
1365+ * powerd is free software; you can redistribute it and/or modify
1366+ * it under the terms of the GNU General Public License as published by
1367+ * the Free Software Foundation; version 3.
1368+ *
1369+ * powerd is distributed in the hope that it will be useful,
1370+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1371+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1372+ * GNU General Public License for more details.
1373+ *
1374+ * You should have received a copy of the GNU General Public License
1375+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1376+ */
1377+
1378+#include <glib.h>
1379+#include <glib-object.h>
1380+#include <gio/gio.h>
1381+#include "powerd-internal.h"
1382+#include "powerd-dbus.h"
1383+
1384+struct _PowerdSourcePrivate {
1385+ GDBusConnection * system_bus;
1386+ const gchar * path;
1387+ ComCanonicalPowerd * skel;
1388+};
1389+
1390+static void powerd_source_class_init (PowerdSourceClass * klass);
1391+static void powerd_source_init (PowerdSource * self);
1392+static void powerd_source_dispose (GObject * object);
1393+static void powerd_source_finalize (GObject * object);
1394+
1395+G_DEFINE_TYPE (PowerdSource, powerd_source, G_TYPE_OBJECT);
1396+
1397+#define POWERD_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POWERD_TYPE_SOURCE, PowerdSourcePrivate))
1398+
1399+/* Instance */
1400+static void
1401+powerd_source_init (PowerdSource *self)
1402+{
1403+ self->priv = POWERD_SOURCE_GET_PRIVATE(self);
1404+ self->priv->system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
1405+ return;
1406+}
1407+
1408+/* Class Init */
1409+static void
1410+powerd_source_class_init (PowerdSourceClass *self)
1411+{
1412+ GObjectClass *object_class = G_OBJECT_CLASS (self);
1413+ g_type_class_add_private (self, sizeof (PowerdSourcePrivate));
1414+ object_class->dispose = powerd_source_dispose;
1415+ object_class->finalize = powerd_source_finalize;
1416+ return;
1417+}
1418+
1419+/* Clean up references */
1420+static void
1421+powerd_source_dispose (GObject *object)
1422+{
1423+ PowerdSource * self = POWERD_SOURCE(object);
1424+ if (self->priv->skel != NULL) {
1425+ g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(self->priv->skel));
1426+ g_clear_object(&self->priv->skel);
1427+ }
1428+ g_clear_object(&self->priv->system_bus);
1429+ return;
1430+}
1431+
1432+/* Free memory */
1433+static void
1434+powerd_source_finalize (GObject *object)
1435+{
1436+ return;
1437+}
1438+
1439+void
1440+powerd_bus_acquired_cb (GDBusConnection *connection,
1441+ const gchar *name,
1442+ gpointer user_data)
1443+{
1444+ GError *error = NULL;
1445+ PowerdSource *source = NULL;
1446+
1447+ g_debug("Bus acquired (guid %s)", g_dbus_connection_get_guid (connection));
1448+ source = (PowerdSource *)g_object_new(POWERD_TYPE_SOURCE, NULL);
1449+ source->priv->skel = com_canonical_powerd_skeleton_new();
1450+ source->priv->path = "/com/canonical/powerd";
1451+
1452+ if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(source->priv->skel),
1453+ source->priv->system_bus, source->priv->path, &error)) {
1454+ g_error("Unable to export skeleton on path '%s': %s", source->priv->path,
1455+ error->message);
1456+ g_error_free(error);
1457+ error = NULL;
1458+ powerd_exit();
1459+ }
1460+
1461+ g_signal_connect(G_OBJECT(source->priv->skel), "handle-request-sys-state",
1462+ G_CALLBACK(handle_request_sys_state), source);
1463+ g_signal_connect(G_OBJECT(source->priv->skel), "handle-clear-sys-state",
1464+ G_CALLBACK(handle_clear_sys_state), source);
1465+ g_signal_connect(G_OBJECT(source->priv->skel), "handle-list-sys-requests",
1466+ G_CALLBACK(handle_list_sys_requests), source);
1467+}
1468+
1469+void
1470+powerd_name_acquired_cb (GDBusConnection *connection,
1471+ const gchar *name,
1472+ gpointer user_data)
1473+{
1474+ g_debug("name acquired (%s)", name);
1475+}
1476+
1477+void
1478+powerd_name_lost_cb (GDBusConnection *connection,
1479+ const gchar *name,
1480+ gpointer user_data)
1481+{
1482+ g_warning("name lost (%s)", name);
1483+ //XXX - quit here
1484+}
1485
1486=== added file 'src/powerd-object.h'
1487--- src/powerd-object.h 1970-01-01 00:00:00 +0000
1488+++ src/powerd-object.h 2013-05-21 14:54:26 +0000
1489@@ -0,0 +1,60 @@
1490+/*
1491+ * Copyright 2013 Canonical Ltd.
1492+ *
1493+ * This file is part of powerd.
1494+ *
1495+ * powerd is free software; you can redistribute it and/or modify
1496+ * it under the terms of the GNU General Public License as published by
1497+ * the Free Software Foundation; version 3.
1498+ *
1499+ * powerd is distributed in the hope that it will be useful,
1500+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1501+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1502+ * GNU General Public License for more details.
1503+ *
1504+ * You should have received a copy of the GNU General Public License
1505+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1506+ */
1507+
1508+#ifndef __POWERD_OBJECT_H__
1509+#define __POWERD_OBJECT_H__
1510+
1511+#include <glib-object.h>
1512+
1513+#ifdef __cplusplus
1514+extern "C" {
1515+#endif
1516+
1517+G_BEGIN_DECLS
1518+
1519+#define POWERD_TYPE_SOURCE (powerd_source_get_type ())
1520+#define POWERD_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POWERD_TYPE_SOURCE, PowerdSource))
1521+#define POWERD_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POWERD_TYPE_SOURCE))
1522+#define POWERD_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POWERD_TYPE_SOURCE, PowerdSourceClass))
1523+#define POWERD_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POWERD_TYPE_SOURCE))
1524+#define POWERD_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), POWERD_TYPE_SOURCE, PowerdSourceClass))
1525+
1526+struct _PowerdSourcePrivate;
1527+
1528+typedef struct _PowerdSource PowerdSource;
1529+typedef struct _PowerdSourceClass PowerdSourceClass;
1530+typedef struct _PowerdSourcePrivate PowerdSourcePrivate;
1531+
1532+struct _PowerdSourceClass {
1533+ GObjectClass parent_class;
1534+};
1535+
1536+struct _PowerdSource {
1537+ GObject parent;
1538+ PowerdSourcePrivate * priv;
1539+};
1540+
1541+GType powerd_source_get_type (void);
1542+
1543+G_END_DECLS
1544+
1545+#ifdef __cplusplus
1546+}
1547+#endif
1548+
1549+#endif
1550
1551=== modified file 'src/powerd.cpp'
1552--- src/powerd.cpp 2013-02-20 15:42:12 +0000
1553+++ src/powerd.cpp 2013-05-21 14:54:26 +0000
1554@@ -1,6 +1,11 @@
1555 /*
1556 * Copyright 2013 Canonical Ltd.
1557 *
1558+ * Authors:
1559+ * Michael Frey: michael.frey@canonical.com
1560+ * Matthew Fischer: matthew.fischer@canonical.com
1561+ * Seth Forshee: seth.forshee@canonical.com
1562+ *
1563 * This file is part of powerd.
1564 *
1565 * powerd is free software; you can redistribute it and/or modify
1566@@ -27,12 +32,21 @@
1567 #include <fcntl.h>
1568 #include <errno.h>
1569 #include <string.h>
1570+#include <sys/types.h>
1571+
1572+#include <glib-object.h>
1573+#include <gio/gio.h>
1574+#include "powerd-internal.h"
1575+#include "powerd-object.h"
1576+#include "powerd-dbus.h"
1577
1578 #include <hybris/input/input_stack_compatibility_layer.h>
1579 #include <hybris/input/input_stack_compatibility_layer_codes_key.h>
1580
1581 #include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
1582
1583+#include "libsuspend.h"
1584+
1585 namespace
1586 {
1587
1588@@ -43,20 +57,6 @@
1589 OUR_FD_COUNT
1590 };
1591
1592-const char * const PATHS[] = {
1593- "/sys/power/wake_lock",
1594- "/sys/power/wake_unlock",
1595- "/sys/power/state"
1596-};
1597-
1598-static const char *off_state = "mem";
1599-static const char *on_state = "on";
1600-
1601-static bool in_suspend = false;
1602-static int g_initialized = 0;
1603-static int g_fds[OUR_FD_COUNT];
1604-static int g_error = 1;
1605-
1606 static uint button_timer = 0;
1607 static uint activity_timer = 0;
1608
1609@@ -68,6 +68,8 @@
1610 static gchar *brightness_path;
1611
1612 static int ACTIVITY_TIMEOUT = 30;
1613+static GMainLoop *main_loop = NULL;
1614+static guint name_id;
1615
1616 enum state {
1617 BUTTON_DOWN,
1618@@ -77,6 +79,16 @@
1619
1620 static state button_state = BUTTON_UP;
1621
1622+enum screen_state {
1623+ SCREEN_OFF,
1624+ SCREEN_ON
1625+};
1626+
1627+static enum screen_state current_screen_state = SCREEN_ON;
1628+static uint internal_request_cookie;
1629+static bool internal_cookie_valid;
1630+
1631+gboolean activity_monitor(gpointer data);
1632
1633 void get_brightness_path (void)
1634 {
1635@@ -100,11 +112,9 @@
1636 (g_strcmp0 (device_type, "platform") == 0) ||
1637 (g_strcmp0 (device_type, "raw") == 0)) {
1638 brightness_path = g_strdup (g_udev_device_get_sysfs_path ((GUdevDevice *)device->data));
1639- g_print ("found: %s\n", brightness_path);
1640 break;
1641 }
1642 }
1643- g_print ("found2: %s\n", brightness_path);
1644
1645 g_list_foreach (devices, (GFunc) g_object_unref, NULL);
1646 g_list_free (devices);
1647@@ -167,110 +177,103 @@
1648
1649 }
1650
1651-static int
1652-open_file_descriptors(const char * const paths[])
1653-{
1654- int i;
1655- for (i=0; i<OUR_FD_COUNT; i++) {
1656- int fd = open(paths[i], O_RDWR);
1657- if (fd < 0) {
1658- fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
1659- g_error = errno;
1660- return -1;
1661- }
1662- g_fds[i] = fd;
1663- }
1664-
1665- g_error = 0;
1666- return 0;
1667-}
1668-
1669-static inline void
1670-initialize_fds(void)
1671-{
1672- if (g_initialized == 0) {
1673- if(open_file_descriptors(PATHS) < 0) {
1674- on_state = "on";
1675- off_state = "mem";
1676- }
1677- g_initialized = 1;
1678- }
1679-}
1680-
1681-
1682 gboolean call_shutdown(gpointer data)
1683 {
1684- gchar *argv[] = {"poweroff",
1685+ static char poweroff_cmd[] = "poweroff";
1686+ gchar *argv[] = {poweroff_cmd,
1687 NULL};
1688+
1689 if (button_state == BUTTON_DOWN) {
1690 button_state = SHUTDOWN;
1691 brightness_set_value(0);
1692 sf_blank(0);
1693 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
1694 }
1695-}
1696-
1697-int set_screen_state(void)
1698-{
1699- initialize_fds();
1700-
1701- if (g_error)
1702- goto failure;
1703-
1704- char buf[32];
1705- int len;
1706- if(in_suspend) {
1707- len = snprintf(buf, sizeof(buf), "%s", on_state);
1708- in_suspend = false;
1709- } else {
1710- if (activity_timer > 0) {
1711- g_source_remove(activity_timer);
1712- activity_timer = 0;
1713- }
1714+
1715+}
1716+
1717+void reset_activity_timer(int add)
1718+{
1719+ if (activity_timer > 0) {
1720+ g_source_remove(activity_timer);
1721+ activity_timer = 0;
1722+ }
1723+ if (add)
1724+ activity_timer = g_timeout_add_seconds(ACTIVITY_TIMEOUT, activity_monitor, NULL);
1725+}
1726+
1727+
1728+int set_screen_state(enum screen_state new_state)
1729+{
1730+ int ret;
1731+
1732+ g_debug("set_screen_state: current %s (%d) new %s (%d)",
1733+ state_to_string(current_screen_state), current_screen_state,
1734+ state_to_string(new_state), new_state);
1735+
1736+ if (current_screen_state == new_state)
1737+ return 0;
1738+
1739+ switch (new_state) {
1740+ case SCREEN_OFF:
1741+ reset_activity_timer(0);
1742 saved_brightness = brightness_get_value();
1743 brightness_set_value(0);
1744 sf_blank(0);
1745- len = snprintf(buf, sizeof(buf), "%s", off_state);
1746- in_suspend = true;
1747- }
1748-
1749- buf[sizeof(buf) - 1] = '\0';
1750- len = write(g_fds[REQUEST_STATE], buf, len);
1751- if(len < 0) {
1752- failure:
1753- printf("Failed setting last user activity: g_error=%d\n", g_error);
1754- }
1755-
1756- //Need to wait for system wakeup otherwise we will get
1757- //permission denied if we try to ake the screen up before that.
1758- if (!in_suspend) {
1759+
1760+ g_debug("Releasing internal active state request");
1761+ ret = clear_sys_state_internal(NULL, internal_request_cookie);
1762+ if (!ret)
1763+ g_warning("Internal system state request cookie invalid: %d\n",
1764+ internal_request_cookie);
1765+ break;
1766+ case SCREEN_ON:
1767+ g_debug("Requesting active state internally");
1768+ ret = request_sys_state_internal(NULL, POWERD_SYS_STATE_ACTIVE,
1769+ getpid(), &internal_request_cookie);
1770+ if (!ret)
1771+ g_warning("Request for active state failed");
1772+
1773+ /* Need to wait for system wakeup before waking screen */
1774 sleep(1);
1775 sf_unblank(0);
1776 brightness_set_value(saved_brightness);
1777+
1778+ activity_timer = g_timeout_add_seconds(ACTIVITY_TIMEOUT, activity_monitor, NULL);
1779+ break;
1780+ default:
1781+ g_warning("Invalid screen state %d", new_state);
1782+ return -1;
1783 }
1784
1785+ current_screen_state = new_state;
1786 return 0;
1787 }
1788
1789+gboolean activity_monitor(gpointer data)
1790+{
1791+ set_screen_state(SCREEN_OFF);
1792+}
1793
1794 void on_new_event(Event* event, void* context)
1795 {
1796-
1797- if (activity_timer > 0) {
1798- g_source_remove(activity_timer);
1799- activity_timer = 0;
1800- }
1801-
1802 switch(event->type)
1803 {
1804 case KEY_EVENT_TYPE:
1805 if (event->details.key.key_code == ISCL_KEYCODE_POWER && button_state != SHUTDOWN) {
1806 if (event->action == 1) {
1807+ g_debug("power button pressed");
1808 button_state = BUTTON_UP;
1809 curtime = time(0);
1810 tm = localtime (&curtime);
1811- if (tm->tm_sec - lasttime < 2)
1812- set_screen_state();
1813+ if (tm->tm_sec - lasttime < 2) {
1814+ enum screen_state new_state;
1815+ if (current_screen_state == SCREEN_OFF)
1816+ new_state = SCREEN_ON;
1817+ else
1818+ new_state = SCREEN_OFF;
1819+ set_screen_state(new_state);
1820+ }
1821 } else if (event->action == 0) {
1822 button_state = BUTTON_DOWN;
1823 curtime = time(0);
1824@@ -278,7 +281,7 @@
1825 lasttime = tm->tm_sec;
1826 if (button_timer > 0)
1827 {
1828- g_source_remove(button_timer);
1829+ g_source_remove(button_timer);
1830 button_timer = 0;
1831 }
1832 button_timer = g_timeout_add_seconds(2, call_shutdown, NULL);
1833@@ -286,19 +289,49 @@
1834 }
1835 break;
1836 default:
1837+ reset_activity_timer(1);
1838 break;
1839 }
1840 }
1841
1842-}
1843-
1844+void powerd_exit(void)
1845+{
1846+ g_main_loop_quit(main_loop);
1847+}
1848+
1849+static void
1850+sigterm_quit(int signal)
1851+{
1852+ g_warning("SIGTERM recieved, cleaning up");
1853+ // XXX - strangely this call to unown name claims the id is invalid
1854+ // but I'm sure we're using it properly
1855+ g_bus_unown_name(name_id);
1856+ g_main_loop_quit(main_loop);
1857+}
1858+
1859+} //namespace
1860
1861 int main(int argc, char** argv)
1862 {
1863-
1864- GMainLoop* main_loop = NULL;
1865+ int i, ret;
1866+
1867+ g_type_init();
1868+ name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, "com.canonical.powerd",
1869+ G_BUS_NAME_OWNER_FLAGS_REPLACE, powerd_bus_acquired_cb,
1870+ powerd_name_acquired_cb, powerd_name_lost_cb, NULL, NULL);
1871+ g_debug("owner id: %u", name_id);
1872+
1873+ libsuspend_init(0);
1874+ power_request_init();
1875+
1876+ /* We start in the active state, so take a request */
1877+ ret = request_sys_state_internal(NULL, POWERD_SYS_STATE_ACTIVE,
1878+ getpid(), &internal_request_cookie);
1879+ if (!ret)
1880+ g_warning("Initial request for active state failed");
1881
1882 main_loop = g_main_loop_new (NULL, FALSE);
1883+ signal(SIGTERM, sigterm_quit);
1884
1885 AndroidEventListener listener;
1886 listener.on_new_event = on_new_event;
1887@@ -312,11 +345,16 @@
1888 android_input_stack_initialize(&listener, &config);
1889 android_input_stack_start();
1890
1891- g_type_init();
1892 get_brightness_path();
1893+ activity_timer = g_timeout_add_seconds(ACTIVITY_TIMEOUT, activity_monitor, NULL);
1894+
1895 g_main_loop_run(main_loop);
1896+ g_bus_unown_name(name_id);
1897+ g_main_loop_unref(main_loop);
1898
1899 android_input_stack_stop();
1900 android_input_stack_shutdown();
1901+
1902+ power_request_deinit();
1903+ return 0;
1904 }
1905-
1906
1907=== added file 'src/powerd.h'
1908--- src/powerd.h 1970-01-01 00:00:00 +0000
1909+++ src/powerd.h 2013-05-21 14:54:26 +0000
1910@@ -0,0 +1,41 @@
1911+/*
1912+ * Copyright 2013 Canonical Ltd.
1913+ *
1914+ * This file is part of powerd.
1915+ *
1916+ * powerd is free software; you can redistribute it and/or modify
1917+ * it under the terms of the GNU General Public License as published by
1918+ * the Free Software Foundation; version 3.
1919+ *
1920+ * powerd is distributed in the hope that it will be useful,
1921+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1922+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1923+ * GNU General Public License for more details.
1924+ *
1925+ * You should have received a copy of the GNU General Public License
1926+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1927+ */
1928+
1929+#ifndef __POWERD_H__
1930+#define __POWERD_H__
1931+
1932+#ifdef __cplusplus
1933+extern "C" {
1934+#endif
1935+
1936+enum SysPowerStates {
1937+ //Note that callers will be notified of suspend state changes
1938+ //but may not request this state.
1939+ POWERD_SYS_STATE_SUSPEND = 0,
1940+
1941+ //The Active state will prevent system suspend
1942+ POWERD_SYS_STATE_ACTIVE,
1943+
1944+ POWERD_NUM_POWER_STATES
1945+};
1946+
1947+#ifdef __cplusplus
1948+}
1949+#endif
1950+
1951+#endif
1952
1953=== added directory 'testclient'
1954=== added file 'testclient/CMakeLists.txt'
1955--- testclient/CMakeLists.txt 1970-01-01 00:00:00 +0000
1956+++ testclient/CMakeLists.txt 2013-05-21 14:54:26 +0000
1957@@ -0,0 +1,37 @@
1958+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb -g")
1959+
1960+set(
1961+ SRCS
1962+
1963+ testclient.c
1964+)
1965+
1966+link_directories(
1967+ ${GLIB_LIBRARY_DIRS}
1968+ ${GIO_LIBRARY_DIRS}
1969+ ${GIO-UNIX_LIBRARY_DIRS}
1970+ ${GUDEV_LIBRARY_DIRS}
1971+)
1972+
1973+include_directories(
1974+ ${GLIB_INCLUDE_DIRS}
1975+ ${GIO_INCLUDE_DIRS}
1976+ ${GIO-UNIX_INCLUDE_DIRS}
1977+ ${GUDEV_INCLUDE_DIRS}
1978+ ../src
1979+)
1980+
1981+add_executable(
1982+ powerd-testclient
1983+
1984+ ${SRCS}
1985+)
1986+
1987+target_link_libraries(
1988+ powerd-testclient
1989+
1990+ ${GLIB_LIBRARIES}
1991+ ${GUDEV_LIBRARIES}
1992+ ${GIO_LIBRARIES}
1993+ ${GIO-UNIX_LIBRARIES}
1994+)
1995
1996=== added file 'testclient/testclient.c'
1997--- testclient/testclient.c 1970-01-01 00:00:00 +0000
1998+++ testclient/testclient.c 2013-05-21 14:54:26 +0000
1999@@ -0,0 +1,120 @@
2000+/*
2001+ * Copyright 2013 Canonical Ltd.
2002+ *
2003+ * This file is part of powerd.
2004+ *
2005+ * powerd is free software; you can redistribute it and/or modify
2006+ * it under the terms of the GNU General Public License as published by
2007+ * the Free Software Foundation; version 3.
2008+ *
2009+ * powerd is distributed in the hope that it will be useful,
2010+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2011+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2012+ * GNU General Public License for more details.
2013+ *
2014+ * You should have received a copy of the GNU General Public License
2015+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2016+ */
2017+
2018+#include <assert.h>
2019+#include <stdlib.h>
2020+#include <stdio.h>
2021+#include <unistd.h>
2022+#include <sys/types.h>
2023+#include <glib-object.h>
2024+#include <gio/gio.h>
2025+#include <powerd.h>
2026+
2027+static void
2028+on_signal (GDBusProxy *proxy,
2029+ gchar *sender_name,
2030+ gchar *signal_name,
2031+ GVariant *parameters,
2032+ gpointer user_data)
2033+{
2034+ g_warning("we get signal from %s: %s", sender_name, signal_name);
2035+}
2036+
2037+static gboolean
2038+requestSysState(GDBusProxy *proxy, int state, pid_t pid, uint *cookie)
2039+{
2040+ GVariant *ret = NULL;
2041+ GError *error = NULL;
2042+
2043+ if (proxy == NULL) {
2044+ g_warning("requires a valid proxy object");
2045+ return FALSE;
2046+ }
2047+
2048+ if (cookie == NULL) {
2049+ g_warning("requires a valid pointer for cookie");
2050+ return FALSE;
2051+ }
2052+
2053+ ret = g_dbus_proxy_call_sync(proxy,
2054+ "requestSysState",
2055+ g_variant_new("(ii)", state, pid),
2056+ G_DBUS_CALL_FLAGS_NONE,
2057+ -1,
2058+ NULL,
2059+ &error);
2060+ if (ret == NULL) {
2061+ g_warning("Error when calling requestSysState: %s", error->message);
2062+ g_error_free(error);
2063+ return FALSE;
2064+ }
2065+ else {
2066+ g_variant_get(ret, "(u)", cookie);
2067+ g_message("Got cookie: %u", *cookie);
2068+ return TRUE;
2069+ }
2070+}
2071+
2072+int main (int argc, char **argv)
2073+{
2074+ GDBusProxy *proxy = NULL;
2075+ GMainLoop *loop = NULL;
2076+ GError *error = NULL;
2077+ pid_t mypid;
2078+ uint cookie;
2079+
2080+ g_type_init();
2081+ loop = g_main_loop_new (NULL, FALSE);
2082+
2083+ proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
2084+ G_DBUS_PROXY_FLAGS_NONE,
2085+ NULL,
2086+ "com.canonical.powerd",
2087+ "/com/canonical/powerd",
2088+ "com.canonical.powerd",
2089+ NULL,
2090+ &error);
2091+
2092+ if (error != NULL) {
2093+ g_error("error, could not acquire system bus: %s", error->message);
2094+ g_error_free(error);
2095+ return -1;
2096+ }
2097+
2098+ // XXX - attach to real signal once we have one
2099+ g_signal_connect(proxy,
2100+ "g-signal",
2101+ G_CALLBACK (on_signal),
2102+ NULL);
2103+
2104+ mypid = getpid();
2105+ g_message("Running as pid %d\n", mypid);
2106+
2107+ assert(requestSysState(proxy, POWERD_SYS_STATE_ACTIVE, mypid, &cookie) == TRUE);
2108+ //cannot request the suspend state, this will fail
2109+ assert(requestSysState(proxy, POWERD_SYS_STATE_SUSPEND, mypid, &cookie) == FALSE);
2110+ //invalid values
2111+ assert(requestSysState(proxy, -1, mypid, &cookie) == FALSE);
2112+ assert(requestSysState(proxy, POWERD_NUM_POWER_STATES, mypid,&cookie) == FALSE);
2113+ assert(requestSysState(proxy, POWERD_NUM_POWER_STATES+1, mypid,&cookie) == FALSE);
2114+
2115+ g_message("Waiting for events");
2116+ g_main_loop_run(loop);
2117+ g_main_loop_unref(loop);
2118+ return 0;
2119+}
2120
2121=== added file 'tester.sh'
2122--- tester.sh 1970-01-01 00:00:00 +0000
2123+++ tester.sh 2013-05-21 14:54:26 +0000
2124@@ -0,0 +1,51 @@
2125+#!/bin/sh
2126+
2127+RET=`sudo gdbus call --system --dest com.canonical.powerd --object-path\
2128+ /com/canonical/powerd --method com.canonical.powerd.requestSysState 1 99`
2129+COOKIEA=`echo ${RET%,*} | sed 's/.* //'`
2130+echo "Cookie: $COOKIEA"
2131+RET=`sudo gdbus call --system --dest com.canonical.powerd --object-path\
2132+ /com/canonical/powerd --method com.canonical.powerd.requestSysState 1 99`
2133+COOKIEB=`echo ${RET%,*} | sed 's/.* //'`
2134+echo "Cookie: $COOKIEB"
2135+
2136+# should have 2
2137+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2138+ /com/canonical/powerd --method com.canonical.powerd.listSysRequests
2139+
2140+# clear our requests
2141+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2142+ /com/canonical/powerd --method com.canonical.powerd.clearSysState $COOKIEA
2143+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2144+ /com/canonical/powerd --method com.canonical.powerd.clearSysState $COOKIEB
2145+
2146+# should have 0
2147+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2148+ /com/canonical/powerd --method com.canonical.powerd.listSysRequests
2149+
2150+# these should fail
2151+echo "These should all fail"
2152+# invalid state 99
2153+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2154+ /com/canonical/powerd --method com.canonical.powerd.requestSysState 99 99
2155+# illegal to request the suspend state
2156+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2157+ /com/canonical/powerd --method com.canonical.powerd.requestSysState 0 99
2158+# gdbus does not like passing -1
2159+#sudo gdbus call --system --dest com.canonical.powerd --object-path\
2160+# /com/canonical/powerd --method com.canonical.powerd.requestSysState \-1 99
2161+# bad arg
2162+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2163+ /com/canonical/powerd --method com.canonical.powerd.requestSysState fred
2164+# bad arg
2165+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2166+ /com/canonical/powerd --method com.canonical.powerd.listStateRequests fred
2167+# bad cookie
2168+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2169+ /com/canonical/powerd --method com.canonical.powerd.clearSysState 18181
2170+# bad arg
2171+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2172+ /com/canonical/powerd --method com.canonical.powerd.clearSysState fred
2173+# invalid call to non-existant method
2174+sudo gdbus call --system --dest com.canonical.powerd --object-path\
2175+ /com/canonical/powerd --method com.canonical.powerd.chickenCutlass

Subscribers

People subscribed via source and target branches