Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions tools/container.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
import configparser
import os
import sys
# import dbus
from tools.helper import run
from tools.logger import Logger

# def DBusContainerService(object_path="/ContainerManager", intf="id.waydro.ContainerManager"):
# return dbus.Interface(dbus.SystemBus().get_object("id.waydro.Container", object_path), intf)

# def DBusSessionService(object_path="/SessionManager", intf="id.waydro.SessionManager"):
# return dbus.Interface(dbus.SessionBus().get_object("id.waydro.Session", object_path), intf)

# def use_dbus():
# try:
# DBusContainerService()
# except:
# return False
# return True

def use_overlayfs():
cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
Expand All @@ -34,20 +20,14 @@ def use_overlayfs():
return False


# def get_session():
# return DBusContainerService().GetSession()

def stop():
# if use_dbus():
# session = DBusContainerService().GetSession()
# if session:
# DBusContainerService().Stop(False)
# else:
run(["waydroid", "container", "stop"])


def is_running():
return "Session:\tRUNNING" in run(["waydroid", "status"]).stdout.decode()

def upgrade():
run(["waydroid", "upgrade", "-o"], ignore=r"\[.*\] Stopping container\n\[.*\] Starting container")
try:
run(["waydroid", "upgrade"], ignore=r"\[.*\] Stopping container\n\[.*\] Starting container")
except subprocess.CalledProcessError:
Logger.warning("Waydroid upgrade reported an error (likely system_ota), but we are continuing...")
130 changes: 64 additions & 66 deletions tools/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import os
import re
import platform
import re
import subprocess
import sys
import requests
Expand All @@ -11,39 +10,37 @@
import hashlib
from typing import Optional


def get_download_dir():
download_loc = ""
if os.environ.get("XDG_CACHE_HOME", None) is None:
download_loc = os.path.join('/', "home", os.environ.get(
"SUDO_USER", os.environ["USER"]), ".cache", "waydroid-script", "downloads"
)
else:
if os.environ.get("XDG_CACHE_HOME"):
download_loc = os.path.join(
os.environ["XDG_CACHE_HOME"], "waydroid-script", "downloads"
)
else:
user = os.environ.get("SUDO_USER", os.environ.get("USER", "root"))
download_loc = os.path.join("/", "home", user, ".cache", "waydroid-script", "downloads")

if not os.path.exists(download_loc):
os.makedirs(download_loc)
os.makedirs(download_loc, exist_ok=True)
return download_loc

# not good
def get_data_dir():
return os.path.join('/', "home", os.environ.get("SUDO_USER", os.environ["USER"]), ".local", "share", "waydroid", "data")
user = os.environ.get("SUDO_USER", os.environ.get("USER", "root"))
return os.path.join("/", "home", user, ".local", "share", "waydroid", "data")

# execute on host
def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
def run(args: list, env: Optional[dict] = None, ignore: Optional[str] = None):
result = subprocess.run(
args=args,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)

# print(result.stdout.decode())
if result.stderr:
error = result.stderr.decode("utf-8")
if ignore and re.match(ignore, error):
error = result.stderr.decode("utf-8").strip()

if (ignore and re.search(ignore, error)) or "system_ota" in error:
return result

Logger.error(error)
raise subprocess.CalledProcessError(
returncode=result.returncode,
Expand All @@ -52,95 +49,96 @@ def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
)
return result

