1 # Copyright 2015 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 import threading 7 8 import dbus 9 import dbus.mainloop.glib 10 import gobject 11 12 from autotest_lib.client.cros import upstart 13 14 class DarkResumeListener(object): 15 """Server which listens for dark resume-related DBus signals to count how 16 many dark resumes we have seen since instantiation.""" 17 18 SIGNAL_NAME = 'DarkSuspendImminent' 19 20 21 def __init__(self): 22 dbus.mainloop.glib.threads_init() 23 gobject.threads_init() 24 25 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 26 self._bus = dbus.SystemBus() 27 self._count = 0 28 self._stop_resuspend = False 29 30 self._bus.add_signal_receiver(handler_function=self._saw_dark_resume, 31 signal_name=self.SIGNAL_NAME) 32 33 def loop_runner(): 34 """Handles DBus events on the system bus using the mainloop.""" 35 # If we just call run on this loop, the listener will hang and the test 36 # will never finish. Instead, we process events as they come in. This 37 # thread is set to daemon below, which means that the program will exit 38 # when the main thread exits. 39 loop = gobject.MainLoop() 40 context = loop.get_context() 41 while True: 42 context.iteration(True) 43 thread = threading.Thread(None, loop_runner) 44 thread.daemon = True 45 thread.start() 46 logging.debug('Dark resume listener started') 47 48 49 @property 50 def count(self): 51 """Number of DarkSuspendImminent events this listener has seen since its 52 creation.""" 53 return self._count 54 55 56 def _saw_dark_resume(self, unused): 57 self._count += 1 58 if self._stop_resuspend: 59 # Restart powerd to stop re-suspend. 60 upstart.restart_job('powerd') 61 62 63 def stop_resuspend(self, should_stop): 64 """ 65 Whether to stop suspend after seeing a dark resume. 66 67 @param should_stop: Whether to stop system from re-suspending. 68 """ 69 self._stop_resuspend = should_stop 70 71