Unity 8
 All Classes Functions Properties
process_helpers.py
1 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2 #
3 # Unity Autopilot Utilities
4 # Copyright (C) 2013, 2014 Canonical
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #
19 
20 from autopilot.introspection import (
21  get_proxy_object_for_existing_process,
22  ProcessSearchError,
23 )
24 import logging
25 import subprocess
26 from unity8.shell import emulators
27 from unity8.shell.emulators import main_window as main_window_emulator
28 
29 logger = logging.getLogger(__name__)
30 
31 
32 class CannotAccessUnity(Exception):
33  pass
34 
35 
36 def unlock_unity(unity_proxy_obj=None):
37  """Helper function that attempts to unlock the unity greeter.
38 
39  If unity_proxy_object is None create a proxy object by querying for the
40  running unity process.
41  Otherwise re-use the passed proxy object.
42 
43  :raises RuntimeError: if the greeter attempts and fails to be unlocked.
44 
45  :raises RuntimeWarning: when the greeter cannot be found because it is
46  already unlocked.
47  :raises CannotAccessUnity: if unity is not introspectable or cannot be
48  found on dbus.
49  :raises CannotAccessUnity: if unity's upstart status is not "start" or the
50  upstart job cannot be found at all.
51 
52  """
53  if unity_proxy_obj is None:
54  try:
55  pid = _get_unity_pid()
56  unity = _get_unity_proxy_object(pid)
57  main_window = unity.select_single(main_window_emulator.QQuickView)
58  except ProcessSearchError as e:
59  raise CannotAccessUnity(
60  "Cannot introspect unity, make sure that it has been started "
61  "with testability. Perhaps use the function "
62  "'restart_unity_with_testability' this module provides."
63  "(%s)"
64  % str(e)
65  )
66  else:
67  main_window = unity_proxy_obj.select_single(
68  main_window_emulator.QQuickView)
69 
70  greeter = main_window.get_greeter()
71  if greeter.created == False:
72  raise RuntimeWarning("Greeter appears to be already unlocked.")
73 
74  # Because of potential input jerkiness under heavy load,
75  # retry unlocking the greeter two times.
76  # https://bugs.launchpad.net/ubuntu/+bug/1260113
77 
78  retries = 3
79  while retries > 0:
80  try:
81  greeter.swipe()
82  except AssertionError:
83  retries -= 1
84  if retries == 0:
85  raise
86  logger.info("Failed to unlock greeter, trying again...")
87  else:
88  logger.info("Greeter unlocked, continuing.")
89  break
90 
91 
92 def lock_unity(unity_proxy_obj=None):
93  """Helper function that attempts to lock the unity greeter."""
94  import evdev, time
95  uinput = evdev.UInput(name='unity8-autopilot-power-button',
96  devnode='/dev/autopilot-uinput')
97  # One press and release to turn screen off (locking unity)
98  uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
99  uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
100  uinput.syn()
101  time.sleep(1)
102  # And another press and release to turn screen back on
103  uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 1)
104  uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_POWER, 0)
105  uinput.syn()
106 
107 
108 def restart_unity_with_testability(*args):
109  """Restarts (or starts) unity with testability enabled.
110 
111  Passes *args arguments to the launched process.
112 
113  """
114  args += ("QT_LOAD_TESTABILITY=1",)
115  return restart_unity(*args)
116 
117 
118 def restart_unity(*args):
119  """Restarts (or starts) unity8 using the provided arguments.
120 
121  Passes *args arguments to the launched process.
122 
123  :raises subprocess.CalledProcessError: if unable to stop or start the
124  unity8 upstart job.
125 
126  """
127  status = _get_unity_status()
128  if "start/" in status:
129  try:
130  output = subprocess.check_output(
131  ['/sbin/initctl', 'stop', 'unity8'])
132  logger.info(output)
133  except subprocess.CalledProcessError as e:
134  e.args += (
135  "Failed to stop running instance of unity8: %s" % e.output,
136  )
137  raise
138 
139  try:
140  command = ['/sbin/initctl', 'start', 'unity8'] + list(args)
141  output = subprocess.check_output(
142  command,
143  stderr=subprocess.STDOUT,
144  universal_newlines=True,
145  )
146  logger.info(output)
147  pid = _get_unity_pid()
148  except subprocess.CalledProcessError as e:
149  e.args += ("Failed to start unity8: %s" % e.output,)
150  raise
151  else:
152  return _get_unity_proxy_object(pid)
153 
154 
155 def _get_unity_status():
156  try:
157  return subprocess.check_output([
158  '/sbin/initctl',
159  'status',
160  'unity8'
161  ], universal_newlines=True)
162  except subprocess.CalledProcessError as e:
163  raise CannotAccessUnity("Unable to get unity's status: %s" % str(e))
164 
165 
166 def _get_unity_pid():
167  status = _get_unity_status()
168  if not "start/" in status:
169  raise CannotAccessUnity("Unity is not in the running state.")
170  return int(status.split()[-1])
171 
172 
173 def _get_unity_proxy_object(pid):
174  return get_proxy_object_for_existing_process(
175  pid=pid,
176  emulator_base=emulators.UnityEmulatorBase,
177  )