├── .github └── workflows │ ├── clean.yml │ ├── magisk.yml │ └── schedule.yml ├── LICENSE ├── README.md ├── arm64 ├── gapps │ ├── priv-app │ │ └── SetupWizard │ │ │ └── SetupWizard.apk │ └── product │ │ └── overlay │ │ └── GoogleWebViewOverlay.apk └── system │ └── system │ ├── etc │ └── permissions │ │ └── android.software.device_admin.xml │ └── priv-app │ ├── VpnDialogs │ └── VpnDialogs.apk │ └── WSAHelper │ └── WSAHelper.apk ├── linker ├── libc.so ├── libdl.so ├── libm.so └── linker64 ├── wine ├── .cache │ └── winetricks │ │ └── msxml6 │ │ └── msxml6-KB973686-enu-amd64.exe └── makepri.exe ├── x64 ├── gapps │ ├── priv-app │ │ └── SetupWizard │ │ │ └── SetupWizard.apk │ └── product │ │ └── overlay │ │ └── GoogleWebViewOverlay.apk └── system │ └── system │ ├── etc │ └── permissions │ │ └── android.software.device_admin.xml │ └── priv-app │ ├── VpnDialogs │ └── VpnDialogs.apk │ └── WSAHelper │ └── WSAHelper.apk └── xml ├── FE3FileUrl.xml ├── GetCookie.xml └── WUIDRequest.xml /.github/workflows/clean.yml: -------------------------------------------------------------------------------- 1 | name: Delete old workflow runs 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | days: 6 | description: 'Number of days.' 7 | required: true 8 | default: 30 9 | minimum_runs: 10 | description: 'The minimum runs to keep for each workflow.' 11 | required: true 12 | default: 6 13 | delete_workflow_pattern: 14 | description: 'The name of the workflow. if not set then it will target all workflows.' 15 | required: false 16 | 17 | jobs: 18 | del_runs: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Delete workflow runs 22 | uses: Mattraks/delete-workflow-runs@v2 23 | with: 24 | token: ${{ github.token }} 25 | repository: ${{ github.repository }} 26 | retain_days: ${{ github.event.inputs.days }} 27 | keep_minimum_runs: ${{ github.event.inputs.minimum_runs }} 28 | delete_workflow_pattern: ${{ github.event.inputs.delete_workflow_pattern }} 29 | -------------------------------------------------------------------------------- /.github/workflows/magisk.yml: -------------------------------------------------------------------------------- 1 | name: Build WSA 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | arch: 6 | description: "Build arch" 7 | required: true 8 | default: "x64 & arm64" 9 | type: choice 10 | options: 11 | - x64 12 | - arm64 13 | - x64 & arm64 14 | release_type: 15 | description: "WSA release type" 16 | required: true 17 | default: "retail" 18 | type: choice 19 | options: 20 | - retail 21 | - release preview 22 | - insider slow 23 | - insider fast 24 | magisk_apk: 25 | description: "Magisk version" 26 | required: true 27 | default: "stable" 28 | type: choice 29 | options: 30 | - stable 31 | - beta 32 | - canary 33 | - debug 34 | gapps_variant: 35 | description: "Variants of gapps" 36 | required: true 37 | default: "pico" 38 | type: choice 39 | options: 40 | - none 41 | - super 42 | - stock 43 | - full 44 | - mini 45 | - micro 46 | - nano 47 | - pico 48 | - tvstock 49 | - tvmini 50 | remove_amazon: 51 | description: "Remove Amazon AppStore" 52 | required: true 53 | default: "keep" 54 | type: choice 55 | options: 56 | - keep 57 | - remove 58 | root_sol: 59 | description: "Root solution" 60 | required: true 61 | default: "magisk" 62 | type: choice 63 | options: 64 | - magisk 65 | - none 66 | 67 | jobs: 68 | matrix: 69 | runs-on: ubuntu-latest 70 | outputs: 71 | matrix: ${{ steps.set-matrix.outputs.matrix }} 72 | steps: 73 | - name: Generate build matrix 74 | id: set-matrix 75 | uses: actions/github-script@v6 76 | with: 77 | script: | 78 | let matrix = {}; 79 | let arch = "${{ github.event.inputs.arch }}" 80 | switch ( arch ) { 81 | case "x64": 82 | matrix.arch = ["x64"]; 83 | break; 84 | case "arm64": 85 | matrix.arch = ["arm64"]; 86 | break; 87 | default: 88 | matrix.arch = ["x64", "arm64"]; 89 | break; 90 | } 91 | core.setOutput("matrix",JSON.stringify(matrix)); 92 | 93 | build: 94 | runs-on: ubuntu-20.04 95 | needs: matrix 96 | strategy: 97 | matrix: ${{fromJson(needs.matrix.outputs.matrix)}} 98 | steps: 99 | - name: Dependencies 100 | run: | 101 | sudo apt-get update && sudo apt-get install setools lzip wine winetricks patchelf 102 | wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- -C ~ --strip-component=2 '*/wine/*' '*/linker/*' '*/xml/*' 103 | winetricks msxml6 104 | - name: Download WSA 105 | shell: python 106 | run: | 107 | import requests 108 | from xml.dom import minidom 109 | import html 110 | import warnings 111 | import re 112 | import zipfile 113 | import os 114 | import urllib.request 115 | from pathlib import Path 116 | 117 | warnings.filterwarnings("ignore") 118 | 119 | arch = "${{ matrix.arch }}" 120 | release_type_map = {"retail": "Retail", "release preview": "RP", "insider slow": "WIS", "insider fast": "WIF"} 121 | release_type = release_type_map["${{ github.event.inputs.release_type }}"] if "${{ github.event.inputs.release_type }}" != "" else "Retail" 122 | 123 | cat_id = '858014f3-3934-4abe-8078-4aa193e74ca8' 124 | 125 | with open(Path.home() / "GetCookie.xml", "r") as f: 126 | cookie_content = f.read() 127 | 128 | out = requests.post( 129 | 'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx', 130 | data=cookie_content, 131 | headers={'Content-Type': 'application/soap+xml; charset=utf-8'}, 132 | verify=False 133 | ) 134 | doc = minidom.parseString(out.text) 135 | cookie = doc.getElementsByTagName('EncryptedData')[0].firstChild.nodeValue 136 | 137 | print(cookie) 138 | 139 | with open(Path.home() / "WUIDRequest.xml", "r") as f: 140 | cat_id_content = f.read().format(cookie, cat_id, release_type) 141 | 142 | out = requests.post( 143 | 'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx', 144 | data=cat_id_content, 145 | headers={'Content-Type': 'application/soap+xml; charset=utf-8'}, 146 | verify=False 147 | ) 148 | 149 | doc = minidom.parseString(html.unescape(out.text)) 150 | 151 | filenames = {} 152 | for node in doc.getElementsByTagName('Files'): 153 | filenames[node.parentNode.parentNode.getElementsByTagName('ID')[0].firstChild.nodeValue] = f"{node.firstChild.attributes['InstallerSpecificIdentifier'].value}_{node.firstChild.attributes['FileName'].value}" 154 | pass 155 | 156 | identities = [] 157 | for node in doc.getElementsByTagName('SecuredFragment'): 158 | filename = filenames[node.parentNode.parentNode.parentNode.getElementsByTagName('ID')[0].firstChild.nodeValue] 159 | update_identity = node.parentNode.parentNode.firstChild 160 | identities += [(update_identity.attributes['UpdateID'].value, update_identity.attributes['RevisionNumber'].value, filename)] 161 | 162 | with open(Path.home() / "FE3FileUrl.xml", "r") as f: 163 | file_content = f.read() 164 | 165 | for i, v, f in identities: 166 | if re.match(f"Microsoft\.UI\.Xaml\..*_{arch}_.*\.appx", f): 167 | out_file = "xaml.appx" 168 | elif re.match(f"Microsoft\.VCLibs\..*_{arch}_.*\.appx", f): 169 | out_file = "vclibs.appx" 170 | elif re.match(f"MicrosoftCorporationII\.WindowsSubsystemForAndroid_.*\.msixbundle", f): 171 | out_file = "wsa.zip" 172 | else: 173 | continue 174 | out = requests.post( 175 | 'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured', 176 | data=file_content.format(i, v, release_type), 177 | headers={'Content-Type': 'application/soap+xml; charset=utf-8'}, 178 | verify=False 179 | ) 180 | doc = minidom.parseString(out.text) 181 | for l in doc.getElementsByTagName("FileLocation"): 182 | url = l.getElementsByTagName("Url")[0].firstChild.nodeValue 183 | if len(url) != 99: 184 | if not os.path.isfile(out_file): 185 | print(f"downloading link: {url} to {out_file}", flush=True) 186 | urllib.request.urlretrieve(url, out_file) 187 | 188 | zip_name = "" 189 | with zipfile.ZipFile("wsa.zip") as zip: 190 | for f in zip.filelist: 191 | if arch in f.filename.lower(): 192 | zip_name = f.filename 193 | if not os.path.isfile(zip_name): 194 | print(f"unzipping to {zip_name}", flush=True) 195 | zip.extract(f) 196 | ver_no = zip_name.split("_") 197 | long_ver = ver_no[1] 198 | ver=long_ver.split(".") 199 | main_ver=ver[0] 200 | with open(os.environ['GITHUB_ENV'], 'a') as g: 201 | g.write(f'WSA_VER={long_ver}\n') 202 | with open(os.environ['GITHUB_ENV'], 'a') as g: 203 | g.write(f'WSA_MAIN_VER={main_ver}\n') 204 | rel = ver_no[3].split(".") 205 | rell = str(rel[0]) 206 | with open(os.environ['GITHUB_ENV'], 'a') as g: 207 | g.write(f'WSA_REL={rell}\n') 208 | if 'language' in f.filename.lower() or 'scale' in f.filename.lower(): 209 | name = f.filename.split("-", 1)[1].split(".")[0] 210 | zip.extract(f) 211 | with zipfile.ZipFile(f.filename) as l: 212 | for g in l.filelist: 213 | if g.filename == 'resources.pri': 214 | g.filename = f'{name}.pri' 215 | l.extract(g, 'pri') 216 | print(f"extract resource pack {g.filename}") 217 | elif g.filename == 'AppxManifest.xml': 218 | g.filename = f'{name}.xml' 219 | l.extract(g, 'xml') 220 | 221 | with zipfile.ZipFile(zip_name) as zip: 222 | if not os.path.isdir(arch): 223 | print(f"unzipping from {zip_name}", flush=True) 224 | zip.extractall(arch) 225 | 226 | print("done", flush=True) 227 | - name: Download Magisk 228 | shell: python 229 | run: | 230 | import urllib.request 231 | import zipfile 232 | import os 233 | import json 234 | import requests 235 | 236 | magisk_apk = """${{ github.event.inputs.magisk_apk }}""" 237 | 238 | if not magisk_apk: 239 | magisk_apk = "stable" 240 | if magisk_apk == "stable" or magisk_apk == "beta" or magisk_apk == "canary" or magisk_apk == "debug": 241 | magisk_apk = json.loads(requests.get(f"https://github.com/topjohnwu/magisk-files/raw/master/{magisk_apk}.json").content)['magisk']['link'] 242 | 243 | out_file = "magisk.zip" 244 | 245 | arch = "${{ matrix.arch }}" 246 | 247 | abi_map={"x64" : ["x86_64", "x86"], "arm64" : ["arm64-v8a", "armeabi-v7a"]} 248 | 249 | if not os.path.isfile(out_file): 250 | urllib.request.urlretrieve(magisk_apk, out_file) 251 | 252 | def extract_as(zip, name, as_name, dir): 253 | info = zip.getinfo(name) 254 | info.filename = as_name 255 | zip.extract(info, dir) 256 | 257 | with zipfile.ZipFile(out_file) as zip: 258 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagisk64.so", "magisk64", "magisk") 259 | extract_as(zip, f"lib/{ abi_map[arch][1] }/libmagisk32.so", "magisk32", "magisk") 260 | standalone_policy = False 261 | try: 262 | zip.getinfo(f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so") 263 | standalone_policy = True 264 | except: 265 | pass 266 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskinit", "magisk") 267 | if standalone_policy: 268 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so", "magiskpolicy", "magisk") 269 | else: 270 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskpolicy", "magisk") 271 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskboot.so", "magiskboot", "magisk") 272 | extract_as(zip, f"lib/{ abi_map[arch][0] }/libbusybox.so", "busybox", "magisk") 273 | if standalone_policy: 274 | extract_as(zip, f"lib/{ abi_map['x64'][0] }/libmagiskpolicy.so", "magiskpolicy", ".") 275 | else: 276 | extract_as(zip, f"lib/{ abi_map['x64'][0] }/libmagiskinit.so", "magiskpolicy", ".") 277 | extract_as(zip, f"assets/boot_patch.sh", "boot_patch.sh", "magisk") 278 | extract_as(zip, f"assets/util_functions.sh", "util_functions.sh", "magisk") 279 | - name: Download OpenGApps 280 | if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} 281 | shell: python 282 | run: | 283 | import requests 284 | import zipfile 285 | import os 286 | import urllib.request 287 | import json 288 | import re 289 | 290 | arch = "${{ matrix.arch }}" 291 | # TODO: if it's an Android 12.1 base WSA keep it pico since other variants of opengapps are unable to boot successfully 292 | variant = "${{ github.event.inputs.gapps_variant }}" if int("${{ env.WSA_MAIN_VER }}") < 2204 else "pico" 293 | abi_map = {"x64" : "x86_64", "arm64": "arm64"} 294 | # TODO: keep it 11.0 since opengapps does not support 12+ yet 295 | # As soon as opengapps is available for 12+, we need to get the sdk/release from build.prop and 296 | # download the corresponding version 297 | release = "11.0" 298 | try: 299 | res = requests.get(f"https://api.opengapps.org/list") 300 | j = json.loads(res.content) 301 | link = {i["name"]: i for i in j["archs"][abi_map[arch]]["apis"][release]["variants"]}[variant]["zip"] 302 | except Exception: 303 | print("Failed to fetch from opengapps api, fallbacking to sourceforge rss...") 304 | res = requests.get(f'https://sourceforge.net/projects/opengapps/rss?path=/{abi_map[arch]}&limit=100') 305 | link = re.search(f'https://.*{abi_map[arch]}/.*{release}.*{variant}.*\.zip/download', res.text).group().replace('.zip/download', '.zip').replace('sourceforge.net/projects/opengapps/files', 'downloads.sourceforge.net/project/opengapps') 306 | 307 | print(f"downloading link: {link}", flush=True) 308 | 309 | out_file = "gapps.zip" 310 | 311 | if not os.path.isfile(out_file): 312 | urllib.request.urlretrieve(link, out_file) 313 | print("done", flush=True) 314 | 315 | - name: Extract GApps 316 | if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} 317 | run: | 318 | mkdir gapps 319 | unzip -p gapps.zip {Core,GApps}/'*.lz' | tar --lzip -C gapps -xvf - -i --strip-components=2 --exclude='setupwizardtablet-x86_64' --exclude='packageinstallergoogle-all' --exclude='speech-common' --exclude='markup-lib-arm' --exclude='markup-lib-arm64' --exclude='markup-all' --exclude='setupwizarddefault-x86_64' --exclude='pixellauncher-all' --exclude='pixellauncher-common' 320 | 321 | - name: Expand images 322 | run: | 323 | e2fsck -yf ${{ matrix.arch }}/system_ext.img 324 | system_ext_size=$(( $(du -sB512 ${{ matrix.arch }}/system_ext.img | cut -f1) + 20000 )) 325 | resize2fs ${{ matrix.arch }}/system_ext.img "$system_ext_size"s 326 | e2fsck -yf ${{ matrix.arch }}/product.img 327 | product_size=$(( $(du -sB512 ${{ matrix.arch }}/product.img | cut -f1) + 20000 )) 328 | if [ -d gapps/product ]; then 329 | product_size=$(( $product_size + $(du -sB512 gapps/product | cut -f1) )) 330 | fi 331 | resize2fs ${{ matrix.arch }}/product.img "$product_size"s 332 | e2fsck -yf ${{ matrix.arch }}/system.img 333 | system_size=$(( $(du -sB512 ${{ matrix.arch }}/system.img | cut -f1) + 20000 )) 334 | if [ -d gapps ]; then 335 | system_size=$(( $system_size + $(du -sB512 gapps | cut -f1) - $(du -sB512 gapps/product | cut -f1) )) 336 | fi 337 | if [ -d magisk ]; then 338 | system_size=$(( $system_size +$(du -sB512 magisk | cut -f1) )) 339 | fi 340 | if [ -f magisk.zip ]; then 341 | system_size=$(( $system_size +$(du -sB512 magisk.zip | cut -f1) )) 342 | fi 343 | resize2fs ${{ matrix.arch }}/system.img "$system_size"s 344 | e2fsck -yf ${{ matrix.arch }}/vendor.img 345 | vendor_size=$(( $(du -sB512 ${{ matrix.arch }}/vendor.img | cut -f1) + 20000 )) 346 | resize2fs ${{ matrix.arch }}/vendor.img "$vendor_size"s 347 | - name: Mount images 348 | run: | 349 | sudo mkdir system 350 | sudo mount -o loop ${{ matrix.arch }}/system.img system 351 | sudo mount -o loop ${{ matrix.arch }}/vendor.img system/vendor 352 | sudo mount -o loop ${{ matrix.arch }}/product.img system/product 353 | sudo mount -o loop ${{ matrix.arch }}/system_ext.img system/system_ext 354 | - name: Remove Amazon AppStore 355 | if: ${{ github.event.inputs.remove_amazon == 'remove' }} 356 | run: | 357 | find system/product/{etc/permissions,etc/sysconfig,framework,priv-app} | grep -e amazon -e venezia | sudo xargs rm -rf 358 | - name: Integrate Magisk 359 | if: ${{ github.event.inputs.root_sol == 'magisk' || github.event.inputs.root_sol == '' }} 360 | run: | 361 | sudo mkdir system/sbin 362 | sudo chcon --reference system/init.environ.rc system/sbin 363 | sudo chown root:root system/sbin 364 | sudo chmod 0700 system/sbin 365 | sudo cp magisk/* system/sbin/ 366 | sudo cp magisk.zip system/sbin/magisk.apk 367 | sudo tee -a system/sbin/loadpolicy.sh < 450 | 451 | 452 | 453 | 454 | 455 | 456 | EOF 457 | wine64 ~/makepri.exe new /pr pri /in MicrosoftCorporationII.WindowsSubsystemForAndroid /cf priconfig.xml /of ${{ matrix.arch }}/resources.pri /o 458 | sed -i -zE "s//\n$(cat xml/* | grep -Po ']*/>' | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/\$/\\$/g' | sed 's/\//\\\//g')\n<\/Resources>/g" ${{ matrix.arch }}/AppxManifest.xml 459 | - name: Add extra packages 460 | run: | 461 | wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- --strip-component=2 '*/${{ matrix.arch }}/system/*' 462 | sudo find system/system/priv-app -type d -exec chmod 0755 {} \; 463 | sudo find system/system/priv-app -type f -exec chmod 0644 {} \; 464 | sudo find system/system/priv-app -exec chcon --reference=system/system/priv-app {} \; 465 | - name: Integrate GApps 466 | if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} 467 | run: | 468 | wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- --strip-component=2 '*/${{ matrix.arch }}/gapps/*' 469 | shopt -s extglob 470 | sudo cp -vr gapps/!(product) system/system 471 | sudo cp -vr gapps/product/* system/product/ 472 | 473 | sudo find system/system/{app,etc,framework,priv-app} -exec chown root:root {} \; 474 | sudo find system/product/{app,etc,overlay,priv-app} -exec chown root:root {} \; 475 | 476 | sudo find system/system/{app,etc,framework,priv-app} -type d -exec chmod 0755 {} \; 477 | sudo find system/product/{app,etc,overlay,priv-app} -type d -exec chmod 0755 {} \; 478 | 479 | sudo find system/system/{app,framework,priv-app} -type f -exec chmod 0644 {} \; 480 | ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type f -exec chmod 0644 {} \; 481 | sudo find system/product/{app,etc,overlay,priv-app} -type f -exec chmod 0644 {} \; 482 | 483 | sudo find system/system/{app,framework,priv-app} -type d -exec chcon --reference=system/system/app {} \; 484 | sudo find system/product/{app,etc,overlay,priv-app} -type d -exec chcon --reference=system/product/app {} \; 485 | ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type d -exec chcon --reference=system/system/etc/permissions {} \; 486 | 487 | sudo find system/system/{app,framework,priv-app} -type f -exec chcon --reference=system/system/framework/ext.jar {} \; 488 | ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type f -exec chcon --reference=system/system/etc/permissions {} \; 489 | sudo find system/product/{app,etc,overlay,priv-app} -type f -exec chcon --reference=system/product/etc/permissions/com.android.settings.intelligence.xml {} \; 490 | sudo patchelf --replace-needed libc.so "${HOME}/libc.so" ./magiskpolicy || true 491 | sudo patchelf --replace-needed libm.so "${HOME}/libm.so" ./magiskpolicy || true 492 | sudo patchelf --replace-needed libdl.so "${HOME}/libdl.so" ./magiskpolicy || true 493 | sudo patchelf --set-interpreter "${HOME}/linker64" ./magiskpolicy || true 494 | chmod +x ./magiskpolicy 495 | sudo ./magiskpolicy --load system/vendor/etc/selinux/precompiled_sepolicy --save system/vendor/etc/selinux/precompiled_sepolicy "allow gmscore_app gmscore_app vsock_socket { create connect write read }" "allow gmscore_app device_config_runtime_native_boot_prop file read" "allow gmscore_app system_server_tmpfs dir search" "allow gmscore_app system_server_tmpfs file open" 496 | - name: Fix GApps prop 497 | if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} 498 | shell: sudo python {0} 499 | run: | 500 | from __future__ import annotations 501 | from io import TextIOWrapper 502 | from os import system, path 503 | from typing import OrderedDict 504 | 505 | 506 | class Prop(OrderedDict): 507 | def __init__(self, file: TextIOWrapper) -> None: 508 | super().__init__() 509 | for i, line in enumerate(file.read().splitlines(False)): 510 | if '=' in line: 511 | k, v = line.split('=', 2) 512 | self[k] = v 513 | else: 514 | self[f".{i}"] = line 515 | 516 | def __str__(self) -> str: 517 | return '\n'.join([v if k.startswith('.') else f"{k}={v}" for k, v in self.items()]) 518 | 519 | def __iadd__(self, other: str) -> Prop: 520 | self[f".{len(self)}"] = other 521 | return self 522 | 523 | 524 | new_props = { 525 | ("product", "brand"): "google", 526 | ("product", "manufacturer"): "Google", 527 | ("build", "product"): "redfin", 528 | ("product", "name"): "redfin", 529 | ("product", "device"): "redfin", 530 | ("product", "model"): "Pixel 5", 531 | ("build", "flavor"): "redfin-user" 532 | } 533 | 534 | 535 | def description(sec: str, p: Prop) -> str: 536 | return f"{p[f'ro.{sec}.build.flavor']} {p[f'ro.{sec}.build.version.release_or_codename']} {p[f'ro.{sec}.build.id']} {p[f'ro.{sec}.build.version.incremental']} {p[f'ro.{sec}.build.tags']}" 537 | 538 | 539 | def fingerprint(sec: str, p: Prop) -> str: 540 | return f"""{p[f"ro.product.{sec}.brand"]}/{p[f"ro.product.{sec}.name"]}/{p[f"ro.product.{sec}.device"]}:{p[f"ro.{sec}.build.version.release"]}/{p[f"ro.{sec}.build.id"]}/{p[f"ro.{sec}.build.version.incremental"]}:{p[f"ro.{sec}.build.type"]}/{p[f"ro.{sec}.build.tags"]}""" 541 | 542 | 543 | def fix_prop(sec, prop): 544 | if not path.exists(prop): 545 | return 546 | 547 | print(f"fixing {prop}", flush=True) 548 | with open(prop, 'r') as f: 549 | p = Prop(f) 550 | 551 | p += "# extra prop added by MagiskOnWSA" 552 | 553 | for k, v in new_props.items(): 554 | p[f"ro.{k[0]}.{k[1]}"] = v 555 | 556 | if k[0] == "build": 557 | p[f"ro.{sec}.{k[0]}.{k[1]}"] = v 558 | elif k[0] == "product": 559 | p[f"ro.{k[0]}.{sec}.{k[1]}"] = v 560 | 561 | p["ro.build.description"] = description(sec, p) 562 | p[f"ro.build.fingerprint"] = fingerprint(sec, p) 563 | p[f"ro.{sec}.build.description"] = description(sec, p) 564 | p[f"ro.{sec}.build.fingerprint"] = fingerprint(sec, p) 565 | p[f"ro.bootimage.build.fingerprint"] = fingerprint(sec, p) 566 | 567 | with open(prop, 'w') as f: 568 | f.write(str(p)) 569 | 570 | for sec, prop in {"system": "system/system/build.prop", "product": "system/product/build.prop", "system_ext": "system/system_ext/build.prop", "vendor": "system/vendor/build.prop", "odm": "system/vendor/odm/etc/build.prop"}.items(): 571 | fix_prop(sec, prop) 572 | - name: Umount images 573 | run: | 574 | sudo find system -exec touch -amt 200901010000.00 {} \;> /dev/null 2>&1 575 | sudo umount system/vendor 576 | sudo umount system/product 577 | sudo umount system/system_ext 578 | sudo umount system 579 | - name: Shrink images 580 | run: | 581 | e2fsck -yf ${{ matrix.arch }}/system.img 582 | resize2fs -M ${{ matrix.arch }}/system.img 583 | e2fsck -yf ${{ matrix.arch }}/vendor.img 584 | resize2fs -M ${{ matrix.arch }}/vendor.img 585 | e2fsck -yf ${{ matrix.arch }}/product.img 586 | resize2fs -M ${{ matrix.arch }}/product.img 587 | e2fsck -yf ${{ matrix.arch }}/system_ext.img 588 | resize2fs -M ${{ matrix.arch }}/system_ext.img 589 | - name: Remove signature and add scripts 590 | run: | 591 | rm -rf ${{ matrix.arch }}/\[Content_Types\].xml ${{ matrix.arch }}/AppxBlockMap.xml ${{ matrix.arch }}/AppxSignature.p7x ${{ matrix.arch }}/AppxMetadata 592 | cp vclibs.appx xaml.appx ${{ matrix.arch }} 593 | tee ${{ matrix.arch }}/Install.ps1 <