From ccda6b1a4672ee6540d21629f21395c5556ee14f Mon Sep 17 00:00:00 2001 From: Lolmc0587 Date: Thu, 10 Jul 2025 16:46:04 +0700 Subject: [PATCH] Add gps support --- main.py | 32 +++++++-- stuff/gps.py | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 stuff/gps.py diff --git a/main.py b/main.py index d76f415..138d53d 100755 --- a/main.py +++ b/main.py @@ -18,6 +18,7 @@ from stuff.nodataperm import Nodataperm from stuff.smartdock import Smartdock from stuff.widevine import Widevine from stuff.fdroidpriv import FDroidPriv +from stuff.gps import GPS import tools.helper as helper from tools import container from tools import images @@ -89,6 +90,8 @@ def install_app(args): install_list.append(Mitm(args.ca_cert_file)) if "fdroidpriv" in app: install_list.append(FDroidPriv(args.android_version)) + if "gps" in app: + install_list.append(GPS(args.android_version, args.gps_host, args.baud_rate)) if not container.use_overlayfs(): copy_dir = "/tmp/waydroid" @@ -115,8 +118,7 @@ def install_app(args): if not container.use_overlayfs(): umount("vendor", copy_dir) umount("system", copy_dir) - - container.upgrade() + container.upgrade() def remove_app(args): @@ -144,6 +146,8 @@ def remove_app(args): remove_list.append(Nodataperm(args.android_version)) if "hidestatusbar" in app: remove_list.append(HideStatusBar()) + if "gps" in app: + remove_list.append(GPS()) if not container.use_overlayfs(): copy_dir = "/tmp/waydroid" @@ -169,6 +173,7 @@ def hack_option(args): hack_list.append(Nodataperm()) if "hidestatusbar" in options: hack_list.append(HideStatusBar()) + if not container.use_overlayfs(): copy_dir = "/tmp/waydroid" @@ -229,10 +234,11 @@ def interact(): if not action: exit() - install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "smartdock", "fdroidpriv",] + install_choices = ["gapps", "microg", "libndk", "libhoudini", "magisk", "smartdock", "fdroidpriv","gps"] + baud_rate_choices = ["9600", "19200", "38400", "57600", "115200"] hack_choices = [] if android_version=="11": - install_choices.extend(["widevine"]) + install_choices.extend(["widevine", ]) hack_choices.extend(["nodataperm", "hidestatusbar"]) if action == "Install": @@ -252,6 +258,20 @@ def interact(): default="Standard", ).execute() args.microg_variant = microg_variant + if "gps" in apps: + gps_host = inquirer.text( + message="Enter GPS host (default: /dev/ttyGPSD)", + default="/dev/ttyGPSD", + ).execute() + args.gps_host = gps_host + baud_rate = inquirer.select( + message="Enter baud rate (default: 9600)", + instruction="([\u2191\u2193]: [Enter]: Confirm", + default="9600", + choices=baud_rate_choices + ).execute() + args.baud_rate = baud_rate + args.app = apps install_app(args) elif action == "Remove": @@ -270,7 +290,7 @@ def interact(): 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", + invalid_message="should be at leinstall_appast 1 selection", choices=hack_choices ).execute() args.option_name = apps @@ -345,6 +365,8 @@ widevine: Add support for widevine DRM L3 args = parser.parse_args() args.microg_variant = "Standard" + args.gps_host = "/dev/ttyGPSD" + args.baud_rate = "9600" if hasattr(args, 'func'): args_dict = vars(args) helper.check_root() diff --git a/stuff/gps.py b/stuff/gps.py new file mode 100644 index 0000000..e6f8e81 --- /dev/null +++ b/stuff/gps.py @@ -0,0 +1,197 @@ +import os +from xml.dom import minidom +import xml.etree.ElementTree as ET +import shutil +from stuff.general import General +from tools.logger import Logger +import tools.images as images +from tools.helper import run, host +from tools import container + +class GPS(General): + id = "gps" + partition = "vendor" + dl_links = ["https://github.com/Lolmc0587/android_gps_libraries/archive/refs/tags/2.1.zip","f84c369c7cebd9dbb8987ca15c6aa856"] + act_md5 = ... + dl_link = ... + dl_file_name = "android_gps_libraries-2.1.zip" + extract_to = "/tmp/android_gps_libraries-2.1" + + files = [ + "lib/hw/android.hardware.gnss@1.0-impl.so", + "lib64/hw/android.hardware.gnss@1.0-impl.so", + "lib/hw/gps.default.so", + "lib64/hw/gps.default.so", + "etc/init/android.hardware.gnss@1.0-service.rc", + ] + + + def __init__(self, android_version="11", gps_host="/dev/ttyGPSD", baud_rate=9600) -> None: + super().__init__() + self.host_arch = host() + # Set for arm 32 bit support from file downloaded + self.host = "arm64-v8a" if "arm" in self.host_arch[0] else self.host_arch[0] + self.gps_host = gps_host + self.baud_rate = baud_rate + self.android_version = android_version + self.usb_name = self.gps_host.split("/")[-1] + self.files_vendor = [ + "bin/hw/android.hardware.gnss@1.0-service", + ] + self.config_files = { + "11": [ + "etc/vintf/compatibility_matrix.legacy.xml", + "etc/vintf/manifest.xml", + "build.prop", + ], + "13": [ + "etc/vintf/compatibility_matrix.7.xml", + "etc/vintf/manifest.xml", + "build.prop", + ], + } + + self.compatibility_files = { + "11": "etc/vintf/compatibility_matrix.legacy.xml", + "13": "etc/vintf/compatibility_matrix.7.xml", + } + + self.dl_link = self.dl_links[0] + self.act_md5 = self.dl_links[1] + + def update_manifest(self, manifest_path, data): + """ + Update the manifest file by inserting data into the tag and format the XML. + """ + tree = ET.parse(manifest_path) + root = tree.getroot() + + root.append(ET.fromstring(data)) + tree.write(manifest_path, encoding="utf-8", xml_declaration=True) + + with open(manifest_path, "r") as f: + content = f.read() + formatted_content = minidom.parseString(content).toprettyxml(indent=" ") + + formatted_content = "\n".join( + [line for line in formatted_content.split("\n") if line.strip()] + ) + + with open(manifest_path, "w") as f: + f.write(formatted_content) + + def copy(self): + Logger.info("Copying gps library files ...") + if self.android_version == "11": + shutil.copytree(os.path.join(self.extract_to, self.dl_file_name.replace(".zip", ""), self.android_version, + self.host, "system"), os.path.join(self.copy_dir, "system"), dirs_exist_ok=True) + self.partition = "system" + if self.android_version == "13": + shutil.copytree(os.path.join(self.extract_to, self.dl_file_name.replace(".zip", ""), self.android_version, + self.host, "system"), os.path.join(self.copy_dir, "vendor"), dirs_exist_ok=True) + self.partition = "vendor" + shutil.copytree(os.path.join(self.extract_to, self.dl_file_name.replace(".zip", ""), self.android_version, + self.host, "vendor"), os.path.join(self.copy_dir, "vendor"), dirs_exist_ok=True) + + def extra1(self): + Logger.info("Setting extra permissions ...") + # set permissions for vendor files + path = os.path.join(self.copy_dir, "vendor", self.files_vendor[0]) + self.set_perm2(path, recursive=True) + + # Copy nessessary files to the overlayfs + container.stop() + copy_dir = "/tmp/waydroid" + if container.use_overlayfs(): + img = os.path.join(images.get_image_dir(), "system.img") + # images.mount(img, copy_dir) + if not os.path.exists(copy_dir): + os.makedirs(copy_dir) + run(["sudo", "mount", img, copy_dir]) + + for file in self.config_files[self.android_version]: + file_dir = os.path.join(self.copy_dir, "system", file) + if not os.path.exists(os.path.dirname(file_dir)): + os.makedirs(os.path.dirname(file_dir)) + shutil.copyfile(os.path.join(copy_dir, "system", file), file_dir) + self.set_perm2(file_dir, recursive=True) + + if self.android_version == "13": + # Copy missing libraries file for android 13 vendor partition from system partition + if not os.path.exists(os.path.join(self.copy_dir, "vendor", "lib64", "hw")): + os.makedirs(os.path.join(self.copy_dir, "vendor", "lib64", "hw")) + + copy_ = True + if "arm" in self.host and self.host_arch[1] == 32: + copy_ = False + if copy_: + shutil.copyfile(os.path.join(copy_dir, "system", "lib64/android.hardware.gnss@1.0.so"), + os.path.join(self.copy_dir, "vendor", "lib64/hw/android.hardware.gnss@1.0.so")) + + if not os.path.exists(os.path.join(self.copy_dir, "vendor", "lib", "hw")): + os.makedirs(os.path.join(self.copy_dir, "vendor", "lib", "hw")) + + shutil.copyfile(os.path.join(copy_dir, "system", "lib/android.hardware.gnss@1.0.so"), + os.path.join(self.copy_dir, "vendor", "lib/hw/android.hardware.gnss@1.0.so")) + + images.umount(copy_dir) + + # Update manifest files + container.upgrade() + + manifest_entry_1 = """ + + android.hardware.gnss + 1.0 + + IGnss + default + + + """ + self.update_manifest( + os.path.join(self.copy_dir, "system", self.compatibility_files[self.android_version]), + data=manifest_entry_1, + ) + + manifest_entry_2 = """ + + android.hardware.gnss + hwbinder + 1.0 + + IGnss + default + + @1.0::IGnss/default + + """ + self.update_manifest(os.path.join(self.copy_dir, "system", "etc", "vintf", "manifest.xml"), data=manifest_entry_2) + config_nodes = "/var/lib/waydroid/lxc/waydroid/config_nodes" + # lxc.mount.entry = /dev/ttyGPSD dev/ttyGPSD none bind,create=file,optional 0 0 + + with open(config_nodes, "a") as f: + f.write(f"lxc.mount.entry = {self.gps_host} dev/{self.usb_name} none bind,create=file,optional 0 0\n") + + with open(os.path.join(self.copy_dir, "system", "build.prop"), "a") as f: + f.write("ro.factory.hasGPS=true\n") + f.write(f"ro.kernel.android.gps={self.usb_name}\n") + f.write(f"ro.kernel.android.gps.speed={self.baud_rate}\n") + Logger.warning( + "You need to add user to the 'dialout' group to access the GPS device." + "\nYou can do this by running: sudo usermod -aG dialout " + "\nand then reboot your system." + ) + def extra2(self): + # Remove vendor files from system partition + self.files = self.files_vendor + self.partition = "vendor" + self.remove() + + # Remove config files from system partition + self.files = self.config_files[self.android_version] + self.partition = "system" + self.remove() + + container.upgrade() +