]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/container_manager.py
upgrade: Fallback to stopping container manually
[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 do_start(self.args, session)
32
33 @dbus.service.method("id.waydro.ContainerManager", in_signature='b', out_signature='')
34 def Stop(self, quit_session):
35 stop(self.args, quit_session)
36
37 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
38 def Freeze(self):
39 freeze(self.args)
40
41 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='')
42 def Unfreeze(self):
43 unfreeze(self.args)
44
45 @dbus.service.method("id.waydro.ContainerManager", in_signature='', out_signature='a{ss}')
46 def GetSession(self):
47 try:
48 session = self.args.session
49 session["state"] = helpers.lxc.status(self.args)
50 return session
51 except AttributeError:
52 return {}
53
54 def service(args, looper):
55 dbus_obj = DbusContainerManager(looper, dbus.SystemBus(), '/ContainerManager', args)
56 looper.run()
57
58 def set_permissions(args, perm_list=None, mode="777"):
59 def chmod(path, mode):
60 if os.path.exists(path):
61 command = ["chmod", mode, "-R", path]
62 tools.helpers.run.user(args, command, check=False)
63
64 # Nodes list
65 if not perm_list:
66 perm_list = [
67 "/dev/ashmem",
68
69 # sw_sync for HWC
70 "/dev/sw_sync",
71 "/sys/kernel/debug/sync/sw_sync",
72
73 # Media
74 "/dev/Vcodec",
75 "/dev/MTK_SMI",
76 "/dev/mdp_sync",
77 "/dev/mtk_cmdq",
78
79 # Graphics
80 "/dev/dri",
81 "/dev/graphics",
82 "/dev/pvr_sync",
83 "/dev/ion",
84 ]
85
86 # Framebuffers
87 perm_list.extend(glob.glob("/dev/fb*"))
88 # Videos
89 perm_list.extend(glob.glob("/dev/video*"))
90
91 for path in perm_list:
92 chmod(path, mode)
93
94 def start(args):
95 try:
96 name = dbus.service.BusName("id.waydro.Container", dbus.SystemBus(), do_not_queue=True)
97 except dbus.exceptions.NameExistsException:
98 logging.error("Container service is already running")
99 return
100
101 status = helpers.lxc.status(args)
102 if status == "STOPPED":
103 # Load binder and ashmem drivers
104 cfg = tools.config.load(args)
105 if cfg["waydroid"]["vendor_type"] == "MAINLINE":
106 if helpers.drivers.probeBinderDriver(args) != 0:
107 logging.error("Failed to load Binder driver")
108 helpers.drivers.probeAshmemDriver(args)
109 helpers.drivers.loadBinderNodes(args)
110 set_permissions(args, [
111 "/dev/" + args.BINDER_DRIVER,
112 "/dev/" + args.VNDBINDER_DRIVER,
113 "/dev/" + args.HWBINDER_DRIVER
114 ], "666")
115
116 mainloop = GLib.MainLoop()
117
118 def sigint_handler(data):
119 stop(args)
120 mainloop.quit()
121
122 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, sigint_handler, None)
123 GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, sigint_handler, None)
124 service(args, mainloop)
125 else:
126 logging.error("WayDroid container is {}".format(status))
127
128 def do_start(args, session):
129 if "session" in args:
130 raise RuntimeError("Already tracking a session")
131
132 # Networking
133 command = [tools.config.tools_src +
134 "/data/scripts/waydroid-net.sh", "start"]
135 tools.helpers.run.user(args, command)
136
137 # Sensors
138 if which("waydroid-sensord"):
139 tools.helpers.run.user(
140 args, ["waydroid-sensord", "/dev/" + args.HWBINDER_DRIVER], output="background")
141
142 # Mount rootfs
143 cfg = tools.config.load(args)
144 helpers.images.mount_rootfs(args, cfg["waydroid"]["images_path"], session)
145
146 helpers.protocol.set_aidl_version(args)
147
148 # Cgroup hacks
149 if which("start"):
150 command = ["start", "cgroup-lite"]
151 tools.helpers.run.user(args, command, check=False)
152 if os.path.ismount("/sys/fs/cgroup/schedtune"):
153 command = ["umount", "-l", "/sys/fs/cgroup/schedtune"]
154 tools.helpers.run.user(args, command, check=False)
155
156 #TODO: remove NFC hacks
157 if which("stop"):
158 command = ["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 helpers.lxc.start(args)
173 services.hardware_manager.start(args)
174
175 args.session = session
176
177 def stop(args, quit_session=True):
178 try:
179 services.hardware_manager.stop(args)
180 status = helpers.lxc.status(args)
181 if status != "STOPPED":
182 helpers.lxc.stop(args)
183 while helpers.lxc.status(args) != "STOPPED":
184 pass
185
186 # Networking
187 command = [tools.config.tools_src +
188 "/data/scripts/waydroid-net.sh", "stop"]
189 tools.helpers.run.user(args, command, check=False)
190
191 #TODO: remove NFC hacks
192 if which("start"):
193 command = ["start", "nfcd"]
194 tools.helpers.run.user(args, command, check=False)
195
196 # Sensors
197 if which("waydroid-sensord"):
198 command = ["pidof", "waydroid-sensord"]
199 pid = tools.helpers.run.user(args, command, check=False, output_return=True).strip()
200 if pid:
201 command = ["kill", "-9", pid]
202 tools.helpers.run.user(args, command, check=False)
203
204 # Umount rootfs
205 helpers.images.umount_rootfs(args)
206
207 # Backwards compatibility
208 try:
209 helpers.mount.umount_all(args, tools.config.defaults["data"])
210 except:
211 pass
212
213 if "session" in args:
214 if quit_session:
215 try:
216 os.kill(int(args.session["pid"]), signal.SIGUSR1)
217 except:
218 pass
219 del args.session
220 except:
221 pass
222
223 def restart(args):
224 status = helpers.lxc.status(args)
225 if status == "RUNNING":
226 helpers.lxc.stop(args)
227 helpers.lxc.start(args)
228 else:
229 logging.error("WayDroid container is {}".format(status))
230
231 def freeze(args):
232 status = helpers.lxc.status(args)
233 if status == "RUNNING":
234 helpers.lxc.freeze(args)
235 while helpers.lxc.status(args) == "RUNNING":
236 pass
237 else:
238 logging.error("WayDroid container is {}".format(status))
239
240 def unfreeze(args):
241 status = helpers.lxc.status(args)
242 if status == "FROZEN":
243 helpers.lxc.unfreeze(args)
244 while helpers.lxc.status(args) == "FROZEN":
245 pass