diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c890b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,106 @@ +git +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so +*.out +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version +.idea/ +# celery beat schedule file +celerybeat-schedule +workspace.xml +# SageMath parsed files +*.sage.py +.idea/workspace.xml +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + diff --git a/main.py b/main.py new file mode 100644 index 0000000..9a176d4 --- /dev/null +++ b/main.py @@ -0,0 +1,58 @@ +import argparse +from stuffs.android_id import Android_id +from stuffs.gapps import Gapps +from stuffs.houdini import Houdini +from stuffs.magisk import Magisk +from stuffs.ndk import Ndk +from stuffs.widevine import Widevine +import tools.helper as helper + + +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 ! + """ + helper.check_root() + parser = argparse.ArgumentParser(description=about, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-g', '--install-gapps', + dest='gapps', + help='Install OpenGapps to waydroid', + action='store_true') + parser.add_argument('-n', '--install-ndk-translation', + dest='ndk', + help='Install libndk translation for arm translation', + 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.getid: + Android_id().get_id() + if args.gapps: + Gapps().install() + if args.ndk and not args.houdini: + arch = helper.host()[0] + if arch == "x86" or arch == "x86_64": + Ndk().install() + if args.houdini and not args.ndk: + arch = helper.host()[0] + if arch == "x86" or arch == "x86_64": + Houdini().install() + if args.magisk: + Magisk().install() + if args.widevine: + Widevine().install() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/stuffs/android_id.py b/stuffs/android_id.py new file mode 100644 index 0000000..4d52d10 --- /dev/null +++ b/stuffs/android_id.py @@ -0,0 +1,18 @@ +import os +import sys +from tools.helper import run +from tools.logger import Logger + + +class Android_id: + def get_id(self): + if not os.path.isfile("/var/lib/waydroid/data/data/com.google.android.gsf/databases/gservices.db"): + Logger.error("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 = run(["sqlite3", "/var/lib/waydroid/data/data/com.google.android.gsf/databases/gservices.db", sqs.strip()]) + print(queryout.stdout.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") \ No newline at end of file diff --git a/stuffs/gapps.py b/stuffs/gapps.py new file mode 100644 index 0000000..49457a1 --- /dev/null +++ b/stuffs/gapps.py @@ -0,0 +1,59 @@ +import os +import shutil +from stuffs.general import General +from tools.helper import host, run +from tools.logger import Logger + +class Gapps(General): + partition = "system" + 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"], + "arm64-v8a": ["https://liquidtelecom.dl.sourceforge.net/project/opengapps/arm64/20220122/open_gapps-arm64-10.0-pico-20220122.zip", "8dfa6e76aeb2d1d5aed40b058e8a852c"], + "armeabi-v7a": ["https://nav.dl.sourceforge.net/project/opengapps/arm/20220122/open_gapps-arm-10.0-pico-20220122.zip", "a48ccbd25eb0a3c5e30f5db5435f5536"] + } + arch = host() + dl_link = dl_links[arch[0]][0] + dl_file_name = "open_gapps.zip" + act_md5 = dl_links[arch[0]][1] + 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" + ] + + def download(self): + Logger.info("Downloading OpenGapps now to {} .....".format(self.download_loc)) + super().download() + + def copy(self): + if not os.path.exists(self.extract_to): + os.makedirs(self.extract_to) + if not os.path.exists(os.path.join(self.extract_to, "appunpack")): + os.makedirs(os.path.join(self.extract_to, "appunpack")) + + for lz_file in os.listdir(os.path.join(self.extract_to, "Core")): + for d in os.listdir(os.path.join(self.extract_to, "appunpack")): + shutil.rmtree(os.path.join(self.extract_to, "appunpack", d)) + if lz_file not in self.skip: + if lz_file not in self.non_apks: + print(" Processing app package : "+os.path.join(self.extract_to, "Core", lz_file)) + run(["tar", "--lzip", "-xvf", os.path.join(self.extract_to, "Core", lz_file), "-C", os.path.join(self.extract_to, "appunpack")]) + app_name = os.listdir(os.path.join(self.extract_to, "appunpack"))[0] + xx_dpi = os.listdir(os.path.join(self.extract_to, "appunpack", app_name))[0] + app_priv = os.listdir(os.path.join(self.extract_to, "appunpack", app_name, "nodpi"))[0] + app_src_dir = os.path.join(self.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(self.copy_dir, self.partition, "priv-app", app), dirs_exist_ok=True) + else: + print(" Processing extra package : "+os.path.join(self.extract_to, "Core", lz_file)) + run(["tar", "--lzip", "-xvf", os.path.join(self.extract_to, "Core", lz_file), "-C", os.path.join(self.extract_to, "appunpack")]) + app_name = os.listdir(os.path.join(self.extract_to, "appunpack"))[0] + common_content_dirs = os.listdir(os.path.join(self.extract_to, "appunpack", app_name, "common")) + for ccdir in common_content_dirs: + shutil.copytree(os.path.join(self.extract_to, "appunpack", app_name, "common", ccdir), os.path.join(self.copy_dir, self.partition, ccdir), dirs_exist_ok=True) \ No newline at end of file diff --git a/stuffs/general.py b/stuffs/general.py new file mode 100644 index 0000000..d7c9d29 --- /dev/null +++ b/stuffs/general.py @@ -0,0 +1,132 @@ +import os +import re +import zipfile +import hashlib +from tools import images +from tools.helper import download_file, get_download_dir, run +from tools.container import DBusContainerService +from tools.logger import Logger + +class General: + @property + def download_loc(self): + return os.path.join(get_download_dir(), self.dl_file_name) + + @property + def copy_dir(self): + if self.use_overlayfs: + return "/var/lib/waydroid/overlay" + else: + return "/tmp/waydroid" + + @property + def use_dbus(self): + try: + DBusContainerService() + except: + return False + return + + @property + def use_overlayfs(self): + return os.path.isdir("/var/lib/waydroid/overlay") + # return False + + def download(self): + loc_md5 = "" + if os.path.isfile(self.download_loc): + with open(self.download_loc, "rb") as f: + bytes = f.read() + loc_md5 = hashlib.md5(bytes).hexdigest() + while not os.path.isfile(self.download_loc) or loc_md5 != self.act_md5: + if os.path.isfile(self.download_loc): + os.remove(self.download_loc) + Logger.warning( + "md5 mismatches, redownloading now ....") + loc_md5 = download_file(self.dl_link, self.download_loc) + + def extract(self): + Logger.info("Extracting archive...") + with zipfile.ZipFile(self.download_loc) as z: + z.extractall(self.extract_to) + + def add_props(self): + with open(os.path.join("/var/lib/waydroid/waydroid_base.prop"), "r") as propfile: + prop_content = propfile.read() + for key in self.apply_props: + if key not in prop_content: + prop_content = prop_content+"\n{key}={value}".format(key=key, value=self.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=self.apply_props[key]), prop_content) + with open(os.path.join("/var/lib/waydroid/waydroid_base.prop"), "w") as propfile: + propfile.write(prop_content) + + def mount(self): + img = os.path.join(images.get_image_dir(), self.partition+".img") + mount_point = "" + if self.partition == "system": + mount_point = os.path.join(self.copy_dir) + else: + mount_point = os.path.join(self.copy_dir, self.partition) + Logger.info("Mounting {} to {}".format(img, mount_point)) + images.mount(img, mount_point) + + def resize(self): + img = os.path.join(images.get_image_dir(), self.partition+".img") + img_size = int(os.path.getsize(img)/(1024*1024)) + new_size = "{}M".format(img_size+500) + Logger.info("Resizing {} to {}".format(img, new_size)) + images.resize(img, new_size) + + def umount(self): + mount_point = "" + if self.partition == "system": + mount_point = os.path.join(self.copy_dir) + else: + mount_point = os.path.join(self.copy_dir, self.partition) + Logger.info("Umounting {}".format(mount_point)) + images.umount(mount_point) + + def stop(self): + if self.use_dbus: + self.session = DBusContainerService().GetSession() + if self.session: + DBusContainerService().Stop(False) + else: + run(["waydroid", "container", "stop"]) + + def start(self): + if self.use_dbus: + DBusContainerService().Start(self.session) + else: + run(["systemctl", "restart", "waydroid-container.service"]) + + def restart(self): + if DBusContainerService().GetSession(): + self.stop() + self.start() + + def copy(self): + pass + + def install(self): + if self.use_overlayfs: + self.download() + self.extract() + self.copy() + if hasattr(self, "apply_props"): + self.add_props() + self.restart() + else: + self.stop() + self.download() + self.extract() + self.resize() + self.mount() + self.copy() + if hasattr(self, "apply_props"): + self.add_props() + self.umount() + self.start() + Logger.info("Installation finished") \ No newline at end of file diff --git a/stuffs/houdini.py b/stuffs/houdini.py new file mode 100644 index 0000000..0ac7db2 --- /dev/null +++ b/stuffs/houdini.py @@ -0,0 +1,49 @@ +import os +import re +import shutil +from stuffs.general import General +from tools.helper import run +from tools.logger import Logger + + +class Houdini(General): + partition = "system" + dl_link = "https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/81f2a51ef539a35aead396ab7fce2adf89f46e88.zip" + act_md5 = "fbff756612b4144797fbc99eadcb6653" + dl_file_name = "libhoudini.zip" + extract_to = "/tmp/houdiniunpack" + 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" +""" + 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" + } + + def download(self): + Logger.info("Downloading libhoudini to {}now .....".format(self.download_loc)) + super().download() + + def copy(self): + run(["chmod", "+x", self.extract_to, "-R"]) + Logger.info("Copying libhoudini library files ...") + name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0] + shutil.copytree(os.path.join(self.extract_to, "vendor_intel_proprietary_houdini-" + name, + "prebuilts"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True) + init_path = os.path.join(self.copy_dir, self.partition, "etc", "init", "houdini.rc") + if not os.path.isfile(init_path): + os.makedirs(os.path.dirname(init_path), exist_ok=True) + with open(init_path, "w") as initfile: + initfile.write(self.init_rc_component) diff --git a/stuffs/magisk.py b/stuffs/magisk.py new file mode 100644 index 0000000..3b918d7 --- /dev/null +++ b/stuffs/magisk.py @@ -0,0 +1,89 @@ +import gzip +import os +import shutil +import re +from stuffs.general import General +from tools.helper import download_file, host, run +from tools.logger import Logger + +class Magisk(General): + partition = "system" + dl_link = "https://huskydg.github.io/magisk-files/app-release.apk" + dl_file_name = "magisk.apk" + extract_to = "/tmp/magisk_unpack" + magisk_dir = os.path.join(partition, "etc", "init", "magisk") + machine = host() + oringinal_bootanim = """ +service bootanim /system/bin/bootanimation + class core animation + user graphics + group graphics audio + disabled + oneshot + ioprio rt 0 + task_profiles MaxPerformance + +""" + bootanim_component = """ +on post-fs-data + start logd + exec u:r:su:s0 root root -- /system/etc/init/magisk/magisk{arch} --auto-selinux --setup-sbin /system/etc/init/magisk + exec u:r:su:s0 root root -- /system/etc/init/magisk/magiskpolicy --live --magisk "allow * magisk_file lnk_file *" + mkdir /sbin/.magisk 700 + mkdir /sbin/.magisk/mirror 700 + mkdir /sbin/.magisk/block 700 + copy /system/etc/init/magisk/config /sbin/.magisk/config + rm /dev/.magisk_unblock + exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --post-fs-data + wait /dev/.magisk_unblock 40 + rm /dev/.magisk_unblock + +on zygote-start + exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --service + +on property:sys.boot_completed=1 + mkdir /data/adb/magisk 755 + exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --boot-complete + exec -- /system/bin/sh -c "if [ ! -e /data/data/io.github.huskydg.magisk ] ; then pm install /system/etc/init/magisk/magisk.apk ; fi" + +on property:init.svc.zygote=restarting + exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --zygote-restart + +on property:init.svc.zygote=stopped + exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --zygote-restart + """.format(arch=machine[1]) + + def download(self): + if os.path.isfile(self.download_loc): + os.remove(self.download_loc) + Logger.info("Downloading latest Magisk-Delta to {} now ...".format(self.download_loc)) + download_file(self.dl_link, self.download_loc) + + def copy(self): + magisk_absolute_dir = os.path.join(self.copy_dir, self.magisk_dir) + if not os.path.exists(magisk_absolute_dir): + os.makedirs(magisk_absolute_dir, exist_ok=True) + + if not os.path.exists(os.path.join(self.copy_dir, "sbin")): + os.makedirs(os.path.join(self.copy_dir, "sbin"), exist_ok=True) + + Logger.info("Copying magisk libs now ...") + + lib_dir = os.path.join(self.extract_to, "lib", self.machine[0]) + 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(magisk_absolute_dir, filename.group(1)) + shutil.copyfile(o_path, n_path) + run(["chmod", "+x", n_path]) + shutil.copyfile(self.download_loc, os.path.join(magisk_absolute_dir,"magisk.apk") ) + + # Updating Magisk from Magisk manager will modify bootanim.rc, + # So it is necessary to backup the original bootanim.rc. + bootanim_path = os.path.join(self.copy_dir, self.partition, "etc", "init", "bootanim.rc") + gz_filename = os.path.join(bootanim_path)+".gz" + with gzip.open(gz_filename,'wb') as f_gz: + f_gz.write(self.oringinal_bootanim.encode('utf-8')) + with open(bootanim_path, "w") as initfile: + initfile.write(self.oringinal_bootanim+self.bootanim_component) \ No newline at end of file diff --git a/stuffs/ndk.py b/stuffs/ndk.py new file mode 100644 index 0000000..0a6c746 --- /dev/null +++ b/stuffs/ndk.py @@ -0,0 +1,48 @@ +import os +import shutil +from stuffs.general import General +from tools.helper import run +from tools.logger import Logger + +class Ndk(General): + partition = "system" + dl_link = "https://www.dropbox.com/s/eaf4dj3novwiccp/libndk_translation_Module-c6077f3398172c64f55aad7aab0e55fad9110cf3.zip?dl=1" + dl_file_name = "libndktranslation.zip" + extract_to = "/tmp/libndkunpack" + act_md5 = "4456fc1002dc78e544e8d9721bb24398" + 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 = """ +# Enable native bridge for target executables +on early-init + mount binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc + +on property:ro.enable.native.bridge.exec=1 + copy /system/etc/binfmt_misc/arm_exe /proc/sys/fs/binfmt_misc/register + copy /system/etc/binfmt_misc/arm_dyn /proc/sys/fs/binfmt_misc/register + copy /system/etc/binfmt_misc/arm64_exe /proc/sys/fs/binfmt_misc/register + copy /system/etc/binfmt_misc/arm64_dyn /proc/sys/fs/binfmt_misc/register +""" + + def download(self): + Logger.info("Downloading libndk to {} now .....".format(self.download_loc)) + super().download() + + def copy(self): + run(["chmod", "+x", self.extract_to, "-R"]) + Logger.info("Copying libndk library files ...") + shutil.copytree(os.path.join(self.extract_to, "libndk_translation_Module-c6077f3398172c64f55aad7aab0e55fad9110cf3", "system"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True) + + init_path = os.path.join(self.copy_dir, self.partition, "etc", "init", "libndk.rc") + if not os.path.isfile(init_path): + os.makedirs(os.path.dirname(init_path), exist_ok=True) + with open(init_path, "w") as initfile: + initfile.write(self.init_rc_component) \ No newline at end of file diff --git a/stuffs/widevine.py b/stuffs/widevine.py new file mode 100644 index 0000000..58899f3 --- /dev/null +++ b/stuffs/widevine.py @@ -0,0 +1,23 @@ +import os +import shutil +from stuffs.general import General +from tools.helper import run +from tools.logger import Logger + + +class Widevine(General): + partition = "vendor" + dl_link = "https://codeload.github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/zip/94c9ee172e3d78fecc81863f50a59e3646f7a2bd" + dl_file_name = "widevine.zip" + extract_to = "/tmp/widevineunpack" + act_md5 = "a31f325453c5d239c21ecab8cfdbd878" + + def download(self): + Logger.info("Downloading widevine to {} now .....".format(self.download_loc)) + super().download() + + def copy(self): + run(["chmod", "+x", self.extract_to, "-R"]) + Logger.info("Copying widevine library files ...") + shutil.copytree(os.path.join(self.extract_to, "vendor_google_proprietary_widevine-prebuilt-94c9ee172e3d78fecc81863f50a59e3646f7a2bd", + "prebuilts"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True) \ No newline at end of file diff --git a/tools/container.py b/tools/container.py new file mode 100644 index 0000000..d0e385a --- /dev/null +++ b/tools/container.py @@ -0,0 +1,7 @@ +import dbus + +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) \ No newline at end of file diff --git a/tools/helper.py b/tools/helper.py new file mode 100644 index 0000000..a476284 --- /dev/null +++ b/tools/helper.py @@ -0,0 +1,74 @@ +import os +import platform +import subprocess +import sys +import requests +from tools.logger import Logger +from tqdm import tqdm +import hashlib + +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: + download_loc = os.path.join(os.environ["XDG_CACHE_HOME"], "waydroid-script", "downloads") + if not os.path.exists(download_loc): + os.makedirs(download_loc) + return download_loc + +def run(args): + result = subprocess.run(args=args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # print(result.stdout.decode()) + if result.stderr: + Logger.error(result.stderr.decode("utf-8")) + raise subprocess.CalledProcessError( + returncode = result.returncode, + cmd = result.args, + stderr = result.stderr + ) + return result + +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: + raise ValueError("Something went wrong while downloading") + return md5 + +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) + return mapping[machine] + raise ValueError("platform.machine '" + machine + "'" + " architecture is not supported") + + +def check_root(): + if os.geteuid() != 0: + Logger.error("This script must be run as root. Aborting.") + sys.exit(1) diff --git a/tools/images.py b/tools/images.py new file mode 100644 index 0000000..eb7f0d2 --- /dev/null +++ b/tools/images.py @@ -0,0 +1,47 @@ +import configparser +import os +import subprocess +import sys +from tools.helper import run +from tools.logger import Logger + +def mount(image, mount_point): + umount(mount_point, False) + if not os.path.exists(mount_point): + os.makedirs(mount_point) + run(["mount", "-o", "rw", image, mount_point]) + +def umount(mount_point, exists=True): + if not os.path.exists(mount_point): + if not exists: + return + Logger.error("{} does not exist!".format(mount_point)) + raise FileNotFoundError() + if not run(["mountpoint", mount_point]).returncode: + run(["umount", mount_point]) + else: + Logger.warning("{} is not a mount point".format( + mount_point)) + +def resize(img_file, size): + try: + run(["e2fsck", "-y", "-f", img_file]) + except subprocess.CalledProcessError: + pass + try: + run(["resize2fs", img_file, size]) + except subprocess.CalledProcessError: + pass + +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("ERROR: Required entry in config was not found, Cannot continue!") #magisk + sys.exit(1) + return cfg["waydroid"]["images_path"] \ No newline at end of file diff --git a/tools/logger.py b/tools/logger.py new file mode 100644 index 0000000..358c0b0 --- /dev/null +++ b/tools/logger.py @@ -0,0 +1,13 @@ +class Logger: + + @staticmethod + def error(str): + print("\033[31m"+"ERROR: "+str+"\033[0m") + + @staticmethod + def info(str): + print("\033[32m"+"INFO: "+"\033[0m"+str) + + @staticmethod + def warning(str): + print("\033[33m"+"WARN: "+str+"\033[0m") diff --git a/waydroid_extras.py b/waydroid_extras.py deleted file mode 100755 index d59e66c..0000000 --- a/waydroid_extras.py +++ /dev/null @@ -1,556 +0,0 @@ -import sys -import os -import hashlib -import shutil -import zipfile -import subprocess -import argparse -import platform -from tqdm import tqdm -import requests -import re -import gzip -import dbus -import subprocess - -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 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(): - print("x86_64 CPU does not support SSE4.2, falling back to x86...") - return ("x86", 32) - return mapping[machine] - raise ValueError("platform.machine '" + machine + "'" - " architecture is not supported") - -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 check_root(): - if os.geteuid() != 0: - print("This script must be run as root. Aborting.") - sys.exit(1) - -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 restart(): - waydroid_session = DBusContainerService().GetSession() - if DBusContainerService().GetSession(): - DBusContainerService().Stop() - DBusContainerService().Start(waydroid_session) - -def run(args): - result = subprocess.run(args=args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if result.stderr: - print(result.stderr.decode("utf-8")) - raise subprocess.CalledProcessError( - returncode = result.returncode, - cmd = result.args, - stderr = result.stderr - ) - return result - -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 = "/var/lib/waydroid/overlay" - 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)) - - # 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)) - run(["tar", "--lzip", "-xvf", os.path.join(extract_to, "Core", lz_file), "-C", 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)) - run(["tar", "--lzip", "-xvf", os.path.join(extract_to, "Core", lz_file), "-C", 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("==> 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") - restart() - - -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 = run(["sqlite3", "/var/lib/waydroid/data/data/com.google.android.gsf/databases/gservices.db", sqs.strip()]) - print(queryout.stdout.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" - sys_image_mount = "/var/lib/waydroid/overlay" - prop_file = "/var/lib/waydroid/waydroid_base.prop" - 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() - - # 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...") - run(["chmod", "+x", extract_to, "-R"]) - - # 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", prop_file) - with open(os.path.join(prop_file), "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(prop_file), "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", "houdini.rc") - if not os.path.isfile(init_path): - os.makedirs(os.path.dirname(init_path), exist_ok=True) - f = open(init_path, "x") - 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) - - print("==> libndk translation installed ! Restarting waydroid service to apply changes !") - restart() - - -def install_houdini(): - sys_image_mount = "/var/lib/waydroid/overlay" - prop_file = "/var/lib/waydroid/waydroid_base.prop" - 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() - - # 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...") - run(["chmod", "+x", extract_to, "-R"]) - - # 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", prop_file) - with open(os.path.join(prop_file), "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(prop_file), "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", "houdini.rc") - if not os.path.isfile(init_path): - os.makedirs(os.path.dirname(init_path), exist_ok=True) - f = open(init_path, "x") - 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) - - print("==> libhoudini translation installed ! Restarting waydroid container to apply changes !") - restart() - -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" - # sys_overlay_dir = "/var/lib/waydroid/overlay_rw/system" - sys_overlay_dir = "/var/lib/waydroid/overlay" - merge_dir = "/var/lib/waydroid/rootfs" - magisk_dir = os.path.join(sys_overlay_dir, "system", "etc", "init", "magisk") - sys_overlay_rw = "/var/lib/waydroid/overlay_rw" - - machine = host() - init_rc_component = """ -on post-fs-data - start logd - exec u:r:su:s0 root root -- /system/etc/init/magisk/magisk{arch} --auto-selinux --setup-sbin /system/etc/init/magisk - exec u:r:su:s0 root root -- /system/etc/init/magisk/magiskpolicy --live --magisk "allow * magisk_file lnk_file *" - mkdir /sbin/.magisk 700 - mkdir /sbin/.magisk/mirror 700 - mkdir /sbin/.magisk/block 700 - copy /system/etc/init/magisk/config /sbin/.magisk/config - rm /dev/.magisk_unblock - start 7zKkuZ1ZhD - wait /dev/.magisk_unblock 40 - rm /dev/.magisk_unblock - -service 7zKkuZ1ZhD /sbin/magisk --auto-selinux --post-fs-data - user root - seclabel u:r:su:s0 - oneshot - -service wHgGlkRCtMoIQw /sbin/magisk --auto-selinux --service - class late_start - user root - seclabel u:r:su:s0 - oneshot - -on property:sys.boot_completed=1 - mkdir /data/adb/magisk 755 - exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --boot-complete - exec -- /system/bin/sh -c "if [ ! -e /data/data/io.github.huskydg.magisk ] ; then pm install /system/etc/init/magisk/magisk.apk ; fi" - -on property:init.svc.zygote=restarting - exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --zygote-restart - -on property:init.svc.zygote=stopped - exec u:r:su:s0 root root -- /sbin/magisk --auto-selinux --zygote-restart - """.format(arch=machine[1]) - - if not DBusContainerService().GetSession(): - print("Please make sure waydroid container is running!") - sys.exit(1) - - # Clear overlay_rw - print("==> Deleting residual files...") - old_bootanim_rc = os.path.join(sys_overlay_rw, "system","system", "etc", "init", "bootanim.rc") - old_bootanim_rc_gz = os.path.join(sys_overlay_rw, "system","system", "etc", "init", "bootanim.rc.gz") - old_magisk = os.path.join(sys_overlay_rw, "system","system", "etc", "init", "magisk") - - if os.path.exists(old_bootanim_rc): - os.remove(old_bootanim_rc) - if os.path.exists(old_bootanim_rc_gz): - os.remove(old_bootanim_rc_gz) - if os.path.exists(old_magisk): - if os.path.isdir(old_magisk): - shutil.rmtree(old_magisk) - else: - os.remove(old_magisk) - - # Download magisk - if os.path.isfile(dl_file_name): - os.remove(dl_file_name) - print("==> Downloading latest Magisk-Delta now .....") - 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(magisk_dir): - os.makedirs(magisk_dir, exist_ok=True) - - if not os.path.exists(os.path.join(sys_overlay_dir, "sbin")): - os.makedirs(os.path.join(sys_overlay_dir, "sbin"), exist_ok=True) - - # Now setup and install magisk binary and app - print("==> Installing magisk now ...") - - lib_dir = os.path.join(extract_to, "lib", machine[0]) - 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(magisk_dir, filename.group(1)) - shutil.copyfile(o_path, n_path) - run(["chmod", "+x", n_path]) - shutil.copyfile(dl_file_name, os.path.join(magisk_dir,"magisk.apk") ) - - # Updating Magisk from Magisk manager will modify bootanim.rc, - # So it is necessary to backup the original bootanim.rc. - print("==> Adding entry to bootanim.rc") - - bootanim = os.path.join(sys_overlay_dir, "system", "etc", "init", "bootanim.rc") - original_bootanim = os.path.join(merge_dir, "system", "etc", "init", "bootanim.rc") - - if not os.path.isfile(bootanim): - os.makedirs(os.path.dirname(bootanim), exist_ok=True) - gz_filename = bootanim+".gz" - with open(original_bootanim,'rb') as f_ungz: - with gzip.open(gz_filename,'wb') as f_gz: - f_gz.writelines(f_ungz) - with open(original_bootanim, "r") as initfile: - initcontent = initfile.read() - if init_rc_component not in initcontent: - initcontent=initcontent+init_rc_component - with open(bootanim, "w") as initfile: - initfile.write(initcontent) - - print("==> Magisk was installed ! Restarting waydroid container to apply changes !") - restart() - -def install_widevine(): - vendor_image_mount = "/var/lib/waydroid/overlay/vendor" - widevine_zip_url = "https://codeload.github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/zip/94c9ee172e3d78fecc81863f50a59e3646f7a2bd" - dl_file_name = os.path.join(download_loc, "widevine.zip") - extract_to = "/tmp/widevineunpack" #All catalog files will be marked as executable! - act_md5 = "a31f325453c5d239c21ecab8cfdbd878" - 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() - - # 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...") - run(["chmod", "+x", extract_to, "-R"]) - - # Copy library file - print("==> Copying library files ...") - shutil.copytree(os.path.join(extract_to, "vendor_google_proprietary_widevine-prebuilt-94c9ee172e3d78fecc81863f50a59e3646f7a2bd", - "prebuilts"), vendor_image_mount, dirs_exist_ok=True) - - print("==> Widevine installed ! Restarting waydroid container to apply changes !") - restart() - -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 ! - """ - check_root() - 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: - install_gapps() - elif args.installndk: - 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__": - main() \ No newline at end of file