]> glassweightruler.freedombox.rocks Git - waydroid.git/blobdiff - tools/actions/initializer.py
Add first-launch command
[waydroid.git] / tools / actions / initializer.py
index c5783a459a125c9cb3f68c0d7c3dd7ccda846573..89bbf576b149287f7ebf00a85cc28b0c651c6b82 100644 (file)
@@ -2,10 +2,21 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 import logging
 import os
-import requests
 from tools import helpers
 import tools.config
 
+from tkinter import *
+from tkinter import ttk
+
+import sys
+import threading
+class Daemon(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        self.daemon = True
+
+def is_initialized(args):
+    return os.path.isfile(args.config) and os.path.isdir(tools.config.defaults["rootfs"])
 
 def get_vendor_type(args):
     vndk_str = helpers.props.host_get(args, "ro.vndk.version")
@@ -21,6 +32,16 @@ def setup_config(args):
     cfg = tools.config.load(args)
     args.arch = helpers.arch.host()
     cfg["waydroid"]["arch"] = args.arch
+
+    preinstalled_images = tools.config.defaults["preinstalled_images_path"]
+    if not args.images_path:
+        if os.path.isdir(preinstalled_images):
+            if os.path.isfile(preinstalled_images + "/system.img") and os.path.isfile(preinstalled_images + "/vendor.img"):
+                args.images_path = preinstalled_images
+            else:
+                logging.error("Missing system or vendor on preinstalled images dir, fallback to default")
+    if not args.images_path:
+        args.images_path = tools.config.defaults["images_path"]
     cfg["waydroid"]["images_path"] = args.images_path
 
     channels_cfg = tools.config.load_channels()
@@ -35,25 +56,37 @@ def setup_config(args):
 
     args.system_ota = args.system_channel + "/" + args.rom_type + \
         "/waydroid_" + args.arch + "/" + args.system_type + ".json"
-    system_request = requests.get(args.system_ota)
-    if system_request.status_code != 200:
-        raise ValueError(
-            "Failed to get system OTA channel: {}".format(args.system_ota))
+    system_request = helpers.http.retrieve(args.system_ota)
+    if system_request[0] != 200:
+        if args.images_path != preinstalled_images:
+            raise ValueError(
+                "Failed to get system OTA channel: {}, error: {}".format(args.system_ota, system_request[0]))
+        else:
+            args.system_ota = "None"
 
     device_codename = helpers.props.host_get(args, "ro.product.device")
     args.vendor_type = None
     for vendor in [device_codename, get_vendor_type(args)]:
         vendor_ota = args.vendor_channel + "/waydroid_" + \
-            args.arch + "/" + vendor + ".json"
-        vendor_request = requests.get(vendor_ota)
-        if vendor_request.status_code == 200:
+            args.arch + "/" + vendor.replace(" ", "_") + ".json"
+        vendor_request = helpers.http.retrieve(vendor_ota)
+        if vendor_request[0] == 200:
             args.vendor_type = vendor
             args.vendor_ota = vendor_ota
             break
 
     if not args.vendor_type:
-        raise ValueError(
-            "Failed to get vendor OTA channel: {}".format(vendor_ota))
+        if args.images_path != preinstalled_images:
+            raise ValueError(
+                "Failed to get vendor OTA channel: {}".format(vendor_ota))
+        else:
+            args.vendor_ota = "None"
+            args.vendor_type = get_vendor_type(args)
+
+    if args.system_ota != cfg["waydroid"].get("system_ota"):
+        cfg["waydroid"]["system_datetime"] = tools.config.defaults["system_datetime"]
+    if args.vendor_ota != cfg["waydroid"].get("vendor_ota"):
+        cfg["waydroid"]["vendor_datetime"] = tools.config.defaults["vendor_datetime"]
 
     cfg["waydroid"]["vendor_type"] = args.vendor_type
     cfg["waydroid"]["system_ota"] = args.system_ota
@@ -64,8 +97,8 @@ def setup_config(args):
     cfg["waydroid"]["hwbinder"] = args.HWBINDER_DRIVER
     tools.config.save(args, cfg)
 
-def init(args):
-    if not os.path.isfile(args.config) or args.force:
+def do_init(args):
+    if not is_initialized(args) or args.force:
         setup_config(args)
         status = "STOPPED"
         if os.path.exists(tools.config.defaults["lxc"] + "/waydroid"):
@@ -74,7 +107,8 @@ def init(args):
             logging.info("Stopping container")
             helpers.lxc.stop(args)
         helpers.images.umount_rootfs(args)
-        helpers.images.get(args)
+        if args.images_path != tools.config.defaults["preinstalled_images_path"]:
+            helpers.images.get(args)
         if not os.path.isdir(tools.config.defaults["rootfs"]):
             os.mkdir(tools.config.defaults["rootfs"])
         helpers.lxc.setup_host_perms(args)
@@ -84,5 +118,91 @@ def init(args):
             logging.info("Starting container")
             helpers.images.mount_rootfs(args, args.images_path)
             helpers.lxc.start(args)
+
+        helpers.ipc.notify(channel="init", msg="done")
     else:
         logging.info("Already initialized")
+
+def init(args):
+    if args.gui:
+        gui_init(args)
+    else:
+        do_init(args)
+
+def gui_init(args):
+    if is_initialized(args) and not args.force:
+        return
+
+    root = Tk()
+    root.title("Initialize Waydroid")
+    root.iconphoto(True, PhotoImage(file="/usr/lib/waydroid/data/AppIcon.png"))
+    frm = ttk.Frame(root, padding=10)
+    frm.grid()
+
+    systemChannel = StringVar(frm, args.system_channel or tools.config.channels_defaults["system_channel"])
+    ttk.Label(frm, text="System OTA").grid(row=0, column=0)
+    ttk.Entry(frm, textvariable=systemChannel).grid(row=0, column=1, ipadx=20)
+
+    vendorChannel = StringVar(frm, args.vendor_channel or tools.config.channels_defaults["vendor_channel"])
+    ttk.Label(frm, text="Vendor OTA").grid(row=1, column=0)
+    ttk.Entry(frm, textvariable=vendorChannel).grid(row=1, column=1, ipadx=20)
+
+    systemType = StringVar(frm)
+    systemTypes = ["VANILLA", "GAPPS"]
+    ttk.Label(frm, text="Android Type").grid(row=2, column=0)
+    ttk.OptionMenu(frm, systemType, args.system_type or systemTypes[0], *systemTypes).grid(row=2, column=1)
+
+    done = ttk.Button(frm, text="Done", command=root.destroy)
+
+    logBox = Text(frm, borderwidth=3, relief="sunken", height=5)
+    logBox.bind("<Key>", lambda e: "break")
+
+    class StdoutRedirect(logging.StreamHandler):
+        def write(self, s):
+            if s.startswith('\r'):
+                logBox.delete("end-1l", "end")
+                logBox.insert(END, '\n')
+                s = s[1:]
+
+            logBox.insert(END, s)
+            logBox.see(END)
+        def flush(self):
+            pass
+        def emit(self, record):
+            if record.levelno >= logging.INFO:
+                self.write(self.format(record) + self.terminator)
+
+    out = StdoutRedirect()
+    sys.stdout = sys.stderr = out
+    logging.getLogger().addHandler(out)
+
+    def runInit():
+        download["state"] = DISABLED
+        logBox.grid(row=4, columnspan=2)
+
+        args.system_channel = systemChannel.get()
+        args.vendor_channel = vendorChannel.get()
+        args.system_type = systemType.get()
+
+        class Runner(Daemon):
+            def run(self):
+                try:
+                    do_init(args)
+                    if is_initialized(args):
+                        done.grid(row=5, columnspan=2)
+                        print("Done")
+                    else:
+                        download["state"] = NORMAL
+                except Exception as e:
+                    print("ERROR: " + str(e))
+                    download["state"] = NORMAL
+
+        Runner().start()
+
+    download = ttk.Button(frm, text="Download", command=runInit)
+    download.grid(row=3, columnspan=2)
+    root.mainloop()
+
+    sys.stdout = sys.__stdout__
+    sys.stderr = sys.__stderr__
+    logging.getLogger().removeHandler(out)