You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
634 lines
28 KiB
Python
634 lines
28 KiB
Python
import configparser
|
|
import sys
|
|
import os
|
|
import hashlib
|
|
import shutil
|
|
import zipfile
|
|
import subprocess
|
|
import argparse
|
|
import platform
|
|
from tqdm import tqdm
|
|
import requests
|
|
import re
|
|
|
|
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:
|
|
download_loc = os.path.join(os.environ["XDG_CACHE_HOME"], "waydroid_script", "downloads")
|
|
|
|
print(download_loc)
|
|
|
|
if not os.path.exists(download_loc):
|
|
os.makedirs(download_loc)
|
|
|
|
def stop_waydroid():
|
|
print("==> Stopping waydroid and unmounting already mounted images...")
|
|
os.system("waydroid container stop &> /dev/null")
|
|
os.system("umount /var/lib/waydroid/rootfs/vendor/waydroid.prop &> /dev/null")
|
|
os.system("umount /var/lib/waydroid/rootfs/vendor &> /dev/null")
|
|
os.system("umount /var/lib/waydroid/rootfs &> /dev/null")
|
|
|
|
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
|
|
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()
|
|
with open(f_name, "rb") as f:
|
|
bytes = f.read()
|
|
md5 = hashlib.md5(bytes).hexdigest()
|
|
if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes:
|
|
print("==> Something went wrong while downloading")
|
|
sys.exit(1)
|
|
return md5
|
|
|
|
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):
|
|
print("==> Cannot locate waydroid config file, reinit wayland and try again !")
|
|
sys.exit(1)
|
|
|
|
cfg.read(cfg_file)
|
|
if "waydroid" not in cfg:
|
|
print("==> Required entry in config was not found, Cannot continue !s") #magisk
|
|
sys.exit(1)
|
|
return cfg["waydroid"]["images_path"]
|
|
|
|
def mount_image(image, mount_point):
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["losetup", "-D"], stderr=subprocess.STDOUT)
|
|
subprocess.check_output(["umount", mount_point], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
if not os.path.exists(mount_point):
|
|
os.makedirs(mount_point)
|
|
try:
|
|
subprocess.check_output(["mount", "-o", "rw", image, mount_point], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Failed to mount system image... ! {}".format(str(e.output.decode())))
|
|
sys.exit(1)
|
|
|
|
def resize_img(img_file, size):
|
|
# Resize the system image
|
|
print("==> Resizing system image....")
|
|
try:
|
|
subprocess.check_output(["e2fsck -y -f "+img_file], stderr=subprocess.STDOUT, shell=True)
|
|
subprocess.check_output(["resize2fs '{}' {}".format(img_file, size)], stderr=subprocess.STDOUT, shell=True)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Failed to resize image '{}' .. ! {}".format(img_file, str(e.output.decode())))
|
|
p = input("==> You can exit and retry with sudo or force continue (May fail installation !), Continue ? [y/N]: ")
|
|
if not p.lower() == "y":
|
|
sys.exit(1)
|
|
|
|
|
|
def install_gapps():
|
|
|
|
dl_links = {
|
|
"x86_64": ["https://master.dl.sourceforge.net/project/opengapps/x86_64/20220121/open_gapps-x86_64-10.0-pico-20220121.zip?viasf=1", "e8c9a7412f5712eea7948957a62a7d66"],
|
|
"x86": ["https://udomain.dl.sourceforge.net/project/opengapps/x86/20220122/open_gapps-x86-10.0-pico-20220122.zip", "9e39e45584b7ade4529e6be654af7b81"],
|
|
"aarch64": ["https://liquidtelecom.dl.sourceforge.net/project/opengapps/arm64/20220122/open_gapps-arm64-10.0-pico-20220122.zip", "8dfa6e76aeb2d1d5aed40b058e8a852c"],
|
|
"arm": ["https://nav.dl.sourceforge.net/project/opengapps/arm/20220122/open_gapps-arm-10.0-pico-20220122.zip", "a48ccbd25eb0a3c5e30f5db5435f5536"]
|
|
}
|
|
if platform.machine() not in dl_links.keys():
|
|
print("==> Unsupported architecture '{}' .. ".format(platform.machine()))
|
|
sys.exit(1)
|
|
google_apps_dl_link = dl_links[platform.machine()][0]
|
|
dl_file_name = os.path.join(download_loc, "open_gapps.zip")
|
|
act_md5 = dl_links[platform.machine()][1]
|
|
loc_md5 = ""
|
|
sys_image_mount = "/tmp/waydroidimage"
|
|
extract_to = "/tmp/ogapps/extract"
|
|
non_apks = [
|
|
"defaultetc-common.tar.lz",
|
|
"defaultframework-common.tar.lz",
|
|
"googlepixelconfig-common.tar.lz"
|
|
]
|
|
skip = [
|
|
"setupwizarddefault-x86_64.tar.lz",
|
|
"setupwizardtablet-x86_64.tar.lz"
|
|
]
|
|
|
|
if not os.path.exists(extract_to):
|
|
os.makedirs(extract_to)
|
|
if not os.path.exists(os.path.join(extract_to, "appunpack")):
|
|
os.makedirs(os.path.join(extract_to, "appunpack"))
|
|
|
|
if os.path.isfile(dl_file_name):
|
|
with open(dl_file_name,"rb") as f:
|
|
bytes = f.read()
|
|
loc_md5 = hashlib.md5(bytes).hexdigest()
|
|
print("==> Excepted hash: {} | File hash: {}".format(act_md5, loc_md5))
|
|
|
|
|
|
system_img = os.path.join(get_image_dir(), "system.img")
|
|
if not os.path.isfile(system_img):
|
|
print("The system image path '{}' from waydroid config is not valid !".format(system_img))
|
|
sys.exit(1)
|
|
print("==> Found system image: "+system_img)
|
|
|
|
img_size = int(os.path.getsize(system_img)/(1024*1024))
|
|
|
|
# Resize image to get some free space
|
|
resize_img(system_img, "{}M".format(img_size+500))
|
|
|
|
# Mount the system image
|
|
mount_image(system_img, sys_image_mount)
|
|
|
|
# Download the file if hash mismatches or if file does not exist
|
|
while not os.path.isfile(dl_file_name) or loc_md5 != act_md5:
|
|
if os.path.isfile(dl_file_name):
|
|
os.remove(dl_file_name)
|
|
print("==> OpenGapps zip not downloaded or hash mismatches, downloading now .....")
|
|
loc_md5 = download_file(google_apps_dl_link, dl_file_name)
|
|
|
|
# Extract opengapps
|
|
print("==> Extracting opengapps...")
|
|
with zipfile.ZipFile(dl_file_name) as z:
|
|
z.extractall(extract_to)
|
|
|
|
# Now copy the files
|
|
for lz_file in os.listdir(os.path.join(extract_to, "Core")):
|
|
for d in os.listdir(os.path.join(extract_to, "appunpack")):
|
|
shutil.rmtree(os.path.join(extract_to, "appunpack", d))
|
|
if lz_file not in skip:
|
|
if lz_file not in non_apks:
|
|
print("==> Processing app package : "+os.path.join(extract_to, "Core", lz_file))
|
|
os.system("tar --lzip -xvf '{}' -C '{}'>/dev/null".format(os.path.join(extract_to, "Core", lz_file), os.path.join(extract_to, "appunpack")))
|
|
app_name = os.listdir(os.path.join(extract_to, "appunpack"))[0]
|
|
xx_dpi = os.listdir(os.path.join(extract_to, "appunpack", app_name))[0]
|
|
app_priv = os.listdir(os.path.join(extract_to, "appunpack", app_name, "nodpi"))[0]
|
|
app_src_dir = os.path.join(extract_to, "appunpack", app_name, xx_dpi, app_priv)
|
|
for app in os.listdir(app_src_dir):
|
|
shutil.copytree(os.path.join(app_src_dir, app), os.path.join(sys_image_mount, "system", "priv-app", app), dirs_exist_ok=True)
|
|
else:
|
|
print("==> Processing extra package : "+os.path.join(extract_to, "Core", lz_file))
|
|
os.system("tar --lzip -xvf '{}' -C '{}'>/dev/null".format(os.path.join(extract_to, "Core", lz_file), os.path.join(extract_to, "appunpack")))
|
|
app_name = os.listdir(os.path.join(extract_to, "appunpack"))[0]
|
|
common_content_dirs = os.listdir(os.path.join(extract_to, "appunpack", app_name, "common"))
|
|
for ccdir in common_content_dirs:
|
|
shutil.copytree(os.path.join(extract_to, "appunpack", app_name, "common", ccdir), os.path.join(sys_image_mount, "system", ccdir), dirs_exist_ok=True)
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["umount", sys_image_mount], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
print("==> OpenGapps installation complete try re init /restarting waydroid")
|
|
print("==> Please note, google apps wont be usable without device registration !, Use --get-android-id for registration instructions")
|
|
|
|
|
|
def get_android_id():
|
|
try:
|
|
if not os.path.isfile("/var/lib/waydroid/data/data/com.google.android.gsf/databases/gservices.db"):
|
|
print("Cannot access gservices.db, make sure gapps is installed and waydroid was started at least once after installation and make sure waydroid is running !")
|
|
sys.exit(1)
|
|
sqs = """
|
|
SELECT * FROM main WHERE name='android_id'
|
|
"""
|
|
queryout = subprocess.check_output(["sqlite3", "/var/lib/waydroid/data/data/com.google.android.gsf/databases/gservices.db", sqs.strip()], stderr=subprocess.STDOUT)
|
|
print(queryout.decode().replace("android_id|", "").strip())
|
|
print(" ^----- Open https://google.com/android/uncertified/?pli=1")
|
|
print(" Login with your google id then submit the form with id shown above")
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Error getting id... '{}' ".format(str(e.output.decode())))
|
|
|
|
def install_ndk():
|
|
sys_image_mount = "/tmp/waydroidimage"
|
|
ndk_zip_url = "https://www.dropbox.com/s/eaf4dj3novwiccp/libndk_translation_Module-c6077f3398172c64f55aad7aab0e55fad9110cf3.zip?dl=1"
|
|
dl_file_name = os.path.join(download_loc, "libndktranslation.zip")
|
|
extract_to = "/tmp/libndkunpack" #All catalog files will be marked as executable!
|
|
act_md5 = "4456fc1002dc78e544e8d9721bb24398"
|
|
loc_md5 = ""
|
|
apply_props = {
|
|
"ro.product.cpu.abilist": "x86_64,x86,armeabi-v7a,armeabi,arm64-v8a",
|
|
"ro.product.cpu.abilist32": "x86,armeabi-v7a,armeabi",
|
|
"ro.product.cpu.abilist64": "x86_64,arm64-v8a",
|
|
"ro.dalvik.vm.native.bridge": "libndk_translation.so",
|
|
"ro.enable.native.bridge.exec": "1",
|
|
# "ro.ndk_translation.version": "0.2.2",
|
|
"ro.dalvik.vm.isa.arm": "x86",
|
|
"ro.dalvik.vm.isa.arm64": "x86_64"
|
|
}
|
|
init_rc_component = """
|
|
on early-init
|
|
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
|
|
|
|
on property:ro.enable.native.bridge.exec=1
|
|
exec -- /system/bin/sh -c "cat /system/etc/binfmt_misc/arm_exe > /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "cat /system/etc/binfmt_misc/arm_dyn >> /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "cat /system/etc/binfmt_misc/arm64_exe >> /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "cat /system/etc/binfmt_misc/arm64_dyn >> /proc/sys/fs/binfmt_misc/register"
|
|
"""
|
|
if os.path.isfile(dl_file_name):
|
|
with open(dl_file_name,"rb") as f:
|
|
bytes = f.read()
|
|
loc_md5 = hashlib.md5(bytes).hexdigest()
|
|
|
|
system_img = os.path.join(get_image_dir(), "system.img")
|
|
if not os.path.isfile(system_img):
|
|
print("The system image path '{}' from waydroid config is not valid !".format(system_img))
|
|
sys.exit(1)
|
|
print("==> Found system image: "+system_img)
|
|
|
|
# Resize rootfs
|
|
img_size = int(os.path.getsize(system_img)/(1024*1024))
|
|
|
|
# Resize image to get some free space
|
|
resize_img(system_img, "{}M".format(img_size+50))
|
|
|
|
# Mount the system image
|
|
mount_image(system_img, sys_image_mount)
|
|
|
|
# Download the file if hash mismatches or if file does not exist
|
|
while not os.path.isfile(dl_file_name) or loc_md5 != act_md5:
|
|
if os.path.isfile(dl_file_name):
|
|
os.remove(dl_file_name)
|
|
print("==> NDK Translation zip not downloaded or hash mismatches, downloading now .....")
|
|
loc_md5 = download_file(ndk_zip_url, dl_file_name)
|
|
|
|
# Extract ndk files
|
|
print("==> Extracting archive...")
|
|
with zipfile.ZipFile(dl_file_name) as z:
|
|
z.extractall(extract_to)
|
|
|
|
#Mark ndk files as executable
|
|
print("==> Chmodding...")
|
|
try: os.system("chmod +x "+extract_to+" -R")
|
|
except: print("==> Couldn't mark files as executable!")
|
|
|
|
# Copy library file
|
|
print("==> Copying library files ...")
|
|
shutil.copytree(os.path.join(extract_to, "libndk_translation_Module-c6077f3398172c64f55aad7aab0e55fad9110cf3", "system"), os.path.join(sys_image_mount, "system"), dirs_exist_ok=True)
|
|
|
|
# Add entries to build.prop
|
|
print("==> Adding arch in build.prop")
|
|
with open(os.path.join(sys_image_mount, "system", "build.prop"), "r") as propfile:
|
|
prop_content = propfile.read()
|
|
for key in apply_props:
|
|
if key not in prop_content:
|
|
prop_content = prop_content+"\n{key}={value}".format(key=key, value=apply_props[key])
|
|
else:
|
|
p = re.compile(r"^{key}=.*$".format(key=key), re.M)
|
|
prop_content = re.sub(p, "{key}={value}".format(key=key, value=apply_props[key]), prop_content)
|
|
with open(os.path.join(sys_image_mount, "system", "build.prop"), "w") as propfile:
|
|
propfile.write(prop_content)
|
|
|
|
|
|
# Add entry to init.rc
|
|
print("==> Adding entry to init.rc")
|
|
# Check if init.rc is located in Android 11's path
|
|
init_path = os.path.join(sys_image_mount, "system", "etc", "init", "hw", "init.rc")
|
|
if not os.path.isfile(init_path):
|
|
# init.rc not found, assuming it's located in the root folder (Android 10 and older)
|
|
init_path = os.path.join(sys_image_mount, "init.rc")
|
|
with open(init_path, "r") as initfile:
|
|
initcontent = initfile.read()
|
|
if init_rc_component not in initcontent:
|
|
initcontent=initcontent+init_rc_component
|
|
with open(init_path, "w") as initfile:
|
|
initfile.write(initcontent)
|
|
|
|
# Unmount and exit
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["umount", sys_image_mount], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
|
|
print("==> libndk translation installed ! Restart waydroid service to apply changes !")
|
|
|
|
|
|
def install_houdini():
|
|
sys_image_mount = "/tmp/waydroidimage"
|
|
houdini_zip_url = "https://www.dropbox.com/s/v7g0fluc7e8tod8/libhoudini.zip?dl=1"
|
|
dl_file_name = os.path.join(download_loc, "libhoudini.zip")
|
|
extract_to = "/tmp/houdiniunpack" #All catalog files will be marked as executable!
|
|
act_md5 = "838097117cec7762e958d7cbc209415e"
|
|
loc_md5 = ""
|
|
|
|
apply_props = {
|
|
"ro.product.cpu.abilist": "x86_64,x86,arm64-v8a,armeabi-v7a,armeabi",
|
|
"ro.product.cpu.abilist32": "x86,armeabi-v7a,armeabi",
|
|
"ro.product.cpu.abilist64": "x86_64,arm64-v8a",
|
|
"ro.dalvik.vm.native.bridge": "libhoudini.so",
|
|
"ro.enable.native.bridge.exec": "1",
|
|
"ro.dalvik.vm.isa.arm": "x86",
|
|
"ro.dalvik.vm.isa.arm64": "x86_64"
|
|
}
|
|
init_rc_component = """
|
|
on early-init
|
|
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
|
|
|
|
on property:ro.enable.native.bridge.exec=1
|
|
exec -- /system/bin/sh -c "echo ':arm_exe:M::\\\\x7f\\\\x45\\\\x4c\\\\x46\\\\x01\\\\x01\\\\x01\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x02\\\\x00\\\\x28::/system/bin/houdini:P' > /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "echo ':arm_dyn:M::\\\\x7f\\\\x45\\\\x4c\\\\x46\\\\x01\\\\x01\\\\x01\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x03\\\\x00\\\\x28::/system/bin/houdini:P' >> /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "echo ':arm64_exe:M::\\\\x7f\\\\x45\\\\x4c\\\\x46\\\\x02\\\\x01\\\\x01\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x02\\\\x00\\\\xb7::/system/bin/houdini64:P' >> /proc/sys/fs/binfmt_misc/register"
|
|
exec -- /system/bin/sh -c "echo ':arm64_dyn:M::\\\\x7f\\\\x45\\\\x4c\\\\x46\\\\x02\\\\x01\\\\x01\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x03\\\\x00\\\\xb7::/system/bin/houdini64:P' >> /proc/sys/fs/binfmt_misc/register"
|
|
"""
|
|
|
|
if os.path.isfile(dl_file_name):
|
|
with open(dl_file_name,"rb") as f:
|
|
bytes = f.read()
|
|
loc_md5 = hashlib.md5(bytes).hexdigest()
|
|
|
|
system_img = os.path.join(get_image_dir(), "system.img")
|
|
if not os.path.isfile(system_img):
|
|
print("The system image path '{}' from waydroid config is not valid !".format(system_img))
|
|
sys.exit(1)
|
|
print("==> Found system image: "+system_img)
|
|
|
|
img_size = int(os.path.getsize(system_img)/(1024*1024))
|
|
|
|
# Resize image to get some free space
|
|
resize_img(system_img, "{}M".format(img_size+300))
|
|
|
|
|
|
# Mount the system image
|
|
mount_image(system_img, sys_image_mount)
|
|
|
|
# Download the file if hash mismatches or if file does not exist
|
|
while not os.path.isfile(dl_file_name) or loc_md5 != act_md5:
|
|
if os.path.isfile(dl_file_name):
|
|
os.remove(dl_file_name)
|
|
print("==> libhoudini zip not downloaded or hash mismatches, downloading now .....")
|
|
loc_md5 = download_file(houdini_zip_url, dl_file_name)
|
|
|
|
# Extract ndk files
|
|
print("==> Extracting archive...")
|
|
with zipfile.ZipFile(dl_file_name) as z:
|
|
z.extractall(extract_to)
|
|
|
|
# Mark libhoudini files as executable
|
|
print("==> Chmodding...")
|
|
try: os.system("chmod +x "+extract_to+" -R")
|
|
except: print("==> Couldn't mark files as executable!")
|
|
|
|
# Copy library file
|
|
print("==> Copying library files ...")
|
|
shutil.copytree(os.path.join(extract_to, "system"), os.path.join(sys_image_mount, "system"), dirs_exist_ok=True)
|
|
|
|
# Add entries to build.prop
|
|
print("==> Adding arch in build.prop")
|
|
with open(os.path.join(sys_image_mount, "system", "build.prop"), "r") as propfile:
|
|
prop_content = propfile.read()
|
|
for key in apply_props:
|
|
if key not in prop_content:
|
|
prop_content = prop_content+"\n{key}={value}".format(key=key, value=apply_props[key])
|
|
else:
|
|
p = re.compile(r"^{key}=.*$".format(key=key), re.M)
|
|
prop_content = re.sub(p, "{key}={value}".format(key=key, value=apply_props[key]), prop_content)
|
|
with open(os.path.join(sys_image_mount, "system", "build.prop"), "w") as propfile:
|
|
propfile.write(prop_content)
|
|
|
|
# Add entry to init.rc
|
|
print("==> Adding entry to init.rc")
|
|
# Check if init.rc is located in Android 11's path
|
|
init_path = os.path.join(sys_image_mount, "system", "etc", "init", "hw", "init.rc")
|
|
if not os.path.isfile(init_path):
|
|
# init.rc not found, assuming it's located in the root folder (Android 10 and older)
|
|
init_path = os.path.join(sys_image_mount, "init.rc")
|
|
with open(init_path, "r") as initfile:
|
|
initcontent = initfile.read()
|
|
if init_rc_component not in initcontent:
|
|
initcontent=initcontent+init_rc_component
|
|
with open(init_path, "w") as initfile:
|
|
initfile.write(initcontent)
|
|
|
|
# Unmount and exit
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["umount", sys_image_mount], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
|
|
print("==> libhoudini translation installed ! Restart waydroid service to apply changes !")
|
|
|
|
def install_magisk():
|
|
dl_link = "https://huskydg.github.io/magisk-files/app-release.apk"
|
|
dl_file_name = os.path.join(download_loc, "magisk.apk")
|
|
extract_to = "/tmp/magisk_unpack"
|
|
# act_md5 = "d60706f6ac22dc7ee32ae297e5252ef7"
|
|
sys_image_mount = "/tmp/waydroidimage"
|
|
sbin_dir = os.path.join(sys_image_mount, "sbin")
|
|
# loc_md5 = ""
|
|
init_rc_component = """
|
|
on post-fs-data
|
|
start logd
|
|
mkdir /dev/waydroid-magisk
|
|
mount tmpfs tmpfs /dev/waydroid-magisk mode=0755
|
|
copy /sbin/magisk64 /dev/waydroid-magisk/magisk64
|
|
chmod 0755 /dev/waydroid-magisk/magisk64
|
|
symlink ./magisk64 /dev/waydroid-magisk/magisk
|
|
exec - root root -- /dev/waydroid-magisk/magisk64 --install
|
|
copy /sbin/magisk32 /dev/waydroid-magisk/magisk32
|
|
chmod 0755 /dev/waydroid-magisk/magisk32
|
|
copy /sbin/magiskinit /dev/waydroid-magisk/magiskinit
|
|
chmod 0755 /dev/waydroid-magisk/magiskinit
|
|
copy /sbin/magiskpolicy /dev/waydroid-magisk/magiskpolicy
|
|
chmod 0755 /dev/waydroid-magisk/magiskpolicy
|
|
exec - root root -- /dev/waydroid-magisk/magiskpolicy --live --magisk "allow * magisk_file lnk_file *"
|
|
exec - root root -- /dev/waydroid-magisk/magiskinit -x manager /dev/waydroid-magisk/stub.apk
|
|
write /dev/.magisk_livepatch 0
|
|
mkdir /dev/waydroid-magisk/.magisk 700
|
|
mkdir /dev/waydroid-magisk/.magisk/mirror 700
|
|
mkdir /dev/waydroid-magisk/.magisk/block 700
|
|
start FAhW7H9G5sf
|
|
wait /dev/.magisk_unblock 40
|
|
|
|
service FAhW7H9G5sf /dev/waydroid-magisk/magisk --post-fs-data
|
|
user root
|
|
seclabel -
|
|
oneshot
|
|
|
|
service HLiFsR1HtIXVN6 /dev/waydroid-magisk/magisk --service
|
|
class late_start
|
|
user root
|
|
seclabel -
|
|
oneshot
|
|
|
|
on property:sys.boot_completed=1
|
|
mkdir /data/adb/magisk 755
|
|
exec - root root -- /dev/waydroid-magisk/magisk --boot-complete
|
|
|
|
on property:init.svc.zygote=restarting
|
|
exec - root root -- /dev/waydroid-magisk/magisk --zygote-restart
|
|
|
|
on property:init.svc.zygote=stopped
|
|
exec - root root -- /dev/waydroid-magisk/magisk --zygote-restart
|
|
"""
|
|
|
|
system_img = os.path.join(get_image_dir(), "system.img")
|
|
if not os.path.isfile(system_img):
|
|
print("The system image path '{}' from waydroid config is not valid !".format(system_img))
|
|
sys.exit(1)
|
|
print("==> Found system image: " + system_img)
|
|
|
|
img_size = int(os.path.getsize(system_img)/(1024*1024))
|
|
|
|
# Resize image to get some free space
|
|
resize_img(system_img, "{}M".format(img_size+50))
|
|
|
|
# Mount the system image
|
|
mount_image(system_img, sys_image_mount)
|
|
|
|
# Download magisk
|
|
while not os.path.isfile(dl_file_name):
|
|
if os.path.isfile(dl_file_name):
|
|
os.remove(dl_file_name)
|
|
print("==> Magisk zip not downloaded or hash mismatches, downloading now .....")
|
|
loc_md5 = download_file(dl_link, dl_file_name)
|
|
|
|
# Extract magisk files
|
|
print("==> Extracting archive...")
|
|
with zipfile.ZipFile(dl_file_name) as z:
|
|
z.extractall(extract_to)
|
|
|
|
if not os.path.exists(sbin_dir):
|
|
os.makedirs(sbin_dir, exist_ok=True)
|
|
|
|
# Now setup and install magisk binary and app
|
|
print("==> Installing magisk now ...")
|
|
|
|
arch_dir = "x86" if "x86" in platform.machine() else "arm"
|
|
arch = "_64" if "64" in platform.machine() else ""
|
|
|
|
lib_dir = os.path.join(extract_to, "lib", "{arch_dir}{arch}".format(arch_dir=arch_dir, arch=arch))
|
|
for parent, dirnames, filenames in os.walk(lib_dir):
|
|
for filename in filenames:
|
|
o_path = os.path.join(lib_dir, filename)
|
|
filename = re.search('lib(.*)\.so', filename)
|
|
n_path = os.path.join(sbin_dir, filename.group(1))
|
|
shutil.copyfile(o_path, n_path)
|
|
|
|
# Add entry to init.rc
|
|
print("==> Adding entry to init.rc")
|
|
init_path = os.path.join(sys_image_mount, "system", "etc", "init", "hw", "init.rc")
|
|
if not os.path.isfile(init_path):
|
|
# init.rc not found, assuming it's located in the root folder (Android 10 and older)
|
|
init_path = os.path.join(sys_image_mount, "init.rc")
|
|
with open(init_path, "r") as initfile:
|
|
initcontent = initfile.read()
|
|
if init_rc_component not in initcontent:
|
|
initcontent=initcontent+init_rc_component
|
|
with open(init_path, "w") as initfile:
|
|
initfile.write(initcontent)
|
|
# Unmount and exit
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["umount", sys_image_mount], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
|
|
|
|
print("==> Magisk was installed ! Restart waydroid service to apply changes !")
|
|
|
|
def install_widevine():
|
|
vendor_image_mount = "/tmp/waydroidvendor"
|
|
widevine_zip_url = "https://codeload.github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/zip/refs/heads/chromeos_hatch"
|
|
dl_file_name = os.path.join(download_loc, "widevine.zip")
|
|
extract_to = "/tmp/widevineunpack" #All catalog files will be marked as executable!
|
|
act_md5 = "7fe3b2a9502da9ad63189a077c457ad2"
|
|
loc_md5 = ""
|
|
|
|
if os.path.isfile(dl_file_name):
|
|
with open(dl_file_name,"rb") as f:
|
|
bytes = f.read()
|
|
loc_md5 = hashlib.md5(bytes).hexdigest()
|
|
vendor_img = os.path.join(get_image_dir(), "vendor.img")
|
|
if not os.path.isfile(vendor_img):
|
|
print("The vendor image path '{}' from waydroid config is not valid !".format(vendor_img))
|
|
sys.exit(1)
|
|
print("==> Found vendor image: "+vendor_img)
|
|
|
|
img_size = int(os.path.getsize(vendor_img)/(1024*1024))
|
|
|
|
# Resize image to get some free space
|
|
resize_img(vendor_img, "{}M".format(img_size+50))
|
|
|
|
# Mount the system image
|
|
mount_image(vendor_img, vendor_image_mount)
|
|
|
|
# Download the file if hash mismatches or if file does not exist
|
|
while not os.path.isfile(dl_file_name) or loc_md5 != act_md5:
|
|
if os.path.isfile(dl_file_name):
|
|
os.remove(dl_file_name)
|
|
print("==> windevine zip not downloaded or hash mismatches, downloading now .....")
|
|
loc_md5 = download_file(widevine_zip_url, dl_file_name)
|
|
|
|
# Extract widevine files
|
|
print("==> Extracting archive...")
|
|
with zipfile.ZipFile(dl_file_name) as z:
|
|
z.extractall(extract_to)
|
|
|
|
#Mark widevine files as executable
|
|
print("==> Chmodding...")
|
|
try: os.system("chmod +x "+extract_to+" -R")
|
|
except: print("==> Couldn't mark files as executable!")
|
|
|
|
# Copy library file
|
|
print("==> Copying library files ...")
|
|
shutil.copytree(os.path.join(extract_to, "vendor_google_proprietary_widevine-prebuilt-chromeos_hatch", "prebuilts"), vendor_image_mount, dirs_exist_ok=True)
|
|
|
|
print("==> Unmounting .. ")
|
|
try:
|
|
subprocess.check_output(["umount", vendor_image_mount], stderr=subprocess.STDOUT)
|
|
except subprocess.CalledProcessError as e:
|
|
print("==> Warning: umount failed.. {} ".format(str(e.output.decode())))
|
|
|
|
print("==> Widevine installed ! Restart waydroid service to apply changes !")
|
|
|
|
def main():
|
|
about = """
|
|
WayDroid Helper script v0.3
|
|
Does stuff like installing Gapps, Installing NDK Translation and getting Android ID for device registration.
|
|
Use -h flag for help !
|
|
"""
|
|
parser = argparse.ArgumentParser(description=about, formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
parser.add_argument('-g', '--install-gapps',
|
|
dest='install',
|
|
help='Install OpenGapps to waydroid',
|
|
action='store_true')
|
|
parser.add_argument('-n', '--install-ndk-translation',
|
|
dest='installndk',
|
|
help='Install experimental libndk translation files',
|
|
action='store_true')
|
|
parser.add_argument('-i', '--get-android-id', dest='getid',
|
|
help='Displays your android id for manual registration',
|
|
action='store_true')
|
|
parser.add_argument('-m', '--install-magisk', dest='magisk',
|
|
help='Attempts to install Magisk ( Bootless )',
|
|
action='store_true')
|
|
parser.add_argument('-l', '--install-libhoudini', dest='houdini',
|
|
help='Install libhoudini for arm translation',
|
|
action='store_true')
|
|
parser.add_argument('-w', '--install-windevine', dest='widevine',
|
|
help='Integrate Widevine DRM (L3)',
|
|
action='store_true')
|
|
|
|
args = parser.parse_args()
|
|
if args.install:
|
|
stop_waydroid()
|
|
install_gapps()
|
|
elif args.installndk:
|
|
stop_waydroid()
|
|
install_ndk()
|
|
elif args.getid:
|
|
get_android_id()
|
|
elif args.magisk:
|
|
install_magisk()
|
|
elif args.houdini:
|
|
install_houdini()
|
|
elif args.widevine:
|
|
install_widevine()
|
|
|
|
if __name__ == "__main__": #sbin
|
|
main()
|