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