]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/container_manager.py
gpu: Check i915_capabilities for the card node
[waydroid.git] / tools / actions / container_manager.py
1 # Copyright 2021 Erfan Abdi
2 # SPDX-License-Identifier: GPL-3.0-or-later
3 from shutil import which
4 import logging
5 import os
6 import time
7 import glob
8 import signal
9 import sys
10 import uuid
11 import tools.config
12 from tools import helpers
13 from tools import services
14 import dbus
15 import dbus.service
16 import dbus.exceptions
17 from gi.repository import GLib
18
19 class DbusContainerManager(dbus.service.Object):
20 def __init__(self, looper, bus, object_path, args):
21 self.args = args
22 self.looper = looper
23 dbus.service.Object.__init__(self, bus, object_path)
24
25 @dbus.service.method("id.waydro.ContainerManager", in_signature='a{ss}', out_signature='', sender_keyword="sender", connection_keyword="conn")
26 def Start(self, session, sender, conn):
27 dbus_info = dbus.Interface(conn.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus/Bus", False), "org.freedesktop.DBus")
28 uid = dbus_info.GetConnectionUnixUser(sender)
29 if str(uid) not in ["0", session["user_id"]]:
30 raise RuntimeError("Cannot start a session on behalf of another user")
31 pid = dbus_info.GetConnectionUnixProcessID(sender)
32 if str(uid) != "0" and str(pid) != session["pid"]:
33 raise RuntimeError("Invalid session pid")
34 do_start(self.args, session)
35
36 @dbus.service.method("id.waydro.ContainerManager", in_signature='b', out_signature='')
37 def Stop(self, quit_session):
38 stop(self.args, quit_session)
39
40 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
41 def Freeze(self):
42 freeze(self.args)
43
44 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
45 def Unfreeze(self):
46 unfreeze(self.args)
47
48 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='a{ss}')
49 def GetSession(self):
50 try:
51 session = self.args.session
52 session["state"] = helpers.lxc.status(self.args)
53 return session
54 except AttributeError:
55 return {}
56
57 def service(args, looper):
58 dbus_obj = DbusContainerManager(looper, dbus.SystemBus(), '/ContainerManager', args)
59 looper.run()
60
61 def set_permissions(args, perm_list=None, mode="777"):
62 def chmod(path, mode):
63 if os.path.exists(path):
64 command = ["chmod", mode, "-R", path]
65 tools.helpers.run.user(args, command, check=False)
66
67 # Nodes list
68 if not perm_list:
69 perm_list = [
70 "/dev/ashmem",
71
72 # sw_sync for HWC
73 "/dev/sw_sync",
74 "/sys/kernel/debug/sync/sw_sync",
75
76 # Media
77 "/dev/Vcodec",
78 "/dev/MTK_SMI",
79 "/dev/mdp_sync",
80 "/dev/mtk_cmdq",
81
82 # Graphics
83 "/dev/graphics",
84 "/dev/pvr_sync",
85 "/dev/ion",
86 ]
87
88 # DRM render nodes
89 perm_list.extend(glob.glob("/dev/dri/renderD*"))
90 # Framebuffers
91 perm_list.extend(glob.glob("/dev/fb*"))
92 # Videos
93 perm_list.extend(glob.glob("/dev/video*"))
94 # DMA-BUF Heaps
95 perm_list.extend(glob.glob("/dev/dma_heap/*"))
96
97 for path in perm_list:
98 chmod(path, mode)
99
100 def start(args):
101 try:
102 name = dbus.service.BusName("id.waydro.Container", dbus.SystemBus(), do_not_queue=True)
103 except dbus.exceptions.NameExistsException:
104 logging.error("Container service is already running")
105 return
106
107 status = helpers.lxc.status(args)
108 if status == "STOPPED":
109 # Load binder and ashmem drivers
110 cfg = tools.config.load(args)
111 if cfg["waydroid"]["vendor_type"] == "MAINLINE":
112 if helpers.drivers.probeBinderDriver(args) != 0:
113 logging.error("Failed to load Binder driver")
114 helpers.drivers.probeAshmemDriver(args)
115 helpers.drivers.loadBinderNodes(args)
116 set_permissions(args, [
117 "/dev/" + args.BINDER_DRIVER,
118 "/dev/" + args.VNDBINDER_DRIVER,
119 "/dev/" + args.HWBINDER_DRIVER
120 ], "666")
121
122 mainloop = GLib.MainLoop()
123
124 def sigint_handler(data):
125 stop(args)
126 mainloop.quit()
127
128 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, sigint_handler, None)
129 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, sigint_handler, None)
130 service(args, mainloop)
131 else:
132 logging.error("WayDroid container is {}".format(status))
133
134 def do_start(args, session):
135 if "session" in args:
136 raise RuntimeError("Already tracking a session")
137
138 # Networking
139 command = [tools.config.tools_src +
140 "/data/scripts/waydroid-net.sh", "start"]
141 tools.helpers.run.user(args, command)
142
143 # Sensors
144 if which("waydroid-sensord"):
145 tools.helpers.run.user(
146 args, ["waydroid-sensord", "/dev/" + args.HWBINDER_DRIVER], output="background")
147
148 # Cgroup hacks
149 if which("start"):
150 command = ["start", "cgroup-lite"]
151 tools.helpers.run.user(args, command, check=False)
152
153 # Keep schedtune around in case nesting is supported
154 if os.path.ismount("/sys/fs/cgroup/schedtune"):
155 try:
156 os.mkdir("/sys/fs/cgroup/schedtune/probe0")
157 os.mkdir("/sys/fs/cgroup/schedtune/probe0/probe1")
158 except:
159 command = ["umount", "-l", "/sys/fs/cgroup/schedtune"]
160 tools.helpers.run.user(args, command, check=False)
161 finally:
162 if os.path.exists("/sys/fs/cgroup/schedtune/probe0/probe1"):
163 os.rmdir("/sys/fs/cgroup/schedtune/probe0/probe1")
164 if os.path.exists("/sys/fs/cgroup/schedtune/probe0"):
165 os.rmdir("/sys/fs/cgroup/schedtune/probe0")
166
167 #TODO: remove NFC hacks
168 if which("stop"):
169 command = ["stop", "nfcd"]
170 tools.helpers.run.user(args, command, check=False)
171 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-active", "-q", "nfcd"], check=False) == 0):
172 command = ["systemctl", "stop", "nfcd"]
173 tools.helpers.run.user(args, command, check=False)
174
175 # Set permissions
176 set_permissions(args)
177
178 # Create session-specific LXC config file
179 helpers.lxc.generate_session_lxc_config(args, session)
180 # Backwards compatibility
181 with open(tools.config.defaults["lxc"] + "/waydroid/config") as f:
182 if "config_session" not in f.read():
183 helpers.mount.bind(args, session["waydroid_data"],
184 tools.config.defaults["data"])
185
186 # Mount rootfs
187 cfg = tools.config.load(args)
188 helpers.images.mount_rootfs(args, cfg["waydroid"]["images_path"], session)
189
190 helpers.protocol.set_aidl_version(args)
191
192 helpers.lxc.start(args)
193 services.hardware_manager.start(args)
194
195 args.session = session
196
197 def stop(args, quit_session=True):
198 try:
199 services.hardware_manager.stop(args)
200 status = helpers.lxc.status(args)
201 if status != "STOPPED":
202 helpers.lxc.stop(args)
203 while helpers.lxc.status(args) != "STOPPED":
204 pass
205
206 # Networking
207 command = [tools.config.tools_src +
208 "/data/scripts/waydroid-net.sh", "stop"]
209 tools.helpers.run.user(args, command, check=False)
210
211 #TODO: remove NFC hacks
212 if which("start"):
213 command = ["start", "nfcd"]
214 tools.helpers.run.user(args, command, check=False)
215 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-enabled", "-q", "nfcd"], check=False) == 0):
216 command = ["systemctl", "start", "nfcd"]
217 tools.helpers.run.user(args, command, check=False)
218
219 # Sensors
220 if which("waydroid-sensord"):
221 command = ["pidof", "waydroid-sensord"]
222 pid = tools.helpers.run.user(args, command, check=False, output_return=True).strip()
223 if pid:
224 command = ["kill", "-9", pid]
225 tools.helpers.run.user(args, command, check=False)
226
227 # Umount rootfs
228 helpers.images.umount_rootfs(args)
229
230 # Backwards compatibility
231 try:
232 helpers.mount.umount_all(args, tools.config.defaults["data"])
233 except:
234 pass
235
236 if "session" in args:
237 if quit_session:
238 try:
239 os.kill(int(args.session["pid"]), signal.SIGUSR1)
240 except:
241 pass
242 del args.session
243 except:
244 pass
245
246 def restart(args):
247 status = helpers.lxc.status(args)
248 if status == "RUNNING":
249 helpers.lxc.stop(args)
250 helpers.lxc.start(args)
251 else:
252 logging.error("WayDroid container is {}".format(status))
253
254 def freeze(args):
255 status = helpers.lxc.status(args)
256 if status == "RUNNING":
257 helpers.lxc.freeze(args)
258 while helpers.lxc.status(args) == "RUNNING":
259 pass
260 else:
261 logging.error("WayDroid container is {}".format(status))
262
263 def unfreeze(args):
264 status = helpers.lxc.status(args)
265 if status == "FROZEN":
266 helpers.lxc.unfreeze(args)
267 while helpers.lxc.status(args) == "FROZEN":
268 pass