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