Compare commits

..
Author SHA1 Message Date
JonasAlv 22f03a94c4 Merge branch 'casualsnek:main' into main 2026-08-22 15:24:54 -03:00
ayasa520 d5289cfd89 Update libhoudini (#256)
* Update download link for Houdini version 13
2026-01-05 09:56:03 +01:00
Jonas Alves 1690a5fcd5 fix errors- manual patching 2025-12-19 18:51:05 -03:00
NullBite ddaa6b190f Add Nix flake and improve derivation
This adds a Nix flake to the repo as well as updates the derivation so
that it includes `lzip` as a dependency
2025-11-17 10:08:53 +01:00
Gerry Bagaskoro Putro 15020ec20a fix(nodataperm): prevent crash when uninstalling on Android 13 2025-11-11 19:37:38 +01:00
Alessandro Astone fcb15624db Fix A13 widevine
Closes: https://github.com/casualsnek/waydroid_script/issues/236
2025-08-31 22:56:59 +02:00
Alessandro Astone db43c7c9cf main: Default to A13
Following Waydroid which now defaults to A13
2025-08-18 12:41:31 +02:00
Mio 3e344b360f fix https://github.com/casualsnek/waydroid_script/issues/229 2025-07-13 09:11:10 +02:00
金雄镕 5527d390eb Reorder ro.product.cpu.abilist to prioritize 64-bit ABIs 2025-07-11 19:43:32 +02:00
MasterKia 6f44d95070 Fix microg installation guide
The previous command returns an error ("ModuleNotFoundError: No module named 'InquirerPy'") even after installing the InquirerPy module using pip.
2025-07-04 10:43:21 +02:00
Alessandro Astone 32d21c8074 Change ndk_translation for A13 2025-05-30 18:36:04 +02:00
Alessandro Astone eb337a1351 Change houdini for A13
Even though this is extracted from an Android 14 image, it works better
including on AMD CPUs

Closes: #224
2025-05-21 21:40:38 +02:00
Alessandro Astone 48186df8af A13 ndk_translation 2025-05-20 00:02:29 +02:00
Alessandro Astone c14650010e A13 houdini 2025-05-20 00:02:29 +02:00
14 changed files with 257 additions and 153 deletions
+1 -1
View File
@@ -166,7 +166,7 @@ chmod 777 -R /mnt/*/*/*/*/Android/obb
![](assets/7.png) ![](assets/7.png)
``` ```
sudo python main.py install microg sudo venv/bin/python3 main.py install microg
``` ```
## Hide Status Bar ## Hide Status Bar
+4 -22
View File
@@ -1,22 +1,4 @@
with (import <nixpkgs> {}); let
pkgs = import <nixpkgs> {};
stdenv.mkDerivation { in
name = "waydroid_script"; pkgs.callPackage ./package.nix { }
buildInputs = [
(python3.withPackages(ps: with ps; [ tqdm requests inquirerpy ]))
];
src = ./.;
postPatch = ''
patchShebangs main.py
'';
installPhase = ''
mkdir -p $out/libexec
cp -r . $out/libexec/waydroid_script
mkdir -p $out/bin
ln -s $out/libexec/waydroid_script/main.py $out/bin/waydroid_script
'';
}
Generated
+41
View File
@@ -0,0 +1,41 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1707650010,
"narHash": "sha256-dOhphIA4MGrH4ElNCy/OlwmN24MsnEqFjRR6+RY7jZw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "809cca784b9f72a5ad4b991e0e7bcf8890f9c3a6",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"systems": "systems"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+21
View File
@@ -0,0 +1,21 @@
{
description = "Waydroid Extras Script";
inputs = {
systems.url = "github:nix-systems/default";
};
outputs = { self, nixpkgs, systems }:
let
inherit (nixpkgs) lib;
eachSystem = lib.genAttrs (import systems);
mkApp = program: { type = "app"; inherit program; };
in {
packages = eachSystem (system: rec {
waydroid_script = nixpkgs.legacyPackages."${system}".callPackage ./package.nix { };
default = waydroid_script;
});
apps = eachSystem (system: rec {
waydroid_script = mkApp "${self.outputs.packages.${system}.waydroid_script}/bin/waydroid_script";
default = waydroid_script;
});
};
}
+55 -25
View File
@@ -21,29 +21,45 @@ from stuff.fdroidpriv import FDroidPriv
import tools.helper as helper import tools.helper as helper
from tools import container from tools import container
from tools import images from tools import images
import argparse
from tools.logger import Logger from tools.logger import Logger
def get_certified():
def get_certified(args):
AndroidId().get_id() AndroidId().get_id()
def mount(partition, copy_dir): def mount(partition, copy_dir):
img = os.path.join(images.get_image_dir(), f"{partition}.img") img = os.path.join(images.get_image_dir(), partition+".img")
mount_point = os.path.join(copy_dir) if partition == "system" else os.path.join(copy_dir, partition) mount_point = ""
Logger.info(f"Mounting {img} to {mount_point}") if partition == "system":
mount_point = os.path.join(copy_dir)
else:
mount_point = os.path.join(copy_dir, partition)
Logger.info("Mounting {} to {}".format(img, mount_point))
images.mount(img, mount_point) images.mount(img, mount_point)
def resize(partition): def resize(partition):
img = os.path.join(images.get_image_dir(), f"{partition}.img") img = os.path.join(images.get_image_dir(), partition+".img")
img_size = int(os.path.getsize(img) / (1024 * 1024)) img_size = int(os.path.getsize(img)/(1024*1024))
new_size = f"{img_size + 500}M" new_size = "{}M".format(img_size+500)
Logger.info(f"Resizing {img} to {new_size}") Logger.info("Resizing {} to {}".format(img, new_size))
images.resize(img, new_size) images.resize(img, new_size)
def umount(partition, copy_dir): def umount(partition, copy_dir):
mount_point = os.path.join(copy_dir) if partition == "system" else os.path.join(copy_dir, partition) mount_point = ""
Logger.info(f"Unmounting {mount_point}") if partition == "system":
mount_point = os.path.join(copy_dir)
else:
mount_point = os.path.join(copy_dir, partition)
Logger.info("Umounting {}".format(mount_point))
images.umount(mount_point) images.umount(mount_point)
def install_app(args): def install_app(args):
install_list: List[General] = [] install_list: List[General] = []
app = args.app app = args.app
@@ -102,6 +118,7 @@ def install_app(args):
container.upgrade() container.upgrade()
def remove_app(args): def remove_app(args):
remove_list: List[General] = [] remove_list: List[General] = []
app = args.app app = args.app
@@ -141,8 +158,10 @@ def remove_app(args):
container.upgrade() container.upgrade()
def hack_option(args): def hack_option(args):
Logger.warning("If these hacks cause any problems, run `sudo python main.py remove <hack_option>` to remove") Logger.warning(
"If these hacks cause any problems, run `sudo python main.py remove <hack_option>` to remove")
hack_list: List[General] = [] hack_list: List[General] = []
options = args.option_name options = args.option_name
@@ -179,8 +198,10 @@ def hack_option(args):
container.upgrade() container.upgrade()
def interact(): def interact():
os.system("clear") os.system("clear")
args = argparse.Namespace()
android_version = inquirer.select( android_version = inquirer.select(
message="Select Android version", message="Select Android version",
instruction="(\u2191\u2193 Select Item)", instruction="(\u2191\u2193 Select Item)",
@@ -189,26 +210,28 @@ def interact():
Choice(name="Android 13", value="13"), Choice(name="Android 13", value="13"),
Choice(name="Exit", value=None) Choice(name="Exit", value=None)
], ],
default="11", default="13",
).execute() ).execute()
if not android_version: if not android_version:
exit() exit()
args.android_version = android_version
args = argparse.Namespace(android_version=android_version, microg_variant="Standard")
action = inquirer.select( action = inquirer.select(
message="Please select an action", message="Please select an action",
choices=["Install", "Remove", "Hack", "Get Google Device ID to Get Certified"], choices=[
"Install",
"Remove",
"Hack",
"Get Google Device ID to Get Certified"
],
instruction="([↑↓]: Select Item)", instruction="([↑↓]: Select Item)",
default=None, default=None,
).execute() ).execute()
if not action: if not action:
exit() exit()
install_choices = ["gapps", "microg", "libndk", "magisk", "smartdock", "fdroidpriv",] install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "smartdock", "fdroidpriv", "widevine",]
hack_choices = [] hack_choices = []
if android_version == "11": if android_version=="11":
install_choices.extend(["libhoudini", "widevine"])
hack_choices.extend(["nodataperm", "hidestatusbar"]) hack_choices.extend(["nodataperm", "hidestatusbar"])
if action == "Install": if action == "Install":
@@ -219,7 +242,8 @@ def interact():
invalid_message="should be at least 1 selection", invalid_message="should be at least 1 selection",
choices=install_choices choices=install_choices
).execute() ).execute()
microg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"] microg_variants = ["Standard", "NoGoolag",
"UNLP", "Minimal", "MinimalIAP"]
if "microg" in apps: if "microg" in apps:
microg_variant = inquirer.select( microg_variant = inquirer.select(
message="Select MicroG variant", message="Select MicroG variant",
@@ -238,7 +262,7 @@ def interact():
choices=[*install_choices, *hack_choices] choices=[*install_choices, *hack_choices]
).execute() ).execute()
args.app = apps args.app = apps
args.microg_variant = "Standard" args.microg_variant="Standard"
remove_app(args) remove_app(args)
elif action == "Hack": elif action == "Hack":
apps = inquirer.checkbox( apps = inquirer.checkbox(
@@ -251,18 +275,19 @@ def interact():
args.option_name = apps args.option_name = apps
hack_option(args) hack_option(args)
elif action == "Get Google Device ID to Get Certified": elif action == "Get Google Device ID to Get Certified":
get_certified() AndroidId().get_id()
def main(): def main():
parser = argparse.ArgumentParser(description=''' parser = argparse.ArgumentParser(description='''
Does stuff like installing Gapps, installing Magisk, installing NDK Translation and getting Android ID for device registration. Does stuff like installing Gapps, installing Magisk, installing NDK Translation and getting Android ID for device registration.
Use -h flag for help!''') Use -h flag for help!''')
subparsers = parser.add_subparsers(title="command", dest='command') subparsers = parser.add_subparsers(title="coomand", dest='command')
parser.add_argument('-a', '--android-version', parser.add_argument('-a', '--android-version',
dest='android_version', dest='android_version',
help='Specify the Android version', help='Specify the Android version',
default="11", default="13",
choices=["11", "13"]) choices=["11", "13"])
# android command # android command
@@ -270,7 +295,8 @@ def main():
'certified', help='Get device ID to obtain Play Store certification') 'certified', help='Get device ID to obtain Play Store certification')
certified.set_defaults(func=get_certified) certified.set_defaults(func=get_certified)
install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "mitm", "smartdock", "widevine"] install_choices = ["gapps", "microg", "libndk", "libhoudini",
"magisk", "mitm", "smartdock", "widevine"]
hack_choices = ["nodataperm", "hidestatusbar"] hack_choices = ["nodataperm", "hidestatusbar"]
micrg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"] micrg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"]
remove_choices = install_choices remove_choices = install_choices
@@ -279,6 +305,7 @@ def main():
"dest": "app", "dest": "app",
"type": str, "type": str,
"nargs": '+', "nargs": '+',
# "metavar":"",
} }
install_help = """ install_help = """
@@ -316,12 +343,15 @@ widevine: Add support for widevine DRM L3
hack_parser.set_defaults(func=hack_option) hack_parser.set_defaults(func=hack_option)
args = parser.parse_args() args = parser.parse_args()
args.microg_variant = "Standard"
if hasattr(args, 'func'): if hasattr(args, 'func'):
args_dict = vars(args)
helper.check_root() helper.check_root()
args.func(args) args.func(args)
else: else:
helper.check_root() helper.check_root()
interact() interact()
if __name__ == "__main__": if __name__ == "__main__":
main() main()
+32
View File
@@ -0,0 +1,32 @@
{ lib,
stdenvNoCC,
lzip,
python3,
makeWrapper }:
let
wrappedPath = lib.makeBinPath [ lzip ];
in stdenvNoCC.mkDerivation {
name = "waydroid_script";
buildInputs = [
(python3.withPackages(ps: with ps; [ tqdm requests inquirerpy ]))
];
nativeBuildInputs = [
makeWrapper
];
src = ./.;
postPatch = ''
patchShebangs main.py
'';
installPhase = ''
mkdir -p $out/libexec
cp -r . $out/libexec/waydroid_script
mkdir -p $out/bin
makeShellWrapper $out/libexec/waydroid_script/main.py $out/bin/waydroid_script \
--prefix PATH : "${wrappedPath}"
'';
}
+2
View File
@@ -6,6 +6,8 @@ from stuff.general import General
class FDroidPriv(General): class FDroidPriv(General):
id = "fdroid priv" id = "fdroid priv"
dl_links = {"11": ["https://f-droid.org/repo/org.fdroid.fdroid.privileged.ota_2130.zip", dl_links = {"11": ["https://f-droid.org/repo/org.fdroid.fdroid.privileged.ota_2130.zip",
"6242cab56d197d80c598593a46da62e4"],
"13": ["https://f-droid.org/repo/org.fdroid.fdroid.privileged.ota_2130.zip",
"6242cab56d197d80c598593a46da62e4"]} "6242cab56d197d80c598593a46da62e4"]}
partition = "system" partition = "system"
dl_file_name = "org.fdroid.fdroid.privileged.ota_2130.zip" dl_file_name = "org.fdroid.fdroid.privileged.ota_2130.zip"
+1 -1
View File
@@ -10,7 +10,7 @@ class Houdini(General):
partition = "system" partition = "system"
dl_links = { dl_links = {
"11": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/81f2a51ef539a35aead396ab7fce2adf89f46e88.zip", "fbff756612b4144797fbc99eadcb6653"], "11": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/81f2a51ef539a35aead396ab7fce2adf89f46e88.zip", "fbff756612b4144797fbc99eadcb6653"],
# "13": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/978d8cba061a08837b7e520cd03b635af643ba08.zip", "1e139054c05034648fae58a1810573b4"] "13": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/9e77896350caccd228b36b2e1b4a994aa4bd48da.zip", "3807fe029559db3037efe245d9e74270"]
} }
act_md5 = ... act_md5 = ...
dl_link = ... dl_link = ...
+2 -2
View File
@@ -9,12 +9,12 @@ class Ndk(General):
partition = "system" partition = "system"
dl_links = { dl_links = {
"11": ["https://github.com/supremegamers/vendor_google_proprietary_ndk_translation-prebuilt/archive/9324a8914b649b885dad6f2bfd14a67e5d1520bf.zip", "c9572672d1045594448068079b34c350"], "11": ["https://github.com/supremegamers/vendor_google_proprietary_ndk_translation-prebuilt/archive/9324a8914b649b885dad6f2bfd14a67e5d1520bf.zip", "c9572672d1045594448068079b34c350"],
"13": ["https://github.com/supremegamers/vendor_google_proprietary_ndk_translation-prebuilt/archive/a090003c60df53a9eadb2df09bd4fd2fa86ea629.zip", "e6f0d9fc28ebc427b59a3942a9a4ffc0"] "13": ["https://github.com/supremegamers/vendor_google_proprietary_ndk_translation-prebuilt/archive/68734c52556d3d7a6db34c603dd9276915c29f2f.zip", "0b2207c490fcb400aa5c87fcf0d52d38"]
} }
dl_file_name = "libndktranslation.zip" dl_file_name = "libndktranslation.zip"
extract_to = "/tmp/libndkunpack" extract_to = "/tmp/libndkunpack"
apply_props = { apply_props = {
"ro.product.cpu.abilist": "x86_64,x86,armeabi-v7a,armeabi,arm64-v8a", "ro.product.cpu.abilist": "x86_64,x86,arm64-v8a,armeabi-v7a,armeabi",
"ro.product.cpu.abilist32": "x86,armeabi-v7a,armeabi", "ro.product.cpu.abilist32": "x86,armeabi-v7a,armeabi",
"ro.product.cpu.abilist64": "x86_64,arm64-v8a", "ro.product.cpu.abilist64": "x86_64,arm64-v8a",
"ro.dalvik.vm.native.bridge": "libndk_translation.so", "ro.dalvik.vm.native.bridge": "libndk_translation.so",
+14 -6
View File
@@ -10,19 +10,23 @@ from tools import container
class Nodataperm(General): class Nodataperm(General):
id = "nodataperm" id = "nodataperm"
dl_links = { dl_links = {
"11": "11": {
{ "x86_64": [
"https://github.com/ayasa520/hack_full_data_permission/archive/d4beab7780eb792059d33e77d865579c9ee41546.zip",
"b0e3908ffcf5df8ea62f4929aa680f1a"
],
},
"13": {
"x86_64": [ "x86_64": [
"https://github.com/ayasa520/hack_full_data_permission/archive/d4beab7780eb792059d33e77d865579c9ee41546.zip", "https://github.com/ayasa520/hack_full_data_permission/archive/d4beab7780eb792059d33e77d865579c9ee41546.zip",
"b0e3908ffcf5df8ea62f4929aa680f1a" "b0e3908ffcf5df8ea62f4929aa680f1a"
], ],
}, },
"13": {}
} }
dl_file_name = "nodataperm.zip" dl_file_name = "nodataperm.zip"
extract_to = "/tmp/nodataperm" extract_to = "/tmp/nodataperm"
dl_link = ... dl_link = None
act_md5 = ... act_md5 = None
partition = "system" partition = "system"
files = [ files = [
"etc/nodataperm.sh", "etc/nodataperm.sh",
@@ -36,11 +40,15 @@ class Nodataperm(General):
super().__init__() super().__init__()
print("ok") print("ok")
arch = self.arch[0] arch = self.arch[0]
if android_version not in self.dl_links:
raise KeyError(f"No download links for Android version '{android_version}'")
if arch not in self.dl_links[android_version]:
raise KeyError(f"No download links for architecture '{arch}' in Android version '{android_version}'")
self.dl_link = self.dl_links[android_version][arch][0] self.dl_link = self.dl_links[android_version][arch][0]
self.act_md5 = self.dl_links[android_version][arch][1] self.act_md5 = self.dl_links[android_version][arch][1]
def copy(self): def copy(self):
name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0] name = re.findall(r"([a-zA-Z0-9]+)\.zip", self.dl_link)[0]
extract_path = os.path.join( extract_path = os.path.join(
self.extract_to, f"hack_full_data_permission-{name}") self.extract_to, f"hack_full_data_permission-{name}")
if not container.use_overlayfs(): if not container.use_overlayfs():
+13 -2
View File
@@ -13,8 +13,8 @@ class Widevine(General):
"x86_64": { "x86_64": {
"11": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/48d1076a570837be6cdce8252d5d143363e37cc1.zip", "11": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/48d1076a570837be6cdce8252d5d143363e37cc1.zip",
"f587b8859f9071da4bca6cea1b9bed6a"], "f587b8859f9071da4bca6cea1b9bed6a"],
"13": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/a8524d608431573ef1c9313822d271f78728f9a6.zip", "13": ["https://github.com/WayDroid-ATV/vendor_google_proprietary_widevine-prebuilt/archive/679552343d8b2e8d7a19b6df61c7a03963d0c75b.zip",
"5c55df61da5c012b4e43746547ab730f"] "80ab79ea85c7b2556baedb371a54e01c"]
}, },
# "armeabi-v7a": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/a1a19361d36311bee042da8cf4ced798d2c76d98.zip", "fed6898b5cfd2a908cb134df97802554"], # "armeabi-v7a": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/a1a19361d36311bee042da8cf4ced798d2c76d98.zip", "fed6898b5cfd2a908cb134df97802554"],
"arm64-v8a": { "arm64-v8a": {
@@ -30,7 +30,10 @@ class Widevine(General):
"etc/init/*widevine.rc", "etc/init/*widevine.rc",
"etc/vintf/manifest/*widevine.xml", "etc/vintf/manifest/*widevine.xml",
"lib/libwvhidl.so", "lib/libwvhidl.so",
"lib/libwvaidl.so",
"lib/mediadrm", "lib/mediadrm",
"lib64/libwvhidl.so",
"lib64/libwvaidl.so",
"lib64/mediadrm" "lib64/mediadrm"
] ]
@@ -38,9 +41,17 @@ class Widevine(General):
super().__init__() super().__init__()
self.dl_link = self.dl_links[self.arch[0]][android_version][0] self.dl_link = self.dl_links[self.arch[0]][android_version][0]
self.act_md5 = self.dl_links[self.arch[0]][android_version][1] self.act_md5 = self.dl_links[self.arch[0]][android_version][1]
self.android_version = android_version
self.libdir = "lib64" if self.arch[1] == 64 else "lib"
def copy(self): def copy(self):
name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0] name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0]
Logger.info("Copying widevine library files ...") Logger.info("Copying widevine library files ...")
shutil.copytree(os.path.join(self.extract_to, "vendor_google_proprietary_widevine-prebuilt-"+name, shutil.copytree(os.path.join(self.extract_to, "vendor_google_proprietary_widevine-prebuilt-"+name,
"prebuilts"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True) "prebuilts"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True)
if self.android_version == "13":
try:
os.symlink("libprotobuf-cpp-lite-3.9.1.so",
os.path.join(self.copy_dir, self.partition, self.libdir, "libprotobuf-cpp-lite.so"))
except FileExistsError:
pass
+4 -24
View File
@@ -1,23 +1,9 @@
import configparser import configparser
import os import os
import sys import sys
# import dbus
from tools.helper import run from tools.helper import run
from tools.logger import Logger 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(): def use_overlayfs():
cfg = configparser.ConfigParser() cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg") cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
@@ -34,20 +20,14 @@ def use_overlayfs():
return False return False
# def get_session():
# return DBusContainerService().GetSession()
def stop(): def stop():
# if use_dbus():
# session = DBusContainerService().GetSession()
# if session:
# DBusContainerService().Stop(False)
# else:
run(["waydroid", "container", "stop"]) run(["waydroid", "container", "stop"])
def is_running(): def is_running():
return "Session:\tRUNNING" in run(["waydroid", "status"]).stdout.decode() return "Session:\tRUNNING" in run(["waydroid", "status"]).stdout.decode()
def upgrade(): 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...")
+65 -67
View File
@@ -2,7 +2,6 @@ import gzip
import os import os
import re import re
import platform import platform
import re
import subprocess import subprocess
import sys import sys
import requests import requests
@@ -11,27 +10,24 @@ from tqdm import tqdm
import hashlib import hashlib
from typing import Optional from typing import Optional
def get_download_dir(): def get_download_dir():
download_loc = "" if os.environ.get("XDG_CACHE_HOME"):
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( download_loc = os.path.join(
os.environ["XDG_CACHE_HOME"], "waydroid-script", "downloads" 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): if not os.path.exists(download_loc):
os.makedirs(download_loc) os.makedirs(download_loc, exist_ok=True)
return download_loc return download_loc
# not good
def get_data_dir(): 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[dict] = None, ignore: Optional[str] = None):
def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
result = subprocess.run( result = subprocess.run(
args=args, args=args,
env=env, env=env,
@@ -39,11 +35,12 @@ def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
stderr=subprocess.PIPE stderr=subprocess.PIPE
) )
# print(result.stdout.decode())
if result.stderr: if result.stderr:
error = result.stderr.decode("utf-8") error = result.stderr.decode("utf-8").strip()
if ignore and re.match(ignore, error):
if (ignore and re.search(ignore, error)) or "system_ota" in error:
return result return result
Logger.error(error) Logger.error(error)
raise subprocess.CalledProcessError( raise subprocess.CalledProcessError(
returncode=result.returncode, returncode=result.returncode,
@@ -52,64 +49,58 @@ def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
) )
return result return result
# execute on waydroid shell
def shell(arg: str, env: Optional[str] = None): def shell(arg: str, env: Optional[str] = None):
a = subprocess.Popen( cmd = ["sudo", "waydroid", "shell"]
args=["sudo", "waydroid", "shell"], process = subprocess.Popen(
args=cmd,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=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: if env:
subprocess.Popen( full_script += f"{env}\n"
args=["echo", env], full_script += f"{arg}\n"
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
subprocess.Popen( stdout, stderr = process.communicate(input=full_script)
args=["echo", arg],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
a.stdin.close() if process.returncode != 0 and stderr:
if a.stderr.read(): Logger.error(stderr.strip())
Logger.error(a.stderr.read().decode('utf-8'))
raise subprocess.CalledProcessError( raise subprocess.CalledProcessError(
returncode=a.returncode, returncode=process.returncode,
cmd=a.args, cmd=cmd,
stderr=a.stderr stderr=stderr.encode()
) )
return a.stdout.read().decode("utf-8") return stdout
def download_file(url, f_name): def download_file(url, f_name):
md5 = ""
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
total_size_in_bytes = int(response.headers.get('content-length', 0)) 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) progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True)
with open(f_name, 'wb') as file: with open(f_name, 'wb') as file:
for data in response.iter_content(block_size): for data in response.iter_content(block_size):
progress_bar.update(len(data)) progress_bar.update(len(data))
file.write(data) file.write(data)
progress_bar.close() progress_bar.close()
hash_md5 = hashlib.md5()
with open(f_name, "rb") as f: with open(f_name, "rb") as f:
bytes = f.read() for chunk in iter(lambda: f.read(4096), b""):
md5 = hashlib.md5(bytes).hexdigest() hash_md5.update(chunk)
if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes: if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes:
raise ValueError("Something went wrong while downloading") raise ValueError("Download incomplete or corrupted")
return md5
return hash_md5.hexdigest()
def host(): def host():
machine = platform.machine() machine = platform.machine()
mapping = { mapping = {
"i686": ("x86", 32), "i686": ("x86", 32),
"x86_64": ("x86_64", 64), "x86_64": ("x86_64", 64),
@@ -117,30 +108,37 @@ def host():
"armv7l": ("armeabi-v7a", 32), "armv7l": ("armeabi-v7a", 32),
"armv8l": ("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")
if machine in mapping:
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(f"Architecture '{machine}' is not supported")
def check_root(): def check_root():
if os.geteuid() != 0: 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) sys.exit(1)
def backup(path): def backup(path):
gz_filename = path+".gz" if not os.path.exists(path):
with gzip.open(gz_filename, 'wb') as f_gz: return
with open(path, "rb") as f: gz_filename = path + ".gz"
f_gz.write(f.read()) with open(path, "rb") as f_in:
with gzip.open(gz_filename, "wb") as f_out:
f_out.writelines(f_in)
def restore(path): def restore(path):
gz_filename = path+".gz" gz_filename = path + ".gz"
with gzip.GzipFile(gz_filename) as f_gz: if not os.path.exists(gz_filename):
with open(path, "wb") as f: return
f.writelines(f_gz) with gzip.open(gz_filename, "rb") as f_in:
with open(path, "wb") as f_out:
f_out.write(f_in.read())
+1 -2
View File
@@ -28,7 +28,6 @@ def resize(img_file, size):
run(["sudo", "resize2fs", img_file, size], ignore="^resize2fs \d+\.\d+\.\d (.+)\n$") run(["sudo", "resize2fs", img_file, size], ignore="^resize2fs \d+\.\d+\.\d (.+)\n$")
def get_image_dir(): def get_image_dir():
# Read waydroid config to get image location
cfg = configparser.ConfigParser() cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg") cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
if not os.path.isfile(cfg_file): if not os.path.isfile(cfg_file):
@@ -36,6 +35,6 @@ def get_image_dir():
sys.exit(1) sys.exit(1)
cfg.read(cfg_file) cfg.read(cfg_file)
if "waydroid" not in cfg: 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) sys.exit(1)
return cfg["waydroid"]["images_path"] return cfg["waydroid"]["images_path"]