name: Magisk on: push: pull_request: workflow_dispatch: inputs: magisk_apk: description: 'Download link to magisk apk.' required: true default: 'https://raw.githubusercontent.com/LSPosed/MagiskOnWSA/main/magisk.apk' gapps_variant: description: 'Variants of gapps. Should be: [none, aroma, super, stock, full, mini, micro, nano, pico, tvstock, tvmini]' required: true default: 'none' jobs: build: runs-on: ubuntu-20.04 strategy: matrix: arch: [x64, arm64] steps: - name: Dependencies run: | pip3 install beautifulsoup4 lxml sudo apt-get update && sudo apt-get install setools lzip - name: Download AWS shell: python run: | import requests from bs4 import BeautifulSoup import re import zipfile import os import urllib.request res = requests.post("https://store.rg-adguard.net/api/GetFiles", "type=CategoryId&url=858014f3-3934-4abe-8078-4aa193e74ca8&ring=WIS&lang=en-US", headers={ "content-type": "application/x-www-form-urlencoded" }) html = BeautifulSoup(res.content, "lxml") a = html.find("a", string=re.compile("MicrosoftCorporationII\.WindowsSubsystemForAndroid_.*\.msixbundle")) link = a["href"] print(f"downloading link: {link}", flush=True) out_file = "wsa.zip" arch = "${{ matrix.arch }}" if not os.path.isfile(out_file): urllib.request.urlretrieve(link, out_file) zip_name = "" with zipfile.ZipFile(out_file) as zip: for f in zip.filelist: if arch in f.filename.lower(): zip_name = f.filename if not os.path.isfile(zip_name): print(f"unzipping to {zip_name}", flush=True) zip.extract(f) break with zipfile.ZipFile(zip_name) as zip: if not os.path.isdir(arch): print(f"unzipping from {zip_name}", flush=True) zip.extractall(arch) print("done", flush=True) - name: Download Magisk shell: python run: | import urllib.request import zipfile import os magisk_apk = """${{ github.event.inputs.magisk_apk }}""" if not magisk_apk: magisk_apk = """https://raw.githubusercontent.com/LSPosed/MagiskOnWSA/main/magisk.apk""" out_file = "magisk.zip" arch = "${{ matrix.arch }}" abi_map={"x64" : ["x86_64", "x86"], "arm64" : ["arm64-v8a", "armeabi-v7a"]} if not os.path.isfile(out_file): urllib.request.urlretrieve(magisk_apk, out_file) def extract_as(zip, name, as_name, dir): info = zip.getinfo(name) info.filename = as_name zip.extract(info, dir) with zipfile.ZipFile(out_file) as zip: extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagisk64.so", "magisk64", "magisk") extract_as(zip, f"lib/{ abi_map[arch][1] }/libmagisk32.so", "magisk32", "magisk") extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskinit", "magisk") extract_as(zip, f"lib/{ abi_map['x64'][0] }/libmagiskinit.so", "magiskpolicy", "magisk") - name: Download OpenGApps if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} shell: python run: | import requests import zipfile import os import urllib.request import json arch = "${{ matrix.arch }}" variant = "${{ github.event.inputs.gapps_variant }}" abi_map = {"x64" : "x86_64", "arm64": "arm64"} res = requests.get(f"https://api.opengapps.org/list") j = json.loads(res.content) link = {i["name"]: i for i in j["archs"][abi_map[arch]]["apis"]["11.0"]["variants"]}[variant]["zip"] print(f"downloading link: {link}", flush=True) out_file = "gapps.zip" if not os.path.isfile(out_file): urllib.request.urlretrieve(link, out_file) print("done", flush=True) - name: Extract GApps and expand images if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }} run: | mkdir gapps 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-all' e2fsck -yf ${{ matrix.arch }}/system.img resize2fs ${{ matrix.arch }}/system.img $(( $(du -sB512 gapps | cut -f1) + $(du -sB512 ${{ matrix.arch }}/system.img | cut -f1) ))s e2fsck -yf ${{ matrix.arch }}/product.img resize2fs ${{ matrix.arch }}/product.img 1024M e2fsck -yf ${{ matrix.arch }}/system_ext.img resize2fs ${{ matrix.arch }}/system_ext.img 108M - name: Expand vendor run: | e2fsck -yf ${{ matrix.arch }}/vendor.img resize2fs ${{ matrix.arch }}/vendor.img 320M - name: Mount images run: | sudo mkdir system sudo mount -o loop ${{ matrix.arch }}/system.img system sudo mount -o loop ${{ matrix.arch }}/vendor.img system/vendor sudo mount -o loop ${{ matrix.arch }}/product.img system/product sudo mount -o loop ${{ matrix.arch }}/system_ext.img system/system_ext - name: Integrate Magisk run: | sudo mkdir system/sbin sudo chcon --reference system/init.environ.rc system/sbin sudo chown root:root system/sbin sudo chmod 0700 system/sbin sudo cp magisk/* system/sbin/ sudo find system/sbin -type f -exec chmod 0755 {} \; sudo find system/sbin -type f -exec chown root:root {} \; sudo find system/sbin -type f -exec chcon --reference system/product {} \; chmod +x magisk/magiskpolicy echo '/dev/wsa-magisk(/.*)? u:object_r:magisk_file:s0' | sudo tee -a system/vendor/etc/selinux/vendor_file_contexts sudo ./magisk/magiskpolicy --load system/vendor/etc/selinux/precompiled_sepolicy --save system/vendor/etc/selinux/precompiled_sepolicy --magisk "allow * magisk_file lnk_file *" sudo tee -a system/system/etc/init/hw/init.rc < None: super().__init__() for i, line in enumerate(file.read().splitlines(False)): if '=' in line: k, v = line.split('=', 2) self[k] = v else: self[f".{i}"] = line def __str__(self) -> str: return '\n'.join([v if k.startswith('.') else f"{k}={v}" for k, v in self.items()]) def __iadd__(self, other: str) -> Prop: self[f".{len(self)}"] = other return self new_props = { ("product", "brand"): "google", ("product", "manufacturer"): "Google", ("build", "product"): "redfin", ("product", "name"): "redfin", ("product", "device"): "redfin", ("product", "model"): "Pixel 5", ("build", "flavor"): "redfin-user" } def description(sec: str, p: Prop) -> str: 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']}" def fingerprint(sec: str, p: Prop) -> str: 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"]}""" def fix_prop(sec, prop): print(f"fixing {prop}", flush=True) with open(prop, 'r') as f: p = Prop(f) p += "# extra prop added by MagiskOnWSA" for k, v in new_props.items(): p[f"ro.{k[0]}.{k[1]}"] = v if k[0] == "build": p[f"ro.{sec}.{k[0]}.{k[1]}"] = v elif k[0] == "product": p[f"ro.{k[0]}.{sec}.{k[1]}"] = v p["ro.build.description"] = description(sec, p) p[f"ro.build.fingerprint"] = fingerprint(sec, p) p[f"ro.{sec}.build.description"] = description(sec, p) p[f"ro.{sec}.build.fingerprint"] = fingerprint(sec, p) p[f"ro.bootimage.build.fingerprint"] = fingerprint(sec, p) with open(prop, 'w') as f: f.write(str(p)) 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(): fix_prop(sec, prop) - name: Umount images run: | sudo umount system/vendor sudo umount system/product sudo umount system/system_ext sudo umount system - name: Shrink images run: | e2fsck -yf ${{ matrix.arch }}/system.img resize2fs -M ${{ matrix.arch }}/system.img e2fsck -yf ${{ matrix.arch }}/vendor.img resize2fs -M ${{ matrix.arch }}/vendor.img e2fsck -yf ${{ matrix.arch }}/product.img resize2fs -M ${{ matrix.arch }}/product.img e2fsck -yf ${{ matrix.arch }}/system_ext.img resize2fs -M ${{ matrix.arch }}/system_ext.img - name: Remove signature run: | rm -rf ${{ matrix.arch }}/\[Content_Types\].xml ${{ matrix.arch }}/AppxBlockMap.xml ${{ matrix.arch }}/AppxSignature.p7x ${{ matrix.arch }}/AppxMetadata - name: Generate artifact name run: | variant="${{ github.event.inputs.gapps_variant }}" if [[ "$variant" = "none" || "$variant" = "" ]]; then echo "artifact_name=WSA-with-Magisk-NoGApps_${{ matrix.arch }}" >> $GITHUB_ENV else echo "artifact_name=WSA-with-Magisk-GApps-${variant}_${{ matrix.arch }}" >> $GITHUB_ENV fi - name: Upload WSA uses: actions/upload-artifact@v2 with: name: ${{ env.artifact_name }} path: './${{ matrix.arch }}/*'