]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/container_manager.py
container: Do not mount KMS nodes
[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
95 for path in perm_list:
96 chmod(path, mode)
97
98 def start(args):
99 try:
100 name = dbus.service.BusName("id.waydro.Container", dbus.SystemBus(), do_not_queue=True)
101 except dbus.exceptions.NameExistsException:
102 logging.error("Container service is already running")
103 return
104
105 status = helpers.lxc.status(args)
106 if status == "STOPPED":
107 # Load binder and ashmem drivers
108 cfg = tools.config.load(args)
109 if cfg["waydroid"]["vendor_type"] == "MAINLINE":
110 if helpers.drivers.probeBinderDriver(args) != 0:
111 logging.error("Failed to load Binder driver")
112 helpers.drivers.probeAshmemDriver(args)
113 helpers.drivers.loadBinderNodes(args)
114 set_permissions(args, [
115 "/dev/" + args.BINDER_DRIVER,
116 "/dev/" + args.VNDBINDER_DRIVER,
117 "/dev/" + args.HWBINDER_DRIVER
118 ], "666")
119
120 mainloop = GLib.MainLoop()
121
122 def sigint_handler(data):
123 stop(args)
124 mainloop.quit()
125
126 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, sigint_handler, None)
127 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, sigint_handler, None)
128 service(args, mainloop)
129 else:
130 logging.error("WayDroid container is {}".format(status))
131
132 def do_start(args, session):
133 if "session" in args:
134 raise RuntimeError("Already tracking a session")
135
136 # Networking
137 command = [tools.config.tools_src +
138 "/data/scripts/waydroid-net.sh", "start"]
139 tools.helpers.run.user(args, command)
140
141 # Sensors
142 if which("waydroid-sensord"):
143 tools.helpers.run.user(
144 args, ["waydroid-sensord", "/dev/" + args.HWBINDER_DRIVER], output="background")
145
146 # Cgroup hacks
147 if which("start"):
148 command = ["start", "cgroup-lite"]
149 tools.helpers.run.user(args, command, check=False)
150
151 # Keep schedtune around in case nesting is supported
152 if os.path.ismount("/sys/fs/cgroup/schedtune"):
153 try:
154 os.mkdir("/sys/fs/cgroup/schedtune/probe0")
155 os.mkdir("/sys/fs/cgroup/schedtune/probe0/probe1")
156 except:
157 command = ["umount", "-l", "/sys/fs/cgroup/schedtune"]
158 tools.helpers.run.user(args, command, check=False)
159 finally:
160 if os.path.exists("/sys/fs/cgroup/schedtune/probe0/probe1"):
161 os.rmdir("/sys/fs/cgroup/schedtune/probe0/probe1")
162 if os.path.exists("/sys/fs/cgroup/schedtune/probe0"):
163 os.rmdir("/sys/fs/cgroup/schedtune/probe0")
164
165 #TODO: remove NFC hacks
166 if which("stop"):
167 command = ["stop", "nfcd"]
168 tools.helpers.run.user(args, command, check=False)
169 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-active", "-q", "nfcd"], check=False) == 0):
170 command = ["systemctl", "stop", "nfcd"]
171 tools.helpers.run.user(args, command, check=False)
172
173 # Set permissions
174 set_permissions(args)
175
176 # Create session-specific LXC config file
177 helpers.lxc.generate_session_lxc_config(args, session)
178 # Backwards compatibility
179 with open(tools.config.defaults["lxc"] + "/waydroid/config") as f:
180 if "config_session" not in f.read():
181 helpers.mount.bind(args, session["waydroid_data"],
182 tools.config.defaults["data"])
183
184 # Mount rootfs
185 cfg = tools.config.load(args)
186 helpers.images.mount_rootfs(args, cfg["waydroid"]["images_path"], session)
187
188 helpers.protocol.set_aidl_version(args)
189
190 helpers.lxc.start(args)
191 services.hardware_manager.start(args)
192
193 args.session = session
194
195 def stop(args, quit_session=True):
196 try:
197 services.hardware_manager.stop(args)
198 status = helpers.lxc.status(args)
199 if status != "STOPPED":
200 helpers.lxc.stop(args)
201 while helpers.lxc.status(args) != "STOPPED":
202 pass
203
204 # Networking
205 command = [tools.config.tools_src +
206 "/data/scripts/waydroid-net.sh", "stop"]
207 tools.helpers.run.user(args, command, check=False)
208
209 #TODO: remove NFC hacks
210 if which("start"):
211 command = ["start", "nfcd"]
212 tools.helpers.run.user(args, command, check=False)
213 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-enabled", "-q", "nfcd"], check=False) == 0):
214 command = ["systemctl", "start", "nfcd"]
215 tools.helpers.run.user(args, command, check=False)
216
217 # Sensors
218 if which("waydroid-sensord"):
219 command = ["pidof", "waydroid-sensord"]
220 pid = tools.helpers.run.user(args, command, check=False, output_return=True).strip()
221 if pid:
222 command = ["kill", "-9", pid]
223 tools.helpers.run.user(args, command, check=False)
224
225 # Umount rootfs
226 helpers.images.umount_rootfs(args)
227
228 # Backwards compatibility
229 try:
230 helpers.mount.umount_all(args, tools.config.defaults["data"])
231 except:
232 pass
233
234 if "session" in args:
235 if quit_session:
236 try:
237 os.kill(int(args.session["pid"]), signal.SIGUSR1)
238 except:
239 pass
240 del args.session
241 except:
242 pass
243
244 def restart(args):
245 status = helpers.lxc.status(args)
246 if status == "RUNNING":
247 helpers.lxc.stop(args)
248 helpers.lxc.start(args)
249 else:
250 logging.error("WayDroid container is {}".format(status))
251
252 def freeze(args):
253 status = helpers.lxc.status(args)
254 if status == "RUNNING":
255 helpers.lxc.freeze(args)
256 while helpers.lxc.status(args) == "RUNNING":
257 pass
258 else:
259 logging.error("WayDroid container is {}".format(status))
260
261 def unfreeze(args):
262 status = helpers.lxc.status(args)
263 if status == "FROZEN":
264 helpers.lxc.unfreeze(args)
265 while helpers.lxc.status(args) == "FROZEN":
266 pass