# execute on waydroid shell
def shell(arg: str, env: Optional[str] = None):
a = subprocess.Popen(
args=["sudo", "waydroid", "shell"],
cmd = ["sudo", "waydroid", "shell"]
process = subprocess.Popen(
args=cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
stderr=subprocess.PIPE,
text=True
)
subprocess.Popen(
args=["echo", "export BOOTCLASSPATH=/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/core-icu4j.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/framework-atb-backward-compatibility.jar:/apex/com.android.conscrypt/javalib/conscrypt.jar:/apex/com.android.media/javalib/updatable-media.jar:/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar:/apex/com.android.os.statsd/javalib/framework-statsd.jar:/apex/com.android.permission/javalib/framework-permission.jar:/apex/com.android.sdkext/javalib/framework-sdkextensions.jar:/apex/com.android.wifi/javalib/framework-wifi.jar:/apex/com.android.tethering/javalib/framework-tethering.jar"],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()

boot_classpath = "export BOOTCLASSPATH=/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/core-icu4j.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/system/framework/framework-atb-backward-compatibility.jar:/apex/com.android.conscrypt/javalib/conscrypt.jar:/apex/com.android.media/javalib/updatable-media.jar:/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar:/apex/com.android.os.statsd/javalib/framework-statsd.jar:/apex/com.android.permission/javalib/framework-permission.jar:/apex/com.android.sdkext/javalib/framework-sdkextensions.jar:/apex/com.android.wifi/javalib/framework-wifi.jar:/apex/com.android.tethering/javalib/framework-tethering.jar"

full_script = f"{boot_classpath}\n"
if env:
subprocess.Popen(
args=["echo", env],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
full_script += f"{env}\n"
full_script += f"{arg}\n"

subprocess.Popen(
args=["echo", arg],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
stdout, stderr = process.communicate(input=full_script)

a.stdin.close()
if a.stderr.read():
Logger.error(a.stderr.read().decode('utf-8'))
if process.returncode != 0 and stderr:
Logger.error(stderr.strip())
raise subprocess.CalledProcessError(
returncode=a.returncode,
cmd=a.args,
stderr=a.stderr
returncode=process.returncode,
cmd=cmd,
stderr=stderr.encode()
)
return a.stdout.read().decode("utf-8")
return stdout

def download_file(url, f_name):
md5 = ""
response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get('content-length', 0))
block_size = 1024 # 1 Kibibyte
block_size = 1024

progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True)
with open(f_name, 'wb') as file:
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
progress_bar.close()

hash_md5 = hashlib.md5()
with open(f_name, "rb") as f:
bytes = f.read()
md5 = hashlib.md5(bytes).hexdigest()
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)

if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes:
raise ValueError("Something went wrong while downloading")
return md5
raise ValueError("Download incomplete or corrupted")

return hash_md5.hexdigest()

def host():
machine = platform.machine()

mapping = {
"i686": ("x86", 32),
"x86_64": ("x86_64", 64),
"aarch64": ("arm64-v8a", 64),
"armv7l": ("armeabi-v7a", 32),
"armv8l": ("armeabi-v7a", 32)
}

if machine in mapping:
if mapping[machine] == "x86_64":
with open("/proc/cpuinfo") as f:
if "sse4_2" not in f.read():
Logger.warning("x86_64 CPU does not support SSE4.2, falling back to x86...")
return ("x86", 32)
if machine == "x86_64":
try:
with open("/proc/cpuinfo", "r") as f:
if "sse4_2" not in f.read():
Logger.warning("CPU does not support SSE4.2, falling back to x86...")
return ("x86", 32)
except Exception:
pass
return mapping[machine]
raise ValueError("platform.machine '" + machine + "'"
" architecture is not supported")


raise ValueError(f"Architecture '{machine}' is not supported")

def check_root():
if os.geteuid() != 0:
Logger.error("This script must be run as root. Aborting.")
Logger.error("This script must be run as root (sudo). Aborting.")
sys.exit(1)

def backup(path):
gz_filename = path+".gz"
with gzip.open(gz_filename, 'wb') as f_gz:
with open(path, "rb") as f:
f_gz.write(f.read())
if not os.path.exists(path):
return
gz_filename = path + ".gz"
with open(path, "rb") as f_in:
with gzip.open(gz_filename, "wb") as f_out:
f_out.writelines(f_in)

def restore(path):
gz_filename = path+".gz"
with gzip.GzipFile(gz_filename) as f_gz:
with open(path, "wb") as f:
f.writelines(f_gz)
gz_filename = path + ".gz"
if not os.path.exists(gz_filename):
return
with gzip.open(gz_filename, "rb") as f_in:
with open(path, "wb") as f_out:
f_out.write(f_in.read())
5 changes: 2 additions & 3 deletions tools/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ def resize(img_file, size):
run(["sudo", "resize2fs", img_file, size], ignore="^resize2fs \d+\.\d+\.\d (.+)\n$")

def get_image_dir():
# Read waydroid config to get image location
cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
if not os.path.isfile(cfg_file):
Logger.error("Cannot locate waydroid config file, reinit wayland and try again!")
sys.exit(1)
cfg.read(cfg_file)
if "waydroid" not in cfg:
Logger.error("Required entry in config was not found, Cannot continue!") #magisk
Logger.error("Required entry in config was not found, Cannot continue!")
sys.exit(1)
return cfg["waydroid"]["images_path"]
return cfg["waydroid"]["images_path"]