]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/container_manager.py
packaging: install icons to xdg icons resource path, and get the .desktop file to...
[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 if os.path.ismount("/sys/fs/cgroup/schedtune"):
150 command = ["umount", "-l", "/sys/fs/cgroup/schedtune"]
151 tools.helpers.run.user(args, command, check=False)
152
153 #TODO: remove NFC hacks
154 if which("stop"):
155 command = ["stop", "nfcd"]
156 tools.helpers.run.user(args, command, check=False)
157 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-active", "-q", "nfcd"], check=False) == 0):
158 command = ["systemctl", "stop", "nfcd"]
159 tools.helpers.run.user(args, command, check=False)
160
161 # Set permissions
162 set_permissions(args)
163
164 # Create session-specific LXC config file
165 helpers.lxc.generate_session_lxc_config(args, session)
166 # Backwards compatibility
167 with open(tools.config.defaults["lxc"] + "/waydroid/config") as f:
168 if "config_session" not in f.read():
169 helpers.mount.bind(args, session["waydroid_data"],
170 tools.config.defaults["data"])
171
172 # Mount rootfs
173 cfg = tools.config.load(args)
174 helpers.images.mount_rootfs(args, cfg["waydroid"]["images_path"], session)
175
176 helpers.protocol.set_aidl_version(args)
177
178 helpers.lxc.start(args)
179 services.hardware_manager.start(args)
180
181 args.session = session
182
183 def stop(args, quit_session=True):
184 try:
185 services.hardware_manager.stop(args)
186 status = helpers.lxc.status(args)
187 if status != "STOPPED":
188 helpers.lxc.stop(args)
189 while helpers.lxc.status(args) != "STOPPED":
190 pass
191
192 # Networking
193 command = [tools.config.tools_src +
194 "/data/scripts/waydroid-net.sh", "stop"]
195 tools.helpers.run.user(args, command, check=False)
196
197 #TODO: remove NFC hacks
198 if which("start"):
199 command = ["start", "nfcd"]
200 tools.helpers.run.user(args, command, check=False)
201 elif which("systemctl") and (tools.helpers.run.user(args, ["systemctl", "is-enabled", "-q", "nfcd"], check=False) == 0):
202 command = ["systemctl", "start", "nfcd"]
203 tools.helpers.run.user(args, command, check=False)
204
205 # Sensors
206 if which("waydroid-sensord"):
207 command = ["pidof", "waydroid-sensord"]
208 pid = tools.helpers.run.user(args, command, check=False, output_return=True).strip()
209 if pid:
210 command = ["kill", "-9", pid]
211 tools.helpers.run.user(args, command, check=False)
212
213 # Umount rootfs
214 helpers.images.umount_rootfs(args)
215
216 # Backwards compatibility
217 try:
218 helpers.mount.umount_all(args, tools.config.defaults["data"])
219 except:
220 pass
221
222 if "session" in args:
223 if quit_session:
224 try:
225 os.kill(int(args.session["pid"]), signal.SIGUSR1)
226 except:
227 pass
228 del args.session
229 except:
230 pass
231
232 def restart(args):
233 status = helpers.lxc.status(args)
234 if status == "RUNNING":
235 helpers.lxc.stop(args)
236 helpers.lxc.start(args)
237 else:
238 logging.error("WayDroid container is {}".format(status))
239
240 def freeze(args):
241 status = helpers.lxc.status(args)
242 if status == "RUNNING":
243 helpers.lxc.freeze(args)
244 while helpers.lxc.status(args) == "RUNNING":
245 pass
246 else:
247 logging.error("WayDroid container is {}".format(status))
248
249 def unfreeze(args):
250 status = helpers.lxc.status(args)
251 if status == "FROZEN":
252 helpers.lxc.unfreeze(args)
253 while helpers.lxc.status(args) == "FROZEN":
254 pass