Compare commits

..
Author SHA1 Message Date
Soul Inferno DE 218fadb6a4 Update README.md 2026-05-26 21:04:46 +02:00
Soul Inferno DE 89e3711977 Merge pull request #1 from casualsnek/main
updates
2026-02-01 19:05:41 +01:00
Soul Inferno DE 73c746fe2b Added support for multi device users
with this changes you can get all GSF IDs if you are using more than one profile on your waydroid system.

What this basically does:

- lists /data/users folders that can will be used for multiple sqlite requests
- uses android pm list users for the output to see a clean output line for name, folder id and gsf id
2025-07-29 05:24:59 +02:00
4 changed files with 56 additions and 99 deletions
+10
View File
@@ -1,3 +1,13 @@
# What's the difference from this fork ?
I added some small code lines to enable this script for beeing used with "MULTIPLE ANDROID USERS IN WAYDROID"
--> It won't work with only a single user created (maybe fixing that in the future..)
--> You need to create at least "two users" in Waydroid to be able to get the IDs for Android verifications
# Waydroid Extras Script
Script to add GApps and other stuff to Waydroid!
+3 -8
View File
@@ -18,7 +18,6 @@ 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
@@ -145,8 +144,6 @@ def remove_app(args):
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"
@@ -172,8 +169,6 @@ def hack_option(args):
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"
@@ -209,7 +204,7 @@ def interact():
args = argparse.Namespace()
android_version = inquirer.select(
message="Select Android version",
instruction="(↑↓ Select Item)",
instruction="(\u2191\u2193 Select Item)",
choices=[
Choice(name="Android 11", value="11"),
Choice(name="Android 13", value="13"),
@@ -235,7 +230,7 @@ def interact():
exit()
install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "smartdock", "fdroidpriv", "widevine",]
hack_choices = ["tflitefix"]
hack_choices = []
if android_version=="11":
hack_choices.extend(["nodataperm", "hidestatusbar"])
@@ -302,7 +297,7 @@ def main():
install_choices = ["gapps", "microg", "libndk", "libhoudini",
"magisk", "mitm", "smartdock", "widevine"]
hack_choices = ["nodataperm", "hidestatusbar", "tflitefix"]
hack_choices = ["nodataperm", "hidestatusbar"]
micrg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"]
remove_choices = install_choices
+42 -12
View File
@@ -1,21 +1,51 @@
from tools import container
from tools.helper import shell
from tools.logger import Logger
import re
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:
if not container.is_running():
Logger.error("Please make sure Waydroid is running and Gapps has been installed!")
return
print(queryout.replace("android_id|", "").strip())
try:
# Get list of user IDs and their names using 'pm list users'
users_raw = shell(
arg="pm list users",
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"
)
user_map = {}
for line in users_raw.strip().splitlines():
match = re.search(r'UserInfo\{(\d+):([^:}]+)', line)
if match:
user_id, username = match.groups()
user_map[user_id] = username
except Exception as e:
Logger.error(f"Failed to parse user list: {e}")
return
print("------------------------------------------------------------------------")
print(f"{'Username':<20} | {'User ID':^10} | {'GSF Android ID'}")
print("------------------------------------------------------------------------")
for user_id, username in user_map.items():
try:
db_path = f"/data/user/{user_id}/com.google.android.gsf/databases/gservices.db"
query = f"sqlite3 {db_path} \"select value from main where name = 'android_id';\""
gsf_id = shell(
arg=query,
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"
).strip()
if gsf_id:
print(f"{username:<20} | {user_id:^10} | {gsf_id}")
else:
print(f"{username:<20} | {user_id:^10} | (not found)")
except:
print(f"{username:<20} | {user_id:^10} | (query error)")
print("------------------------------------------------------------------------")
print(" ^----- Open https://google.com/android/uncertified/?pli=1")
print(" Login with your google id then submit the form with id shown above")
print(" Login with your Google ID, then submit the form with the ID(s) shown above.")
-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}")