]> glassweightruler.freedombox.rocks Git - waydroid.git/blob - tools/actions/initializer.py
Add first-launch command
[waydroid.git] / tools / actions / initializer.py
1 # Copyright 2021 Erfan Abdi
2 # SPDX-License-Identifier: GPL-3.0-or-later
3 import logging
4 import os
5 from tools import helpers
6 import tools.config
7
8 from tkinter import *
9 from tkinter import ttk
10
11 import sys
12 import threading
13 class Daemon(threading.Thread):
14 def __init__(self):
15 super().__init__()
16 self.daemon = True
17
18 def is_initialized(args):
19 return os.path.isfile(args.config) and os.path.isdir(tools.config.defaults["rootfs"])
20
21 def get_vendor_type(args):
22 vndk_str = helpers.props.host_get(args, "ro.vndk.version")
23 ret = "MAINLINE"
24 if vndk_str != "":
25 vndk = int(vndk_str)
26 if vndk > 19:
27 ret = "HALIUM_" + str(vndk - 19)
28
29 return ret
30
31 def setup_config(args):
32 cfg = tools.config.load(args)
33 args.arch = helpers.arch.host()
34 cfg["waydroid"]["arch"] = args.arch
35
36 preinstalled_images = tools.config.defaults["preinstalled_images_path"]
37 if not args.images_path:
38 if os.path.isdir(preinstalled_images):
39 if os.path.isfile(preinstalled_images + "/system.img") and os.path.isfile(preinstalled_images + "/vendor.img"):
40 args.images_path = preinstalled_images
41 else:
42 logging.error("Missing system or vendor on preinstalled images dir, fallback to default")
43 if not args.images_path:
44 args.images_path = tools.config.defaults["images_path"]
45 cfg["waydroid"]["images_path"] = args.images_path
46
47 channels_cfg = tools.config.load_channels()
48 if not args.system_channel:
49 args.system_channel = channels_cfg["channels"]["system_channel"]
50 if not args.vendor_channel:
51 args.vendor_channel = channels_cfg["channels"]["vendor_channel"]
52 if not args.rom_type:
53 args.rom_type = channels_cfg["channels"]["rom_type"]
54 if not args.system_type:
55 args.system_type = channels_cfg["channels"]["system_type"]
56
57 args.system_ota = args.system_channel + "/" + args.rom_type + \
58 "/waydroid_" + args.arch + "/" + args.system_type + ".json"
59 system_request = helpers.http.retrieve(args.system_ota)
60 if system_request[0] != 200:
61 if args.images_path != preinstalled_images:
62 raise ValueError(
63 "Failed to get system OTA channel: {}, error: {}".format(args.system_ota, system_request[0]))
64 else:
65 args.system_ota = "None"
66
67 device_codename = helpers.props.host_get(args, "ro.product.device")
68 args.vendor_type = None
69 for vendor in [device_codename, get_vendor_type(args)]:
70 vendor_ota = args.vendor_channel + "/waydroid_" + \
71 args.arch + "/" + vendor.replace(" ", "_") + ".json"
72 vendor_request = helpers.http.retrieve(vendor_ota)
73 if vendor_request[0] == 200:
74 args.vendor_type = vendor
75 args.vendor_ota = vendor_ota
76 break
77
78 if not args.vendor_type:
79 if args.images_path != preinstalled_images:
80 raise ValueError(
81 "Failed to get vendor OTA channel: {}".format(vendor_ota))
82 else:
83 args.vendor_ota = "None"
84 args.vendor_type = get_vendor_type(args)
85
86 if args.system_ota != cfg["waydroid"].get("system_ota"):
87 cfg["waydroid"]["system_datetime"] = tools.config.defaults["system_datetime"]
88 if args.vendor_ota != cfg["waydroid"].get("vendor_ota"):
89 cfg["waydroid"]["vendor_datetime"] = tools.config.defaults["vendor_datetime"]
90
91 cfg["waydroid"]["vendor_type"] = args.vendor_type
92 cfg["waydroid"]["system_ota"] = args.system_ota
93 cfg["waydroid"]["vendor_ota"] = args.vendor_ota
94 helpers.drivers.setupBinderNodes(args)
95 cfg["waydroid"]["binder"] = args.BINDER_DRIVER
96 cfg["waydroid"]["vndbinder"] = args.VNDBINDER_DRIVER
97 cfg["waydroid"]["hwbinder"] = args.HWBINDER_DRIVER
98 tools.config.save(args, cfg)
99
100 def do_init(args):
101 if not is_initialized(args) or args.force:
102 setup_config(args)
103 status = "STOPPED"
104 if os.path.exists(tools.config.defaults["lxc"] + "/waydroid"):
105 status = helpers.lxc.status(args)
106 if status != "STOPPED":
107 logging.info("Stopping container")
108 helpers.lxc.stop(args)
109 helpers.images.umount_rootfs(args)
110 if args.images_path != tools.config.defaults["preinstalled_images_path"]:
111 helpers.images.get(args)
112 if not os.path.isdir(tools.config.defaults["rootfs"]):
113 os.mkdir(tools.config.defaults["rootfs"])
114 helpers.lxc.setup_host_perms(args)
115 helpers.lxc.set_lxc_config(args)
116 helpers.lxc.make_base_props(args)
117 if status != "STOPPED":
118 logging.info("Starting container")
119 helpers.images.mount_rootfs(args, args.images_path)
120 helpers.lxc.start(args)
121
122 helpers.ipc.notify(channel="init", msg="done")
123 else:
124 logging.info("Already initialized")
125
126 def init(args):
127 if args.gui:
128 gui_init(args)
129 else:
130 do_init(args)
131
132 def gui_init(args):
133 if is_initialized(args) and not args.force:
134 return
135
136 root = Tk()
137 root.title("Initialize Waydroid")
138 root.iconphoto(True, PhotoImage(file="/usr/lib/waydroid/data/AppIcon.png"))
139 frm = ttk.Frame(root, padding=10)
140 frm.grid()
141
142 systemChannel = StringVar(frm, args.system_channel or tools.config.channels_defaults["system_channel"])
143 ttk.Label(frm, text="System OTA").grid(row=0, column=0)
144 ttk.Entry(frm, textvariable=systemChannel).grid(row=0, column=1, ipadx=20)
145
146 vendorChannel = StringVar(frm, args.vendor_channel or tools.config.channels_defaults["vendor_channel"])
147 ttk.Label(frm, text="Vendor OTA").grid(row=1, column=0)
148 ttk.Entry(frm, textvariable=vendorChannel).grid(row=1, column=1, ipadx=20)
149
150 systemType = StringVar(frm)
151 systemTypes = ["VANILLA", "GAPPS"]
152 ttk.Label(frm, text="Android Type").grid(row=2, column=0)
153 ttk.OptionMenu(frm, systemType, args.system_type or systemTypes[0], *systemTypes).grid(row=2, column=1)
154
155 done = ttk.Button(frm, text="Done", command=root.destroy)
156
157 logBox = Text(frm, borderwidth=3, relief="sunken", height=5)
158 logBox.bind("<Key>", lambda e: "break")
159
160 class StdoutRedirect(logging.StreamHandler):
161 def write(self, s):
162 if s.startswith('\r'):
163 logBox.delete("end-1l", "end")
164 logBox.insert(END, '\n')
165 s = s[1:]
166
167 logBox.insert(END, s)
168 logBox.see(END)
169 def flush(self):
170 pass
171 def emit(self, record):
172 if record.levelno >= logging.INFO:
173 self.write(self.format(record) + self.terminator)
174
175 out = StdoutRedirect()
176 sys.stdout = sys.stderr = out
177 logging.getLogger().addHandler(out)
178
179 def runInit():
180 download["state"] = DISABLED
181 logBox.grid(row=4, columnspan=2)
182
183 args.system_channel = systemChannel.get()
184 args.vendor_channel = vendorChannel.get()
185 args.system_type = systemType.get()
186
187 class Runner(Daemon):
188 def run(self):
189 try:
190 do_init(args)
191 if is_initialized(args):
192 done.grid(row=5, columnspan=2)
193 print("Done")
194 else:
195 download["state"] = NORMAL
196 except Exception as e:
197 print("ERROR: " + str(e))
198 download["state"] = NORMAL
199
200 Runner().start()
201
202 download = ttk.Button(frm, text="Download", command=runInit)
203 download.grid(row=3, columnspan=2)
204 root.mainloop()
205
206 sys.stdout = sys.__stdout__
207 sys.stderr = sys.__stderr__
208 logging.getLogger().removeHandler(out)