Compare commits

..
Author SHA1 Message Date
Bruno Cabral 51698d9c48 add vending-common to non_apks list
This solves issue #30
2022-04-14 10:00:20 -07:00
43 changed files with 641 additions and 2232 deletions
-111
View File
@@ -1,111 +0,0 @@
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
.vscode
# 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/
# nix
result*
test.py
+46 -173
View File
@@ -1,205 +1,78 @@
# Waydroid Extras Script
Script to add GApps and other stuff to Waydroid!
[![Visits Badge](https://badges.pufler.dev/visits/casualsnek/waydroid_script)](https://github.com/casualsnek)
Script to add gapps and other stuff to waydroid !
# Installation/Usage
## Interactive terminal interface
```
git clone https://github.com/casualsnek/waydroid_script
cd waydroid_script
python3 -m venv venv
venv/bin/pip install -r requirements.txt
sudo venv/bin/python3 main.py
```
![image-20230430013103883](assets/img/README/image-20230430013103883.png)
![image-20230430013119763](assets/img/README/image-20230430013119763.png)
![image-20230430013148814](assets/img/README/image-20230430013148814.png)
## Command Line
```bash
git clone https://github.com/casualsnek/waydroid_script
cd waydroid_script
python3 -m venv venv
venv/bin/pip install -r requirements.txt
# install something
sudo venv/bin/python3 main.py install {gapps, magisk, libndk, libhoudini, nodataperm, smartdock, microg, mitm}
# uninstall something
sudo venv/bin/python3 main.py uninstall {gapps, magisk, libndk, libhoudini, nodataperm, smartdock, microg}
# get Android device ID
sudo venv/bin/python3 main.py certified
# some hacks
sudo venv/bin/python3 main.py hack {nodataperm, hidestatusbar}
```
## Dependencies
"lzip" is required for this script to work, install it using your distribution's package manager:
### Arch, Manjaro and EndeavourOS based distributions:
sudo pacman -S lzip
### Debian and Ubuntu based distributions:
sudo apt install lzip
### RHEL, Fedora and Rocky based distributions:
sudo dnf install lzip
### openSUSE based distributions:
sudo zypper install lzip
"lzip" and "sqlite" is required for this script to work, install it using your distribution's package manager:
## Arch, Manjaro and EndeavourOS based distributions:
sudo pacman -S lzip sqlite
## Debian and Ubuntu based distributions:
sudo apt install lzip sqlite
## RHEL, Fedora and Rocky based distributions:
sudo dnf install lzip sqlite
## openSUSE based distributions:
sudo zypper install lzip sqlite
Then run:
git clone https://github.com/casualsnek/waydroid_script
cd waydroid_script
sudo python3 -m pip install -r requirements.txt
sudo python3 waydroid_extras.py [-i/-g/-n/-h]
## Install OpenGapps
![](assets/1.png)
Open terminal and switch to directory where "waydroid_extras.py" is located then run:
Open terminal and switch to the directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install gapps
sudo python3 waydroid_extras.py -g
Then restart waydroid service with command below :
sudo systemctl start waydroid-container.service
Then launch waydroid with:
waydroid show-full-ui
After waydroid has finished booting open terminal and switch to directory where "waydroid_extras.py" is located then run:
After waydroid has finished booting, open terminal and switch to directory where "main.py" is located then run:
sudo python3 main.py google
Copy the returned numeric ID, then open ["https://google.com/android/uncertified/?pli=1"](https://google.com/android/uncertified/?pli=1). Enter the ID and register it. Wait 10-20 minutes for device to get registered. Then clear Google Play Service's cache and try logging in!
sudo python3 waydroid_extras.py -i
Copy the returned numeric ID open ["https://google.com/android/uncertified/?pli=1"](https://google.com/android/uncertified/?pli=1) enter the id and register it, you may need to wait upto 10-20 minutes for device to get registered, then clear Google Play Service's cache and try logging in !
## Install Magisk
![](assets/2.png)
Open terminal and switch to directory where "waydroid_extras.py" is located then run:
Open terminal and switch to directory where "main.py" is located then run:
sudo python3 waydroid_extras.py -m
Then restart waydroid service with command below :
sudo venv/bin/python3 main.py install magisk
Magisk will be installed on next boot!
Zygisk and modules like LSPosed should work now.
If you want to update Magisk, Please use `Direct Install into system partition` or run this sript again.
This script only focuses on Magisk installation, if you need more management, please check https://github.com/nitanmarcel/waydroid-magisk
sudo systemctl start waydroid-container.service
Magisk will be installed on next boot !
Note That this is bootless installation and modules don't work as of now !
## Install libndk arm translation
libndk_translation from guybrush firmware.
This may or may not work properly and is only for testing:
Open terminal and switch to directory where "waydroid_extras.py" is located then run:
libndk seems to have better performance than libhoudini on AMD.
sudo python3 waydroid_extras.py -n
Then restart waydroid service with command below :
Open terminal and switch to directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install libndk
sudo systemctl start waydroid-container.service
## Install libhoudini arm translation
Intel's libhoudini for intel/AMD x86 CPU, pulled from Microsoft's WSA 11 image
houdini version: 11.0.1b_y.38765.m
houdini64 version: 11.0.1b_z.38765.m
Open terminal and switch to directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install libhoudini
## Integrate Widevine DRM (L3)
![](assets/3.png)
Open terminal and switch to directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install widevine
## Install Smart Dock
![](assets/4.png)
![](assets/5.png)
Open terminal and switch to directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install smartdock
## Install a self-signed CA certificate
Open terminal and switch to directory where "main.py" is located then run:
sudo venv/bin/python3 main.py install mitm --ca-cert mycert.pem
## Granting full permission for apps data (HACK)
This is a temporary hack to combat against the apps permission issue on Android 11. Whenever an app is open it will always enable a property (persist.sys.nodataperm) to make it execute a script to grant the data full permissions (777). The **correct** way is to use `sdcardfs` or `esdfs`, both need to recompile the kernel or WayDroid image.
Arknights, PUNISHING: GRAY RAVEN and other games won't freeze on the black screen.
![](assets/6.png)
Open terminal and switch to directory where "main.py" is located then run:
```
sudo venv/bin/python3 main.py hack nodataperm
```
**WARNING**: Tested on `lineage-18.1-20230128-VANILLA-waydroid_x86_64.img`. This script will replace `/system/framework/service.jar`, which may prevent WayDroid from booting. If so, run `sudo venv/bin/python3 main.py uninstall nodataperm` to remove it.
Or you can run the following commands directly in `sudo waydroid shell`. In this way, every time a new game is installed, you need to run it again, but it's much less risky.
```
chmod 777 -R /sdcard/Android
chmod 777 -R /data/media/0/Android
chmod 777 -R /sdcard/Android/data
chmod 777 -R /data/media/0/Android/obb
chmod 777 -R /mnt/*/*/*/*/Android/data
chmod 777 -R /mnt/*/*/*/*/Android/obb
```
- https://github.com/supremegamers/device_generic_common/commit/2d47891376c96011b2ee3c1ccef61cb48e15aed6
- https://github.com/supremegamers/android_frameworks_base/commit/24a08bf800b2e461356a9d67d04572bb10b0e819
## Install microG, Aurora Store and Aurora Droid
![](assets/7.png)
```
sudo venv/bin/python3 main.py install microg
```
## Hide Status Bar
Before
![Before](assets/8.png)
After
![After](assets/9.png)
```
sudo venv/bin/python3 main.py hack hidestatusbar
```
This may or may not work properly and is only for testing: ( Much stable than libndk ) and works on android 11 images
Open terminal and switch to directory where "waydroid_extras.py" is located then run:
sudo python3 waydroid_extras.py -l
Then restart waydroid service with command below :
sudo systemctl start waydroid-container.service
## Get Android ID for device registration
You need to register you device with its it before being able to use gapps, this will print out your Android ID which you can use for device registration required for Google apps:
Open terminal and switch to directory where "main.py" is located then run:
You need to register you device with its it before being able to use gapps, this will print out your Android ID which you can use for device registration required for google apps:
Open terminal and switch to directory where "waydroid_extras.py" is located then run:
sudo venv/bin/python3 main.py certified
sudo python3 waydroid_extras.py -i
Star this repository if you find this useful, if you encounter problem create an issue on GitHub!
## Error handling
- Magisk installed: N/A
Check [waydroid-magisk](https://github.com/nitanmarcel/waydroid-magisk)
## Credits
- [WayDroid](https://github.com/waydroid/waydroid)
- [Magisk Delta](https://huskydg.github.io/magisk-files/)
- [microG Project](https://microg.org)
- [Open GApps](https://opengapps.org)
- [Smart Dock](https://github.com/axel358/smartdock)
- [wd-scripts](https://github.com/electrikjesus/wd-scripts/)
Star this repository if you find this useful, if you encounter problem create a issue on github !
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
-4
View File
@@ -1,4 +0,0 @@
let
pkgs = import <nixpkgs> {};
in
pkgs.callPackage ./package.nix { }
Generated
-41
View File
@@ -1,41 +0,0 @@
{
"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
@@ -1,21 +0,0 @@
{
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;
});
};
}
-362
View File
@@ -1,362 +0,0 @@
#!/usr/bin/env python3
from InquirerPy import inquirer
from InquirerPy.base.control import Choice
from InquirerPy.separator import Separator
import argparse
import os
from typing import List
from stuff.android_id import AndroidId
from stuff.gapps import Gapps
from stuff.general import General
from stuff.hidestatusbar import HideStatusBar
from stuff.houdini import Houdini
from stuff.magisk import Magisk
from stuff.microg import MicroG
from stuff.mitm import Mitm
from stuff.ndk import Ndk
from stuff.nodataperm import Nodataperm
from stuff.smartdock import Smartdock
from stuff.widevine import Widevine
from stuff.fdroidpriv import FDroidPriv
from stuff.tflitefix import TfliteFix
import tools.helper as helper
from tools import container
from tools import images
import argparse
from tools.logger import Logger
def get_certified(args):
AndroidId().get_id()
def mount(partition, copy_dir):
img = os.path.join(images.get_image_dir(), partition+".img")
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)
def resize(partition):
img = os.path.join(images.get_image_dir(), 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(partition, copy_dir):
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)
def install_app(args):
install_list: List[General] = []
app = args.app
if "gapps" in app:
install_list.append(Gapps(args.android_version))
if "libndk" in app and "houdini" not in app:
arch = helper.host()[0]
if arch == "x86_64":
install_list.append(Ndk(args.android_version))
else:
Logger.warn("libndk is not supported on your CPU")
if "libhoudini" in app and "ndk" not in app:
arch = helper.host()[0]
if arch == "x86_64":
install_list.append(Houdini(args.android_version))
else:
Logger.warn("libhoudini is not supported on your CPU")
if "magisk" in app:
install_list.append(Magisk())
if "widevine" in app:
install_list.append(Widevine(args.android_version))
if "smartdock" in app:
install_list.append(Smartdock())
if "microg" in app:
install_list.append(MicroG(args.android_version, args.microg_variant))
if "mitm" in app:
install_list.append(Mitm(args.ca_cert_file))
if "fdroidpriv" in app:
install_list.append(FDroidPriv(args.android_version))
if not container.use_overlayfs():
copy_dir = "/tmp/waydroid"
container.stop()
resize_system, resize_vendor = False, False
for item in install_list:
if item.partition == "system":
resize_system = True
elif item.partition == "vendor":
resize_vendor = True
if resize_system:
resize("system")
if resize_vendor:
resize("vendor")
mount("system", copy_dir)
mount("vendor", copy_dir)
for item in install_list:
item.install()
if not container.use_overlayfs():
umount("vendor", copy_dir)
umount("system", copy_dir)
container.upgrade()
def remove_app(args):
remove_list: List[General] = []
app = args.app
if "gapps" in app:
remove_list.append(Gapps(args.android_version))
if "libndk" in app and "houdini" not in app:
remove_list.append(Ndk(args.android_version))
if "libhoudini" in app and "ndk" not in app:
remove_list.append(Houdini(args.android_version))
if "magisk" in app:
remove_list.append(Magisk())
if "widevine" in app:
remove_list.append(Widevine(args.android_version))
if "smartdock" in app:
remove_list.append(Smartdock())
if "microg" in app:
remove_list.append(MicroG(args.android_version, args.microg_variant))
if "mitm" in app:
remove_list.append(Mitm())
if "fdroidpriv" in app:
remove_list.append(FDroidPriv(args.android_version))
if "nodataperm" in app:
remove_list.append(Nodataperm(args.android_version))
if "hidestatusbar" in app:
remove_list.append(HideStatusBar())
if "tflitefix" in app:
remove_list.append(TfliteFix())
if not container.use_overlayfs():
copy_dir = "/tmp/waydroid"
container.stop()
for item in remove_list:
item.uninstall()
if not container.use_overlayfs():
umount("vendor", copy_dir)
umount("system", copy_dir)
container.upgrade()
def hack_option(args):
Logger.warning(
"If these hacks cause any problems, run `sudo python main.py remove <hack_option>` to remove")
hack_list: List[General] = []
options = args.option_name
if "nodataperm" in options:
hack_list.append(Nodataperm())
if "hidestatusbar" in options:
hack_list.append(HideStatusBar())
if "tflitefix" in options:
hack_list.append(TfliteFix())
if not container.use_overlayfs():
copy_dir = "/tmp/waydroid"
container.stop()
resize_system, resize_vendor = False, False
for item in hack_list:
if item.partition == "system":
resize_system = True
elif item.partition == "vendor":
resize_vendor = True
if resize_system:
resize("system")
if resize_vendor:
resize("vendor")
mount("system", copy_dir)
mount("vendor", copy_dir)
for item in hack_list:
item.install()
if not container.use_overlayfs():
umount("vendor", copy_dir)
umount("system", copy_dir)
container.upgrade()
def interact():
os.system("clear")
args = argparse.Namespace()
android_version = inquirer.select(
message="Select Android version",
instruction="(↑↓ Select Item)",
choices=[
Choice(name="Android 11", value="11"),
Choice(name="Android 13", value="13"),
Choice(name="Exit", value=None)
],
default="13",
).execute()
if not android_version:
exit()
args.android_version = android_version
action = inquirer.select(
message="Please select an action",
choices=[
"Install",
"Remove",
"Hack",
"Get Google Device ID to Get Certified"
],
instruction="([↑↓]: Select Item)",
default=None,
).execute()
if not action:
exit()
install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "smartdock", "fdroidpriv", "widevine",]
hack_choices = ["tflitefix"]
if android_version=="11":
hack_choices.extend(["nodataperm", "hidestatusbar"])
if action == "Install":
apps = inquirer.checkbox(
message="Select apps",
instruction="([\u2191\u2193]: Select Item. [Space]: Toggle Choice), [Enter]: Confirm",
validate=lambda result: len(result) >= 1,
invalid_message="should be at least 1 selection",
choices=install_choices
).execute()
microg_variants = ["Standard", "NoGoolag",
"UNLP", "Minimal", "MinimalIAP"]
if "microg" in apps:
microg_variant = inquirer.select(
message="Select MicroG variant",
choices=microg_variants,
default="Standard",
).execute()
args.microg_variant = microg_variant
args.app = apps
install_app(args)
elif action == "Remove":
apps = inquirer.checkbox(
message="Select apps",
instruction="([\u2191\u2193]: Select Item. [Space]: Toggle Choice), [Enter]: Confirm",
validate=lambda result: len(result) >= 1,
invalid_message="should be at least 1 selection",
choices=[*install_choices, *hack_choices]
).execute()
args.app = apps
args.microg_variant="Standard"
remove_app(args)
elif action == "Hack":
apps = inquirer.checkbox(
message="Select hack options",
instruction="([\u2191\u2193]: Select Item. [Space]: Toggle Choice), [Enter]: Confirm",
validate=lambda result: len(result) >= 1,
invalid_message="should be at least 1 selection",
choices=hack_choices
).execute()
args.option_name = apps
hack_option(args)
elif action == "Get Google Device ID to Get Certified":
AndroidId().get_id()
def main():
parser = argparse.ArgumentParser(description='''
Does stuff like installing Gapps, installing Magisk, installing NDK Translation and getting Android ID for device registration.
Use -h flag for help!''')
subparsers = parser.add_subparsers(title="coomand", dest='command')
parser.add_argument('-a', '--android-version',
dest='android_version',
help='Specify the Android version',
default="13",
choices=["11", "13"])
# android command
certified = subparsers.add_parser(
'certified', help='Get device ID to obtain Play Store certification')
certified.set_defaults(func=get_certified)
install_choices = ["gapps", "microg", "libndk", "libhoudini",
"magisk", "mitm", "smartdock", "widevine"]
hack_choices = ["nodataperm", "hidestatusbar", "tflitefix"]
micrg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"]
remove_choices = install_choices
arg_template = {
"dest": "app",
"type": str,
"nargs": '+',
# "metavar":"",
}
install_help = """
gapps: Install Open GApps (Android 11) or MindTheGapps (Android 13)
microg: Add microG, Aurora Store and Aurora Droid to WayDriod
libndk: Add libndk arm translation, better for AMD CPUs
libhoudini: Add libhoudini arm translation, better for Intel CPUs
magisk: Install Magisk Delta to WayDroid
mitm -c CA_CERT_FILE: Install root CA cert into system trust store
smartdock: A desktop mode launcher for Android
widevine: Add support for widevine DRM L3
"""
# install and its aliases
install_parser = subparsers.add_parser(
'install', formatter_class=argparse.RawTextHelpFormatter, help='Install an app')
install_parser.add_argument(
**arg_template, choices=install_choices, help=install_help)
install_parser.add_argument('-c', '--ca-cert',
dest='ca_cert_file',
help='[for mitm only] The CA certificate file (*.pem) to install',
default=None)
install_parser.set_defaults(func=install_app)
# remove and its aliases
remove_parser = subparsers.add_parser(
'remove', aliases=["uninstall"], help='Remove an app')
remove_parser.add_argument(
**arg_template, choices=[*remove_choices, * hack_choices], help='Name of app to remove')
remove_parser.set_defaults(func=remove_app)
# hack and its aliases
hack_parser = subparsers.add_parser('hack', help='Hack the system')
hack_parser.add_argument(
'option_name', nargs="+", choices=hack_choices, help='Name of hack option')
hack_parser.set_defaults(func=hack_option)
args = parser.parse_args()
args.microg_variant = "Standard"
if hasattr(args, 'func'):
args_dict = vars(args)
helper.check_root()
args.func(args)
else:
helper.check_root()
interact()
if __name__ == "__main__":
main()
-32
View File
@@ -1,32 +0,0 @@
{ 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}"
'';
}
-1
View File
@@ -1,3 +1,2 @@
tqdm
requests
InquirerPy
-21
View File
@@ -1,21 +0,0 @@
from tools import container
from tools.helper import shell
from tools.logger import Logger
class AndroidId:
def get_id(self):
if container.is_running():
try:
queryout = shell(
arg="sqlite3 /data/data/com.google.android.gsf/databases/gservices.db \"select * from main where name = 'android_id';\"",
env="ANDROID_RUNTIME_ROOT=/apex/com.android.runtime ANDROID_DATA=/data ANDROID_TZDATA_ROOT=/apex/com.android.tzdata ANDROID_I18N_ROOT=/apex/com.android.i18n"
)
except:
return
else:
Logger.error("Please make sure Waydroid is running and Gapps has been installed!")
return
print(queryout.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")
-42
View File
@@ -1,42 +0,0 @@
import os
import shutil
from stuff.general import General
class FDroidPriv(General):
id = "fdroid priv"
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"]}
partition = "system"
dl_file_name = "org.fdroid.fdroid.privileged.ota_2130.zip"
dl_link = ...
act_md5 = ...
extract_to = "/tmp/fdroid_ota_2130"
files = [
"app/F-Droid.apk"
"app/F-Droid/F-Droid.apk"
"etc/permissions/permissions_org.fdroid.fdroid.privileged.xml"
"priv-app/F-DroidPrivilegedExtension.apk"
"priv-app/F-DroidPrivilegedExtension/F-DroidPrivilegedExtension.apk"
]
file_map = {
"permissions_org.fdroid.fdroid.privileged.xml": "etc/permissions/permissions_org.fdroid.fdroid.privileged.xml",
"F-Droid.apk": "app/F-Droid/F-Droid.apk",
"F-DroidPrivilegedExtension.apk": "priv-app/F-DroidPrivilegedExtension/F-DroidPrivilegedExtension.apk",
}
def __init__(self, android_version="11") -> None:
super().__init__()
self.dl_link = self.dl_links[android_version][0]
self.act_md5 = self.dl_links[android_version][1]
def copy(self):
for f, d in self.file_map.items():
rro_file = os.path.join(
self.copy_dir, self.partition, d)
rro_dir = os.path.dirname(rro_file)
if not os.path.exists(rro_dir):
os.makedirs(rro_dir)
shutil.copyfile(os.path.join(self.extract_to, f), rro_file)
-172
View File
@@ -1,172 +0,0 @@
import os
import shutil
from stuff.general import General
from tools.helper import run
class Gapps(General):
id = ...
partition = "system"
dl_links = {
"11": {
"x86_64": ["https://sourceforge.net/projects/opengapps/files/x86_64/20220503/open_gapps-x86_64-11.0-pico-20220503.zip", "5a6d242be34ad1acf92899c7732afa1b"],
"x86": ["https://sourceforge.net/projects/opengapps/files/x86/20220503/open_gapps-x86-11.0-pico-20220503.zip", "efda4943076016d00b40e0874b12ddd3"],
"arm64-v8a": ["https://sourceforge.net/projects/opengapps/files/arm64/20220503/open_gapps-arm64-11.0-pico-20220503.zip", "7790055d34bbfc6fe610b0cd263a7add"],
"armeabi-v7a": ["https://sourceforge.net/projects/opengapps/files/arm/20220215/open_gapps-arm-11.0-pico-20220215.zip", "8719519fa32ae83a62621c6056d32814"]
},
"13": {
"x86_64": ["https://github.com/s1204IT/MindTheGappsBuilder/releases/download/20231028/MindTheGapps-13.0.0-x86_64-20231028.zip", "63ccebbf93d45c384f58d7c40049d398"],
"x86": ["https://github.com/s1204IT/MindTheGappsBuilder/releases/download/20231028/MindTheGapps-13.0.0-x86-20231028.zip", "f12b6a8ed14eedbb4b5b3c932a865956"],
"arm64-v8a": ["https://github.com/s1204IT/MindTheGappsBuilder/releases/download/20231028/MindTheGapps-13.0.0-arm64-20231028.zip", "11180da0a5d9f2ed2863882c30a8d556"],
"armeabi-v7a": ["https://github.com/s1204IT/MindTheGappsBuilder/releases/download/20231028/MindTheGapps-13.0.0-arm-20231028.zip", "d525c980bac427844aa4cb01628f8a8f"]
}
}
android_version = ...
dl_link = ...
act_md5 = ...
dl_file_name = "gapps.zip"
extract_to = "/tmp/gapps/extract"
non_apks = [
"defaultetc-common.tar.lz",
"defaultframework-common.tar.lz",
"googlepixelconfig-common.tar.lz",
"vending-common.tar.lz"
]
skip = [
"setupwizarddefault-x86_64.tar.lz",
"setupwizardtablet-x86_64.tar.lz"
]
files = [
"etc/default-permissions/default-permissions.xml",
"etc/default-permissions/opengapps-permissions-q.xml",
"etc/permissions/com.google.android.maps.xml",
"etc/permissions/com.google.android.media.effects.xml",
"etc/permissions/privapp-permissions-google.xml",
"etc/permissions/split-permissions-google.xml",
"etc/preferred-apps/google.xml",
"etc/sysconfig/google.xml",
"etc/sysconfig/google_build.xml",
"etc/sysconfig/google_exclusives_enable.xml",
"etc/sysconfig/google-hiddenapi-package-whitelist.xml",
"framework/com.google.android.maps.jar",
"framework/com.google.android.media.effects.jar",
"priv-app/AndroidMigratePrebuilt",
"priv-app/GoogleExtServices",
"priv-app/GoogleRestore",
"priv-app/CarrierSetup",
"priv-app/GoogleExtShared",
"priv-app/GoogleServicesFramework",
"priv-app/ConfigUpdater",
"priv-app/GoogleFeedback",
"priv-app/Phonesky",
"priv-app/GoogleBackupTransport",
"priv-app/GoogleOneTimeInitializer",
"priv-app/PrebuiltGmsCore",
"priv-app/GoogleContactsSyncAdapter",
"priv-app/GooglePartnerSetup",
"product/overlay/PlayStoreOverlay.apk",
"product/overlay/GmsOverlay.apk.apk",
"product/overlay/GmsSettingsProviderOverlay.apk",
"system_ext/etc/permissions/privapp-permissions-google-system-ext.xml",
"system_ext/priv-app/GoogleFeedback",
"system_ext/priv-app/GoogleServicesFramework",
"system_ext/priv-app/SetupWizard",
"product/priv-app/GmsCore",
"product/priv-app/AndroidAutoStub",
"product/priv-app/GoogleRestore",
"product/priv-app/Phonesky",
"product/priv-app/Velvet",
"product/priv-app/GooglePartnerSetup",
"product/app/GoogleCalendarSyncAdapter",
"product/app/PrebuiltExchange3Google",
"product/app/GoogleContactsSyncAdapter",
"product/framework/com.google.android.dialer.support.jar",
"product/lib64/libjni_latinimegoogle.so",
"product/etc/default-permissions/default-permissions-google.xml",
"product/etc/default-permissions/default-permissions-mtg.xml",
"product/etc/sysconfig/google.xml",
"product/etc/sysconfig/d2d_cable_migration_feature.xml",
"product/etc/sysconfig/google-hiddenapi-package-allowlist.xml",
"product/etc/sysconfig/google_build.xml",
"product/etc/permissions/privapp-permissions-google-product.xml",
"product/etc/permissions/com.google.android.dialer.support.xml",
"product/etc/security/fsverity/gms_fsverity_cert.der",
"product/lib/libjni_latinimegoogle.so",
]
def __init__(self, android_version="11") -> None:
super().__init__()
self.android_version = android_version
self.dl_link = self.dl_links[android_version][self.arch[0]][0]
self.act_md5 = self.dl_links[android_version][self.arch[0]][1]
if android_version == "11":
self.id = "OpenGapps"
else:
self.id = "MindTheGapps"
def copy(self):
if self.android_version == "11":
return self.copy_11()
elif self.android_version == "13":
return self.copy_13()
def copy_11(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)
for f in os.listdir(os.path.join(self.copy_dir, self.partition, "priv-app", app)):
dst_file_path = os.path.join(os.path.join(
self.copy_dir, self.partition, "priv-app", app), f)
if os.path.splitext(dst_file_path)[1].lower() == ".apk":
self.extract_app_lib(dst_file_path)
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)
def copy_13(self):
src_dir = os.path.join(self.extract_to, "system")
dst_dir = os.path.join(self.copy_dir, self.partition)
for root, dirs, files in os.walk(src_dir):
dir_name = os.path.basename(root)
# 遍历文件
for file in files:
src_file_path = os.path.join(root, file)
dst_file_path = os.path.join(dst_dir, os.path.relpath(
src_file_path, src_dir))
if not os.path.exists(os.path.dirname(dst_file_path)):
os.makedirs(os.path.dirname(dst_file_path))
# Logger.info(f"{src_file_path} -> {dst_file_path}")
shutil.copy2(src_file_path, dst_file_path)
if os.path.splitext(dst_file_path)[1].lower() == ".apk":
self.extract_app_lib(dst_file_path)
-190
View File
@@ -1,190 +0,0 @@
import configparser
import glob
import os
import shutil
import zipfile
import hashlib
from tools.helper import download_file, get_download_dir, host
from tools import container
from tools.logger import Logger
class General:
files = []
@property
def arch(self):
return host()
@property
def skip_extract(self):
return False
@property
def download_loc(self):
return os.path.join(get_download_dir(), self.dl_file_name)
@property
def copy_dir(self):
if container.use_overlayfs():
return "/var/lib/waydroid/overlay"
else:
return "/tmp/waydroid"
def download(self):
Logger.info("Downloading {} now to {} .....".format(
self.dl_file_name, self.download_loc))
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 remove(self):
for f in self.files:
file = os.path.join(self.copy_dir, self.partition, f)
if "*" in file:
for wildcard_file in glob.glob(file):
if os.path.isdir(wildcard_file):
shutil.rmtree(wildcard_file)
elif os.path.isfile(wildcard_file):
os.remove(wildcard_file)
else:
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file):
os.remove(file)
def extract(self):
Logger.info(f"Extracting {self.download_loc} to {self.extract_to}")
with zipfile.ZipFile(self.download_loc) as z:
z.extractall(self.extract_to)
def add_props(self):
bin_dir = os.path.join(self.copy_dir, "system", "etc")
resetprop_rc = os.path.join(
self.copy_dir, "system/etc/init/resetprop.rc")
if not os.path.isfile(os.path.join(bin_dir, "resetprop")):
if not os.path.exists(bin_dir):
os.makedirs(bin_dir)
shutil.copy(os.path.join(os.path.join(os.path.dirname(__file__), "..", "bin",
self.arch[0], "resetprop")), bin_dir)
os.chmod(os.path.join(bin_dir, "resetprop"), 0o755)
if not os.path.isfile(os.path.join(bin_dir, "resetprop.sh")):
with open(os.path.join(bin_dir, "resetprop.sh"), "w") as f:
f.write("#!/system/bin/sh\n")
f.write(
"while read line; do /system/etc/resetprop ${line%=*} ${line#*=}; done < /vendor/waydroid.prop\n")
os.chmod(os.path.join(bin_dir, "resetprop.sh"), 0o755)
if not os.path.isfile(resetprop_rc):
if not os.path.exists(os.path.dirname(resetprop_rc)):
os.makedirs(os.path.dirname(resetprop_rc))
with open(resetprop_rc, "w") as f:
f.write(
"on post-fs-data\n exec u:r:su:s0 root root -- /system/bin/sh /system/bin/resetprop.sh")
os.chmod(resetprop_rc, 0o644)
cfg = configparser.ConfigParser()
cfg.read("/var/lib/waydroid/waydroid.cfg")
for key in self.apply_props.keys():
if self.apply_props[key]:
cfg.set('properties', key, self.apply_props[key])
with open("/var/lib/waydroid/waydroid.cfg", "w") as f:
cfg.write(f)
def extract_app_lib(self, apk_file_path):
lib_dest_dir = os.path.dirname(apk_file_path)
with zipfile.ZipFile(apk_file_path, "r") as apk:
for file_info in apk.infolist():
file_name = file_info.filename
file_path = os.path.join(lib_dest_dir, file_name)
if file_info.filename.startswith(f"lib/{self.arch[0]}/") and file_name.endswith(".so"):
os.makedirs(os.path.dirname(
file_path), exist_ok=True)
with apk.open(file_info.filename) as src_file, open(file_path, "wb") as dest_file:
# Logger.info(f"{src_file} -> {dest_file}")
shutil.copyfileobj(src_file, dest_file)
def set_path_perm(self, path):
if "bin" in path.split("/"):
perms = [0, 2000, 0o755, 0o777]
else:
perms = [0, 0, 0o755, 0o644]
mode = os.stat(path).st_mode
if os.path.isdir(path):
mode |= perms[2]
else:
mode |= perms[3]
os.chown(path, perms[0], perms[1])
os.chmod(path, mode)
def set_perm2(self, path, recursive=False):
if not os.path.exists(path):
return
if recursive and os.path.isdir(path):
for root, dirs, files in os.walk(path):
for dir in dirs:
self.set_path_perm(os.path.join(root, dir))
for file in files:
self.set_path_perm(os.path.join(root, file))
else:
self.set_path_perm(path)
def set_perm(self):
for f in self.files:
path = os.path.join(self.copy_dir, self.partition, f)
if "*" in path:
for wildcard_file in glob.glob(path):
self.set_perm2(wildcard_file, recursive=True)
else:
self.set_perm2(path, recursive=True)
def remove_props(self):
cfg = configparser.ConfigParser()
cfg.read("/var/lib/waydroid/waydroid.cfg")
for key in self.apply_props.keys():
cfg.remove_option('properties', key)
with open("/var/lib/waydroid/waydroid.cfg", "w") as f:
cfg.write(f)
def copy(self):
pass
def extra1(self):
pass
def extra2(self):
pass
def install(self):
self.download()
if not self.skip_extract:
self.extract()
self.copy()
self.extra1()
if hasattr(self, "apply_props"):
self.add_props()
self.set_perm()
Logger.info(f"{self.id} installation finished")
def uninstall(self):
self.remove()
if hasattr(self, "apply_props"):
self.remove_props()
self.extra2()
self.set_perm()
Logger.info("Uninstallation finished")
-31
View File
@@ -1,31 +0,0 @@
import os
import shutil
from stuff.general import General
class HideStatusBar(General):
id = "hide status bar"
dl_links = {"11": ["https://github.com/ayasa520/hide-status-bar/releases/download/v0.0.2/app-release.apk",
"ff2fe63ddfb4b035e6720a1b195b2355"]}
partition = "system"
dl_file_name = "hidestatusbar.apk"
dl_link = ...
act_md5 = ...
files = [
"product/overlay/"+dl_file_name
]
def __init__(self, android_version="11") -> None:
super().__init__()
self.dl_link = self.dl_links[android_version][0]
self.act_md5 = self.dl_links[android_version][1]
def copy(self):
rro_dir = os.path.join(
self.copy_dir, self.partition, "product", "overlay")
if not os.path.exists(rro_dir):
os.makedirs(rro_dir)
shutil.copyfile(self.download_loc, os.path.join(
rro_dir, "hidestatusbar.apk"))
def skip_extract(self):
return True
-66
View File
@@ -1,66 +0,0 @@
import os
import re
import shutil
from stuff.general import General
from tools.logger import Logger
class Houdini(General):
id = "libhoudini"
partition = "system"
dl_links = {
"11": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/81f2a51ef539a35aead396ab7fce2adf89f46e88.zip", "fbff756612b4144797fbc99eadcb6653"],
"13": ["https://github.com/supremegamers/vendor_intel_proprietary_houdini/archive/9e77896350caccd228b36b2e1b4a994aa4bd48da.zip", "3807fe029559db3037efe245d9e74270"]
}
act_md5 = ...
dl_link = ...
dl_file_name = "libhoudini.zip"
extract_to = "/tmp/houdiniunpack"
init_rc_component = """
on early-init
mount 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"
}
files = [
"bin/arm",
"bin/arm64",
"bin/houdini",
"bin/houdini64",
"etc/binfmt_misc",
"etc/init/houdini.rc",
"lib/arm",
"lib/libhoudini.so",
"lib64/arm64",
"lib64/libhoudini.so"
]
def __init__(self, android_version="11") -> None:
super().__init__()
self.dl_link = self.dl_links[android_version][0]
self.act_md5 = self.dl_links[android_version][1]
def copy(self):
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)
-163
View File
@@ -1,163 +0,0 @@
import gzip
import os
import shutil
import re
from stuff.general import General
from tools.helper import download_file, get_data_dir, host
from tools.logger import Logger
from tools import container
class Magisk(General):
id = "magisk delta"
partition = "system"
dl_link = "https://github.com/mistrmochov/magiskdeltaorig/raw/main/app-release.apk"
dl_file_name = "magisk.apk"
extract_to = "/tmp/magisk_unpack"
magisk_dir = os.path.join(partition, "etc", "init", "magisk")
files = ["etc/init/magisk", "etc/init/bootanim.rc"]
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 = f"""
on post-fs-data
start logd
exec u:r:su:s0 root root -- /system/etc/init/magisk/magiskpolicy --live --magisk
exec u:r:magisk:s0 root root -- /system/etc/init/magisk/magiskpolicy --live --magisk
exec u:r:update_engine:s0 root root -- /system/etc/init/magisk/magiskpolicy --live --magisk
mkdir /dev/magisk_iqeoVo2mDrO 700
exec u:r:su:s0 root root -- /system/etc/init/magisk/magisk64 --auto-selinux --setup-sbin /system/etc/init/magisk /dev/magisk_iqeoVo2mDrO
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --post-fs-data
on nonencrypted
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --service
on property:vold.decrypt=trigger_restart_framework
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --service
on property:sys.boot_completed=1
mkdir /data/adb/magisk 755
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --boot-complete
on property:init.svc.zygote=restarting
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --zygote-restart
on property:init.svc.zygote=stopped
exec u:r:su:s0 root root -- /dev/magisk_iqeoVo2mDrO/magisk --auto-selinux --zygote-restart
"""
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)
# require additional setup
def setup(self):
Logger.info("Additional setup")
magisk_absolute_dir = os.path.join(self.copy_dir, self.magisk_dir)
data_dir = get_data_dir()
shutil.copytree(magisk_absolute_dir, os.path.join(data_dir, "adb", "magisk"), dirs_exist_ok=True)
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.arch[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)
shutil.copyfile(self.download_loc, os.path.join(magisk_absolute_dir,"magisk.apk") )
shutil.copytree(os.path.join(self.extract_to, "assets", "chromeos"), os.path.join(magisk_absolute_dir, "chromeos"), dirs_exist_ok=True)
assets_files = [
"addon.d.sh",
"boot_patch.sh",
"stub.apk",
"util_functions.sh"
]
for f in assets_files:
shutil.copyfile(os.path.join(self.extract_to, "assets", f), os.path.join(magisk_absolute_dir, f))
# 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)
def set_path_perm(self, path):
if "magisk" in path.split("/"):
perms = [0, 2000, 0o755, 0o755]
else:
perms = [0, 0, 0o755, 0o644]
mode = os.stat(path).st_mode
if os.path.isdir(path):
mode |= perms[2]
else:
mode |= perms[3]
os.chown(path, perms[0], perms[1])
os.chmod(path, mode)
def extra1(self):
self.delete_upper()
self.setup()
# Delete the contents of upperdir
def delete_upper(self):
if container.use_overlayfs():
sys_overlay_rw = "/var/lib/waydroid/overlay_rw"
files = [
"system/system/etc/init/bootanim.rc",
"system/system/etc/init/bootanim.rc.gz",
"system/system/etc/init/magisk",
"system/system/addon.d/99-magisk.sh",
"vendor/etc/selinux/precompiled_sepolicy"
]
for f in files:
file = os.path.join(sys_overlay_rw, f)
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file) or os.path.exists(file):
os.remove(file)
def extra2(self):
self.delete_upper()
data_dir = get_data_dir()
files = [
os.path.join(data_dir, "adb/magisk.db"),
os.path.join(data_dir, "adb/magisk")
]
for file in files:
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file):
os.remove(file)
bootanim_path = os.path.join(self.copy_dir, self.partition, "etc", "init", "bootanim.rc")
if container.use_overlayfs():
if os.path.exists(bootanim_path):
os.remove(bootanim_path)
else:
with open(bootanim_path, "w") as initfile:
initfile.write(self.oringinal_bootanim)
-176
View File
@@ -1,176 +0,0 @@
import os
import shutil
from stuff.general import General
from tools.logger import Logger
class MicroG(General):
id = "MicroG"
partition = "system"
fdroid_repo_apks = {
"com.aurora.store_41.apk": "9e6c79aefde3f0bbfedf671a2d73d1be",
"com.etesync.syncadapter_20300.apk": "997d6de7d41c454d39fc22cd7d8fc3c2",
"com.aurora.adroid_8.apk": "0010bf93f02c2d18daf9e767035fefc5",
"org.fdroid.fdroid.privileged_2130.apk": "b04353155aceb36207a206d6dd14ba6a",
"org.microg.nlp.backend.ichnaea_20036.apk": "0b3cb65f8458d1a5802737c7392df903",
"org.microg.nlp.backend.nominatim_20042.apk": "88e7397cbb9e5c71c8687d3681a23383",
}
microg_apks= {
"com.google.android.gms-223616054.apk": "a945481ca5d33a03bc0f9418263c3228",
"com.google.android.gsf-8.apk": "b2b4ea3642df6158e14689a4b2a246d4",
"com.android.vending-22.apk": "6815d191433ffcd8fa65923d5b0b0573",
"org.microg.gms.droidguard-14.apk": "4734b41c1a6bc34a541053ddde7a0f8e"
}
priv_apps = ["com.google.android.gms", "com.android.vending"]
dl_links = {
"Standard": [
"https://github.com/ayasa520/MinMicroG/releases/download/latest/MinMicroG-Standard-2.11.1-20230429100529.zip",
"0fe332a9caa3fbb294f2e2b50f720c6b"
],
"NoGoolag": [
"https://github.com/ayasa520/MinMicroG/releases/download/latest/MinMicroG-NoGoolag-2.11.1-20230429100545.zip",
"ff920f33f4c874eeae4c0444be427c68"
],
"UNLP": [
"https://github.com/ayasa520/MinMicroG/releases/download/latest/MinMicroG-UNLP-2.11.1-20230429100555.zip",
"6136b383153c2a6797d14fb4d7ca3f97"
],
"Minimal": [
"https://github.com/ayasa520/MinMicroG/releases/download/latest/MinMicroG-Minimal-2.11.1-20230429100521.zip"
"afb87eb64e7749cfd72c4760d85849da"
],
"MinimalIAP": [
"https://github.com/ayasa520/MinMicroG/releases/download/latest/MinMicroG-MinimalIAP-2.11.1-20230429100556.zip"
"cc071f4f776cbc16c4c1f707aff1f7fa"
]
}
dl_link = ...
act_md5 = ...
dl_file_name = ...
sdk = ...
extract_to = "/tmp/microg/extract"
rc_content = '''
on property:sys.boot_completed=1
start microg_service
service microg_service /system/bin/sh /system/bin/npem
user root
group root
oneshot
'''
files = [
"priv-app/GoogleBackupTransport",
"priv-app/MicroGUNLP",
"priv-app/MicroGGMSCore",
"priv-app/MicroGGMSCore/lib/x86_64/libmapbox-gl.so",
"priv-app/MicroGGMSCore/lib/x86_64/libconscrypt_gmscore_jni.so",
"priv-app/MicroGGMSCore/lib/x86_64/libcronet.102.0.5005.125.so",
"priv-app/PatchPhonesky",
"priv-app/PatchPhonesky/lib/x86_64/libempty_x86_64.so",
"priv-app/AuroraServices",
"bin/npem",
"app/GoogleCalendarSyncAdapter",
"app/NominatimNLPBackend",
"app/MicroGGSFProxy",
"app/LocalGSMNLPBackend",
"app/DejaVuNLPBackend",
"app/MozillaUnifiedNLPBackend",
"app/AppleNLPBackend",
"app/AuroraDroid",
"app/LocalWiFiNLPBackend",
"app/GoogleContactsSyncAdapter",
"app/MicroGGSFProxy/MicroGGSFProxy",
"framework/com.google.widevine.software.drm.jar",
"framework/com.google.android.media.effects.jar",
"framework/com.google.android.maps.jar",
"lib64/libjni_keyboarddecoder.so",
"lib64/libjni_latinimegoogle.so",
"etc/default-permissions/microg-permissions.xml",
"etc/default-permissions/microg-permissions-unlp.xml",
"etc/default-permissions/gsync.xml",
"etc/sysconfig/nogoolag.xml",
"etc/sysconfig/nogoolag-unlp.xml",
"etc/init/microg.rc",
"etc/permissions/com.google.android.backuptransport.xml",
"etc/permissions/com.android.vending.xml",
"etc/permissions/foss-permissions.xml",
"etc/permissions/com.google.android.gms.xml",
"etc/permissions/com.aurora.services.xml",
"etc/permissions/com.google.android.maps.xml",
"etc/permissions/com.google.widevine.software.drm.xml",
"etc/permissions/com.google.android.media.effects.xml",
"lib/libjni_keyboarddecoder.so",
"lib/libjni_latinimegoogle.so",
]
def __init__(self, android_version="11", variant="Standard") -> None:
super().__init__()
self.dl_link = self.dl_links[variant][0]
self.act_md5 = self.dl_links[variant][1]
self.id = self.id+f"-{variant}"
self.dl_file_name = f'MinMicroG-{variant}.zip'
if android_version == "11":
self.sdk = 30
elif android_version == "13":
self.sdk = 33
def copy(self):
Logger.info("Copying libs and apks...")
dst_dir = os.path.join(self.copy_dir, self.partition)
src_dir = os.path.join(self.extract_to, "system")
if "arm" in self.arch[0]:
sub_arch = "arm"
else:
sub_arch = "x86"
if 64 == self.arch[1]:
arch = f"{sub_arch}{'' if sub_arch=='arm' else '_'}64"
for root, dirs, files in os.walk(src_dir):
flag = False
dir_name = os.path.basename(root)
# 遍历文件
if dir_name.startswith('-') and dir_name.endswith('-'):
archs, sdks = [], []
for i in dir_name.split("-"):
if i.isdigit():
sdks.append(i)
elif i:
archs.append(i)
if len(archs) != 0 and arch not in archs and sub_arch not in archs or len(sdks) != 0 and str(self.sdk) not in sdks:
continue
else:
flag = True
for file in files:
src_file_path = os.path.join(root, file)
if not flag:
dst_file_path = os.path.join(dst_dir, os.path.relpath(
src_file_path, src_dir))
else:
dst_file_path = os.path.join(dst_dir, os.path.relpath(
os.path.join(os.path.dirname(root), file), src_dir))
if not os.path.exists(os.path.dirname(dst_file_path)):
os.makedirs(os.path.dirname(dst_file_path))
# Logger.info(f"{src_file_path} -> {dst_file_path}")
shutil.copy2(src_file_path, dst_file_path)
if os.path.splitext(dst_file_path)[1].lower() == ".apk":
self.extract_app_lib(dst_file_path)
rc_dir = os.path.join(dst_dir, "etc/init/microg.rc")
if not os.path.exists(os.path.dirname(rc_dir)):
os.makedirs(os.path.dirname(rc_dir))
with open(rc_dir, "w") as f:
f.write(self.rc_content)
def extra2(self):
system_dir = os.path.join(self.copy_dir, self.partition)
files = [key.split("_")[0] for key in self.fdroid_repo_apks.keys()]
files += [key.split("-")[0] for key in self.microg_apks.keys()]
for f in files:
if f in self.priv_apps:
file = os.path.join(system_dir, "priv-app", f)
else:
file = os.path.join(system_dir, "app", f)
if os.path.isdir(file):
shutil.rmtree(file)
elif os.path.isfile(file):
os.remove(file)
-40
View File
@@ -1,40 +0,0 @@
import os
import shutil
from stuff.general import General
from tools.helper import run
from tools.logger import Logger
class Mitm(General):
id = "mitm"
partition = "system"
def __init__(self, ca_cert_file: str=None) -> None:
super().__init__()
self.ca_cert_file = ca_cert_file
def download(self):
pass
def skip_extract(self):
return True
def copy(self):
file_hash = run([
'openssl', 'x509', '-noout', '-subject_hash_old', '-in',
self.ca_cert_file,
]).stdout.decode("ascii").strip()
target_dir = os.path.join(
self.copy_dir, self.partition, "etc", "security", "cacerts")
Logger.info(f"Creating directory: {target_dir}")
os.makedirs(target_dir, exist_ok=True)
target_path = os.path.join(target_dir, f'{file_hash}.0')
Logger.info(f"Copying {self.ca_cert_file} to system trust store")
Logger.info(f"Target file: {target_path}")
shutil.copyfile(self.ca_cert_file, target_path)
os.chmod(target_path, 0o644)
def install(self):
if not self.ca_cert_file:
raise ValueError(
"This command requires the --ca-cert switch and a *.pem file")
super().install()
-52
View File
@@ -1,52 +0,0 @@
import os
import re
import shutil
from stuff.general import General
from tools.logger import Logger
class Ndk(General):
id = "libndk"
partition = "system"
dl_links = {
"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/68734c52556d3d7a6db34c603dd9276915c29f2f.zip", "0b2207c490fcb400aa5c87fcf0d52d38"]
}
dl_file_name = "libndktranslation.zip"
extract_to = "/tmp/libndkunpack"
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": "libndk_translation.so",
"ro.enable.native.bridge.exec": "1",
"ro.vendor.enable.native.bridge.exec": "1",
"ro.vendor.enable.native.bridge.exec64": "1",
"ro.ndk_translation.version": "0.2.3",
"ro.dalvik.vm.isa.arm": "x86",
"ro.dalvik.vm.isa.arm64": "x86_64"
}
files = [
"bin/arm",
"bin/arm64",
"bin/ndk_translation_program_runner_binfmt_misc",
"bin/ndk_translation_program_runner_binfmt_misc_arm64",
"etc/binfmt_misc",
"etc/ld.config.arm.txt",
"etc/ld.config.arm64.txt",
"etc/init/ndk_translation.rc",
"lib/arm",
"lib64/arm64",
"lib/libndk*",
"lib64/libndk*"
]
def __init__(self, android_version="11") -> None:
super().__init__()
self.dl_link = self.dl_links[android_version][0]
self.act_md5 = self.dl_links[android_version][1]
def copy(self):
Logger.info("Copying libndk library files ...")
name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0]
shutil.copytree(os.path.join(self.extract_to, "vendor_google_proprietary_ndk_translation-prebuilt-" + name,
"prebuilts"), os.path.join(self.copy_dir, self.partition), dirs_exist_ok=True)
-79
View File
@@ -1,79 +0,0 @@
import os
import re
import shutil
from stuff.general import General
from tools.helper import backup, restore
from tools.logger import Logger
from tools import container
class Nodataperm(General):
id = "nodataperm"
dl_links = {
"11": {
"x86_64": [
"https://github.com/ayasa520/hack_full_data_permission/archive/d4beab7780eb792059d33e77d865579c9ee41546.zip",
"b0e3908ffcf5df8ea62f4929aa680f1a"
],
},
"13": {
"x86_64": [
"https://github.com/ayasa520/hack_full_data_permission/archive/d4beab7780eb792059d33e77d865579c9ee41546.zip",
"b0e3908ffcf5df8ea62f4929aa680f1a"
],
},
}
dl_file_name = "nodataperm.zip"
extract_to = "/tmp/nodataperm"
dl_link = None
act_md5 = None
partition = "system"
files = [
"etc/nodataperm.sh",
"etc/init/nodataperm.rc",
"framework/services.jar",
"framework/services.jar.prof",
"framework/services.jar.bprof",
]
def __init__(self, android_version="11") -> None:
super().__init__()
print("ok")
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.act_md5 = self.dl_links[android_version][arch][1]
def copy(self):
name = re.findall(r"([a-zA-Z0-9]+)\.zip", self.dl_link)[0]
extract_path = os.path.join(
self.extract_to, f"hack_full_data_permission-{name}")
if not container.use_overlayfs():
services_jar = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar")
services_jar_prof = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar.prof")
services_jar_bprof = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar.bprof")
backup(services_jar)
backup(services_jar_prof)
backup(services_jar_bprof)
Logger.info(f"Copying {self.id} library files ...")
shutil.copytree(extract_path, os.path.join(
self.copy_dir, self.partition), dirs_exist_ok=True)
def extra2(self):
if not container.use_overlayfs():
services_jar = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar")
services_jar_prof = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar.prof")
services_jar_bprof = os.path.join(
self.copy_dir, self.partition, "framework", "services.jar.bprof")
restore(services_jar)
restore(services_jar_prof)
restore(services_jar_bprof)
-67
View File
@@ -1,67 +0,0 @@
import os
import shutil
from stuff.general import General
class Smartdock(General):
id = "smartdock"
dl_link = "https://f-droid.org/repo/cu.axel.smartdock_1100.apk"
partition = "system"
dl_file_name = "smartdock.apk"
act_md5 = "f4087d34218eac902a5cca98ee03d215"
apply_props = { "qemu.hw.mainkeys" : "1" }
skip_extract = True
permissions = """<?xml version="1.0" encoding="utf-8"?>
<permissions>
<privapp-permissions package="cu.axel.smartdock">
<permission name="android.permission.SYSTEM_ALERT_WINDOW" />
<permission name="android.permission.GET_TASKS"/>
<permission name="android.permission.REORDER_TASKS"/>
<permission name="android.permission.REMOVE_TASKS" />
<permission name="android.permission.ACCESS_WIFI_STATE"/>
<permission name="android.permission.CHANGE_WIFI_STATE"/>
<permission name="android.permission.ACCESS_NETWORK_STATE"/>
<permission name="android.permission.ACCESS_FINE_LOCATION"/>
<permission name="android.permission.READ_EXTERNAL_STORAGE"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.BLUETOOTH_ADMIN"/>
<permission name="android.permission.BLUETOOTH_CONNECT"/>
<permission name="android.permission.BLUETOOTH"/>
<permission name="android.permission.REQUEST_DELETE_PACKAGES"/>
<permission name="android.permission.ACCESS_SUPERUSER"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
<permission name="android.permission.QUERY_ALL_PACKAGES" />
</privapp-permissions>
</permissions>
"""
files = [
"etc/permissions/permissions_cu.axel.smartdock.xml",
"priv-app/SmartDock",
"etc/init/smartdock.rc"
]
rc_content = '''
on property:sys.boot_completed=1
start set_home_activity
service set_home_activity /system/bin/sh -c "cmd package set-home-activity cu.axel.smartdock/.activities.LauncherActivity"
user root
group root
oneshot
'''
def copy(self):
if not os.path.exists(os.path.join(self.copy_dir, self.partition, "priv-app", "SmartDock")):
os.makedirs(os.path.join(self.copy_dir, self.partition, "priv-app", "SmartDock"))
if not os.path.exists(os.path.join(self.copy_dir, self.partition, "etc", "permissions")):
os.makedirs(os.path.join(self.copy_dir, self.partition, "etc", "permissions"))
shutil.copyfile(os.path.join(self.download_loc),
os.path.join(self.copy_dir, self.partition, "priv-app/SmartDock/smartdock.apk"))
with open(os.path.join(self.copy_dir, self.partition, "etc", "permissions", "permissions_cu.axel.smartdock.xml"), "w") as f:
f.write(self.permissions)
rc_dir = os.path.join(self.copy_dir, self.partition, "etc/init/smartdock.rc")
if not os.path.exists(os.path.dirname(rc_dir)):
os.makedirs(os.path.dirname(rc_dir))
self.extract_app_lib(os.path.join(self.copy_dir, self.partition, "priv-app/SmartDock/smartdock.apk"))
with open(rc_dir, "w") as f:
f.write(self.rc_content)
-78
View File
@@ -1,78 +0,0 @@
import glob
import os
import shutil
from stuff.general import General
from tools.logger import Logger
class TfliteFix(General):
id = "tflitefix"
partition = "system"
TARGET_OFFSET = 0x2E9204
PATCH_BYTES = b"\xc0\x03\x5f\xd6" # ret in AArch64 little-endian
def __init__(self, android_version="13") -> None:
super().__init__()
def download(self):
pass
@property
def skip_extract(self):
return True
def copy(self):
pass
def extra1(self):
"""Applies binary patch to libtensorflowlite.so in installed apps"""
search_paths = [
os.path.expanduser("~/.local/share/waydroid/data/app/~~*==/*/lib/arm64/libtensorflowlite.so"),
"/var/lib/waydroid/data/app/~~*==/*/lib/arm64/libtensorflowlite.so",
]
found = []
for p in search_paths:
found.extend(glob.glob(p))
if not found:
Logger.warning("No installed apps with libtensorflowlite.so found in Waydroid data.")
return
for lib_path in found:
try:
with open(lib_path, "rb") as f:
data = bytearray(f.read())
if len(data) > self.TARGET_OFFSET + 4:
if bytes(data[self.TARGET_OFFSET:self.TARGET_OFFSET+4]) == self.PATCH_BYTES:
Logger.info(f"Patch already applied to {lib_path}")
continue
backup = lib_path + ".orig"
if not os.path.exists(backup):
shutil.copy2(lib_path, backup)
data[self.TARGET_OFFSET:self.TARGET_OFFSET+4] = self.PATCH_BYTES
with open(lib_path, "wb") as f:
f.write(data)
os.chmod(lib_path, 0o755)
Logger.info(f"Successfully patched {lib_path}")
except Exception as e:
Logger.error(f"Failed to patch {lib_path}: {e}")
def extra2(self):
"""Restores original libtensorflowlite.so from backup"""
search_paths = [
os.path.expanduser("~/.local/share/waydroid/data/app/~~*==/*/lib/arm64/libtensorflowlite.so.orig"),
"/var/lib/waydroid/data/app/~~*==/*/lib/arm64/libtensorflowlite.so.orig",
]
for p in search_paths:
for orig in glob.glob(p):
target = orig[:-5]
try:
shutil.copy2(orig, target)
os.remove(orig)
os.chmod(target, 0o755)
Logger.info(f"Restored {target}")
except Exception as e:
Logger.error(f"Failed to restore {target}: {e}")
-57
View File
@@ -1,57 +0,0 @@
import os
import re
import shutil
from stuff.general import General
from tools.logger import Logger
class Widevine(General):
id = "widevine"
partition = "vendor"
dl_links = {
# "x86": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/94c9ee172e3d78fecc81863f50a59e3646f7a2bd.zip", "a31f325453c5d239c21ecab8cfdbd878"],
"x86_64": {
"11": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/48d1076a570837be6cdce8252d5d143363e37cc1.zip",
"f587b8859f9071da4bca6cea1b9bed6a"],
"13": ["https://github.com/WayDroid-ATV/vendor_google_proprietary_widevine-prebuilt/archive/679552343d8b2e8d7a19b6df61c7a03963d0c75b.zip",
"80ab79ea85c7b2556baedb371a54e01c"]
},
# "armeabi-v7a": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/a1a19361d36311bee042da8cf4ced798d2c76d98.zip", "fed6898b5cfd2a908cb134df97802554"],
"arm64-v8a": {
"11": ["https://github.com/supremegamers/vendor_google_proprietary_widevine-prebuilt/archive/a1a19361d36311bee042da8cf4ced798d2c76d98.zip",
"fed6898b5cfd2a908cb134df97802554"]
}
}
dl_file_name = "widevine.zip"
extract_to = "/tmp/widevineunpack"
files = [
"bin/hw/*widevine",
"bin/move_widevine_data.sh",
"etc/init/*widevine.rc",
"etc/vintf/manifest/*widevine.xml",
"lib/libwvhidl.so",
"lib/libwvaidl.so",
"lib/mediadrm",
"lib64/libwvhidl.so",
"lib64/libwvaidl.so",
"lib64/mediadrm"
]
def __init__(self, android_version) -> None:
super().__init__()
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.android_version = android_version
self.libdir = "lib64" if self.arch[1] == 64 else "lib"
def copy(self):
name = re.findall("([a-zA-Z0-9]+)\.zip", self.dl_link)[0]
Logger.info("Copying widevine library files ...")
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)
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
-53
View File
@@ -1,53 +0,0 @@
import configparser
import os
import sys
# import dbus
from tools.helper import run
from tools.logger import Logger
# def DBusContainerService(object_path="/ContainerManager", intf="id.waydro.ContainerManager"):
# return dbus.Interface(dbus.SystemBus().get_object("id.waydro.Container", object_path), intf)
# def DBusSessionService(object_path="/SessionManager", intf="id.waydro.SessionManager"):
# return dbus.Interface(dbus.SessionBus().get_object("id.waydro.Session", object_path), intf)
# def use_dbus():
# try:
# DBusContainerService()
# except:
# return False
# return True
def use_overlayfs():
cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
if not os.path.isfile(cfg_file):
Logger.error("Cannot locate waydroid config file, reinit wayland and try again!")
sys.exit(1)
cfg.read(cfg_file)
if "waydroid" not in cfg:
Logger.error("Required entry in config was not found, Cannot continue!")
if "mount_overlays" not in cfg["waydroid"]:
return False
if cfg["waydroid"]["mount_overlays"]=="True":
return True
return False
# def get_session():
# return DBusContainerService().GetSession()
def stop():
# if use_dbus():
# session = DBusContainerService().GetSession()
# if session:
# DBusContainerService().Stop(False)
# else:
run(["waydroid", "container", "stop"])
def is_running():
return "Session:\tRUNNING" in run(["waydroid", "status"]).stdout.decode()
def upgrade():
run(["waydroid", "upgrade", "-o"], ignore=r"\[.*\] Stopping container\n\[.*\] Starting container")
-146
View File
@@ -1,146 +0,0 @@
import gzip
import os
import re
import platform
import re
import subprocess
import sys
import requests
from tools.logger import Logger
from tqdm import tqdm
import hashlib
from typing import Optional
def get_download_dir():
download_loc = ""
if os.environ.get("XDG_CACHE_HOME", None) is None:
download_loc = os.path.join('/', "home", os.environ.get(
"SUDO_USER", os.environ["USER"]), ".cache", "waydroid-script", "downloads"
)
else:
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
# not good
def get_data_dir():
return os.path.join('/', "home", os.environ.get("SUDO_USER", os.environ["USER"]), ".local", "share", "waydroid", "data")
# execute on host
def run(args: list, env: Optional[str] = None, ignore: Optional[str] = None):
result = subprocess.run(
args=args,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# print(result.stdout.decode())
if result.stderr:
error = result.stderr.decode("utf-8")
if ignore and re.match(ignore, error):
return result
Logger.error(error)
raise subprocess.CalledProcessError(
returncode=result.returncode,
cmd=result.args,
stderr=result.stderr
)
return result
# execute on waydroid shell
def shell(arg: str, env: Optional[str] = None):
a = subprocess.Popen(
args=["sudo", "waydroid", "shell"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
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()
if env:
subprocess.Popen(
args=["echo", env],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
subprocess.Popen(
args=["echo", arg],
stdout=a.stdin,
stdin=subprocess.PIPE
).communicate()
a.stdin.close()
if a.stderr.read():
Logger.error(a.stderr.read().decode('utf-8'))
raise subprocess.CalledProcessError(
returncode=a.returncode,
cmd=a.args,
stderr=a.stderr
)
return a.stdout.read().decode("utf-8")
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)
def backup(path):
gz_filename = path+".gz"
with gzip.open(gz_filename, 'wb') as f_gz:
with open(path, "rb") as f:
f_gz.write(f.read())
def restore(path):
gz_filename = path+".gz"
with gzip.GzipFile(gz_filename) as f_gz:
with open(path, "wb") as f:
f.writelines(f_gz)
-41
View File
@@ -1,41 +0,0 @@
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):
run(["sudo", "e2fsck", "-y", "-f", img_file], ignore="^e2fsck \d+\.\d+\.\d (.+)\n$")
run(["sudo", "resize2fs", img_file, size], ignore="^resize2fs \d+\.\d+\.\d (.+)\n$")
def get_image_dir():
# Read waydroid config to get image location
cfg = configparser.ConfigParser()
cfg_file = os.environ.get("WAYDROID_CONFIG", "/var/lib/waydroid/waydroid.cfg")
if not os.path.isfile(cfg_file):
Logger.error("Cannot locate waydroid config file, reinit wayland and try again!")
sys.exit(1)
cfg.read(cfg_file)
if "waydroid" not in cfg:
Logger.error("Required entry in config was not found, Cannot continue!") #magisk
sys.exit(1)
return cfg["waydroid"]["images_path"]
-13
View File
@@ -1,13 +0,0 @@
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")
+595
View File
@@ -0,0 +1,595 @@
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:
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")
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",
"vending-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://github.com/newbit1/libndk_translation_Module/archive/c6077f3398172c64f55aad7aab0e55fad9110cf3.zip"
dl_file_name = os.path.join(download_loc, "libndktranslation.zip")
extract_to = "/tmp/libndkunpack" #All catalog files will be marked as executable!
act_md5 = "5e8e0cbde0e672fdc2b47f20a87472fd"
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://raw.githubusercontent.com/casualsnek/miscpackages/main/libhoudini_a11.zip"
dl_file_name = os.path.join(download_loc, "libhoudini.zip")
extract_to = "/tmp/houdiniunpack" #All catalog files will be marked as executable!
act_md5 = "c9a80831641de8fd44ccf93a0ad8b585"
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://github.com/topjohnwu/Magisk/releases/download/v20.4/Magisk-v20.4.zip"
busybox_dl_link = "https://github.com/Gnurou/busybox-android/raw/master/busybox-android"
busybox_dl_file_name = os.path.join(download_loc, "busybox-android")
dl_file_name = os.path.join(download_loc, "magisk.zip")
extract_to = "/tmp/magisk_unpack"
act_md5 = "9503fc692e03d60cb8897ff2753c193f"
busybox_act_md5 = "2e43cc2e8f44b83f9029a6561ce5d8b9"
sys_image_mount = "/tmp/waydroidimage"
loc_md5 = ""
busybox_loc_md5 = ""
magisk_init = """#!/system/bin/sh
mount -o remount,rw /
rm /sbin/magisk /sbin/magiskpolicy /sbin/magiskinit
cp /magiskinit /sbin/magiskinit
ln -s /sbin/magiskinit /sbin/magisk
ln -s /sbin/magiskinit /sbin/magiskpolicy
mkdir -p /data/adb/magisk
cp /busybox /data/adb/magisk/busybox
cp /util_functions.sh /data/adb/magisk/util_functions.sh
cp /boot_patch.sh /data/adb/magisk/boot_patch.sh
cp /addon.d.sh /data/adb/magisk/addon.d.sh
magisk -c >&2
ln -sf /data /sbin/.magisk/mirror/data
ln -sf /vendor /sbin/.magisk/mirror/vendor
magisk --post-fs-data
sleep 1
magisk --service
magisk --boot-complete
mount -o remount,ro /
"""
init_rc_component = """on property:dev.bootcomplete=1
start magisk
service magisk /system/bin/init-magisk.sh
class main
user root
group root
oneshot
"""
if os.path.isfile(dl_file_name):
with open(dl_file_name,"rb") as f:
bytes = f.read()
loc_md5 = hashlib.md5(bytes).hexdigest()
if os.path.isfile(busybox_dl_file_name):
with open(busybox_dl_file_name,"rb") as f:
bytes = f.read()
busybox_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+50))
# Mount the system image
mount_image(system_img, sys_image_mount)
# Download magisk
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("==> Magisk zip not downloaded or hash mismatches, downloading now .....")
loc_md5 = download_file(dl_link, dl_file_name)
# Download busybox android binary
while not os.path.isfile(busybox_dl_file_name) or busybox_loc_md5 != busybox_act_md5:
if os.path.isfile(busybox_dl_file_name):
os.remove(busybox_dl_file_name)
print("==> BusyBox binary not downloaded or hash mismatches, downloading now .....")
busybox_loc_md5 = download_file(busybox_dl_link, busybox_dl_file_name)
# Extract magisk files
print("==> Extracting archive...")
with zipfile.ZipFile(dl_file_name) as z:
z.extractall(extract_to)
# Now setup and install magisk binary and app
print("==> Installing magisk now ...")
with open(os.path.join(sys_image_mount, "system", "bin", "init-magisk.sh"), "w") as imf:
imf.write(magisk_init)
os.system("chmod 755 {}".format(os.path.join(sys_image_mount, "system", "bin", "init-magisk.sh")))
arch_dir = "x86" if "x86" in platform.machine() else "arm"
arch = "64" if "64" in platform.machine() else ""
shutil.copyfile(os.path.join(extract_to, arch_dir, "magiskinit{arch}".format(arch=arch)),
os.path.join(sys_image_mount, "sbin", "magiskinit"))
shutil.copyfile(os.path.join(extract_to, arch_dir, "magiskinit{arch}".format(arch=arch)),
os.path.join(sys_image_mount, "magiskinit"))
os.system("chmod 755 {} & chmod 755 {}".format(os.path.join(sys_image_mount, "sbin", "magiskinit"), os.path.join(sys_image_mount, "magiskinit")))
# Copy busybox
print("==> Installing BusyBox")
shutil.copyfile(busybox_dl_file_name, os.path.join(sys_image_mount, "busybox"))
os.system("chmod 755 {}".format(os.path.join(sys_image_mount, "busybox")))
# Copy files from common directory
for file in ["util_functions.sh", "boot_patch.sh", "addon.d.sh"]:
shutil.copyfile(os.path.join(extract_to, "common", file),
os.path.join(sys_image_mount, file))
os.system("chmod 755 {}".format(os.path.join(sys_image_mount, file)))
# Create symlinks
print("==> Creating symlinks")
os.system("cd {root}/sbin && ln -sf magiskinit magiskinit >> /dev/null 2>&1".format(root=sys_image_mount))
os.system("cd {root}/sbin && ln -sf magiskinit magisk >> /dev/null 2>&1".format(root=sys_image_mount))
print("==> magiskinit -> magisk")
os.system("cd {root}/sbin && ln -sf /magiskinit magiskpolicy >> /dev/null 2>&1".format(root=sys_image_mount))
print("==> magiskinit -> magiskpolicy")
# Add entry to init.rc
print("==> Adding entry to init.rc")
with open(os.path.join(sys_image_mount, "init.rc"), "r") as initfile:
initcontent = initfile.read()
if init_rc_component not in initcontent:
initcontent=initcontent+init_rc_component
with open(os.path.join(sys_image_mount, "init.rc"), "w") as initfile:
initfile.write(initcontent)
# Install Magisk apk
if not os.path.exists(os.path.join(sys_image_mount, "system", "priv-app", "Magisk")):
os.makedirs(os.path.join(sys_image_mount, "system", "priv-app", "Magisk"))
shutil.copyfile(os.path.join(extract_to, "common", "magisk.apk"),
os.path.join(sys_image_mount, "system", "priv-app", "Magisk", "magisk.apk"))
# 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 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')
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()
if __name__ == "__main__":
main()