All work done in local host.

Remove Action.
This commit is contained in:
Howard20181 2022-08-14 10:43:35 +08:00
parent 79f2d86677
commit 555c643c2f
11 changed files with 790 additions and 751 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
* text eol=lf
*.exe binary

View File

@ -1,718 +0,0 @@
name: Build WSA
on:
workflow_dispatch:
inputs:
arch:
description: "Build arch"
required: true
default: "x64 & arm64"
type: choice
options:
- x64
- arm64
- x64 & arm64
release_type:
description: "WSA release type"
required: true
default: "retail"
type: choice
options:
- retail
- release preview
- insider slow
- insider fast
magisk_apk:
description: "Magisk version"
required: true
default: "stable"
type: choice
options:
- stable
- beta
- canary
- debug
gapps_variant:
description: "Variants of gapps"
required: true
default: "none"
type: choice
options:
- none
- super
- stock
- full
- mini
- micro
- nano
- pico
- tvstock
- tvmini
remove_amazon:
description: "Remove Amazon AppStore"
required: true
default: "keep"
type: choice
options:
- keep
- remove
root_sol:
description: "Root solution"
required: true
default: "magisk"
type: choice
options:
- magisk
- none
jobs:
matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Generate build matrix
id: set-matrix
uses: actions/github-script@v6
with:
script: |
let matrix = {};
let arch = "${{ github.event.inputs.arch }}"
switch ( arch ) {
case "x64":
matrix.arch = ["x64"];
break;
case "arm64":
matrix.arch = ["arm64"];
break;
default:
matrix.arch = ["x64", "arm64"];
break;
}
core.setOutput("matrix",JSON.stringify(matrix));
build:
runs-on: ubuntu-20.04
needs: matrix
strategy:
matrix: ${{fromJson(needs.matrix.outputs.matrix)}}
steps:
- name: Dependencies
run: |
sudo apt-get update && sudo apt-get install setools lzip wine winetricks patchelf
wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- -C ~ --strip-component=2 '*/wine/*' '*/linker/*' '*/xml/*'
winetricks msxml6
- name: Download WSA
shell: python
run: |
import requests
from xml.dom import minidom
import html
import warnings
import re
import zipfile
import os
import urllib.request
from pathlib import Path
warnings.filterwarnings("ignore")
arch = "${{ matrix.arch }}"
release_type_map = {"retail": "Retail", "release preview": "RP", "insider slow": "WIS", "insider fast": "WIF"}
release_type = release_type_map["${{ github.event.inputs.release_type }}"] if "${{ github.event.inputs.release_type }}" != "" else "Retail"
cat_id = '858014f3-3934-4abe-8078-4aa193e74ca8'
with open(Path.home() / "GetCookie.xml", "r") as f:
cookie_content = f.read()
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cookie_content,
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(out.text)
cookie = doc.getElementsByTagName('EncryptedData')[0].firstChild.nodeValue
print(cookie)
with open(Path.home() / "WUIDRequest.xml", "r") as f:
cat_id_content = f.read().format(cookie, cat_id, release_type)
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cat_id_content,
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(html.unescape(out.text))
filenames = {}
for node in doc.getElementsByTagName('Files'):
filenames[node.parentNode.parentNode.getElementsByTagName('ID')[0].firstChild.nodeValue] = f"{node.firstChild.attributes['InstallerSpecificIdentifier'].value}_{node.firstChild.attributes['FileName'].value}"
pass
identities = []
for node in doc.getElementsByTagName('SecuredFragment'):
filename = filenames[node.parentNode.parentNode.parentNode.getElementsByTagName('ID')[0].firstChild.nodeValue]
update_identity = node.parentNode.parentNode.firstChild
identities += [(update_identity.attributes['UpdateID'].value, update_identity.attributes['RevisionNumber'].value, filename)]
with open(Path.home() / "FE3FileUrl.xml", "r") as f:
file_content = f.read()
for i, v, f in identities:
if re.match(f"Microsoft\.UI\.Xaml\..*_{arch}_.*\.appx", f):
out_file = "xaml.appx"
elif re.match(f"Microsoft\.VCLibs\..*_{arch}_.*\.appx", f):
out_file = "vclibs.appx"
elif re.match(f"MicrosoftCorporationII\.WindowsSubsystemForAndroid_.*\.msixbundle", f):
out_file = "wsa.zip"
else:
continue
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured',
data=file_content.format(i, v, release_type),
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(out.text)
for l in doc.getElementsByTagName("FileLocation"):
url = l.getElementsByTagName("Url")[0].firstChild.nodeValue
if len(url) != 99:
if not os.path.isfile(out_file):
print(f"downloading link: {url} to {out_file}", flush=True)
urllib.request.urlretrieve(url, out_file)
zip_name = ""
with zipfile.ZipFile("wsa.zip") 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)
ver_no = zip_name.split("_")
long_ver = ver_no[1]
ver=long_ver.split(".")
main_ver=ver[0]
with open(os.environ['GITHUB_ENV'], 'a') as g:
g.write(f'WSA_VER={long_ver}\n')
with open(os.environ['GITHUB_ENV'], 'a') as g:
g.write(f'WSA_MAIN_VER={main_ver}\n')
rel = ver_no[3].split(".")
rell = str(rel[0])
with open(os.environ['GITHUB_ENV'], 'a') as g:
g.write(f'WSA_REL={rell}\n')
if 'language' in f.filename.lower() or 'scale' in f.filename.lower():
name = f.filename.split("-", 1)[1].split(".")[0]
zip.extract(f)
with zipfile.ZipFile(f.filename) as l:
for g in l.filelist:
if g.filename == 'resources.pri':
g.filename = f'{name}.pri'
l.extract(g, 'pri')
print(f"extract resource pack {g.filename}")
elif g.filename == 'AppxManifest.xml':
g.filename = f'{name}.xml'
l.extract(g, 'xml')
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
import json
import requests
magisk_apk = """${{ github.event.inputs.magisk_apk }}"""
if not magisk_apk:
magisk_apk = "stable"
if magisk_apk == "stable" or magisk_apk == "beta" or magisk_apk == "canary" or magisk_apk == "debug":
magisk_apk = json.loads(requests.get(f"https://github.com/topjohnwu/magisk-files/raw/master/{magisk_apk}.json").content)['magisk']['link']
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")
standalone_policy = False
try:
zip.getinfo(f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so")
standalone_policy = True
except:
pass
extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskinit", "magisk")
if standalone_policy:
extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so", "magiskpolicy", "magisk")
else:
extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskpolicy", "magisk")
extract_as(zip, f"lib/{ abi_map[arch][0] }/libmagiskboot.so", "magiskboot", "magisk")
extract_as(zip, f"lib/{ abi_map[arch][0] }/libbusybox.so", "busybox", "magisk")
if standalone_policy:
extract_as(zip, f"lib/{ abi_map['x64'][0] }/libmagiskpolicy.so", "magiskpolicy", ".")
else:
extract_as(zip, f"lib/{ abi_map['x64'][0] }/libmagiskinit.so", "magiskpolicy", ".")
extract_as(zip, f"assets/boot_patch.sh", "boot_patch.sh", "magisk")
extract_as(zip, f"assets/util_functions.sh", "util_functions.sh", "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
import re
arch = "${{ matrix.arch }}"
# TODO: if it's an Android 12.1 base WSA keep it pico since other variants of opengapps are unable to boot successfully
variant = "${{ github.event.inputs.gapps_variant }}" if int("${{ env.WSA_MAIN_VER }}") < 2204 else "pico"
abi_map = {"x64" : "x86_64", "arm64": "arm64"}
# TODO: keep it 11.0 since opengapps does not support 12+ yet
# As soon as opengapps is available for 12+, we need to get the sdk/release from build.prop and
# download the corresponding version
release = "11.0"
try:
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"][release]["variants"]}[variant]["zip"]
except Exception:
print("Failed to fetch from opengapps api, fallbacking to sourceforge rss...")
res = requests.get(f'https://sourceforge.net/projects/opengapps/rss?path=/{abi_map[arch]}&limit=100')
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')
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
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-lib-arm64' --exclude='markup-all' --exclude='setupwizarddefault-x86_64' --exclude='pixellauncher-all' --exclude='pixellauncher-common'
- name: Expand images
run: |
e2fsck -yf ${{ matrix.arch }}/system_ext.img
system_ext_size=$(( $(du -sB512 ${{ matrix.arch }}/system_ext.img | cut -f1) + 20000 ))
resize2fs ${{ matrix.arch }}/system_ext.img "$system_ext_size"s
e2fsck -yf ${{ matrix.arch }}/product.img
product_size=$(( $(du -sB512 ${{ matrix.arch }}/product.img | cut -f1) + 20000 ))
if [ -d gapps/product ]; then
product_size=$(( $product_size + $(du -sB512 gapps/product | cut -f1) ))
fi
resize2fs ${{ matrix.arch }}/product.img "$product_size"s
e2fsck -yf ${{ matrix.arch }}/system.img
system_size=$(( $(du -sB512 ${{ matrix.arch }}/system.img | cut -f1) + 20000 ))
if [ -d gapps ]; then
system_size=$(( $system_size + $(du -sB512 gapps | cut -f1) - $(du -sB512 gapps/product | cut -f1) ))
fi
if [ -d magisk ]; then
system_size=$(( $system_size +$(du -sB512 magisk | cut -f1) ))
fi
if [ -f magisk.zip ]; then
system_size=$(( $system_size +$(du -sB512 magisk.zip | cut -f1) ))
fi
resize2fs ${{ matrix.arch }}/system.img "$system_size"s
e2fsck -yf ${{ matrix.arch }}/vendor.img
vendor_size=$(( $(du -sB512 ${{ matrix.arch }}/vendor.img | cut -f1) + 20000 ))
resize2fs ${{ matrix.arch }}/vendor.img "$vendor_size"s
- 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: Remove Amazon AppStore
if: ${{ github.event.inputs.remove_amazon == 'remove' }}
run: |
find system/product/{etc/permissions,etc/sysconfig,framework,priv-app} | grep -e amazon -e venezia | sudo xargs rm -rf
- name: Integrate Magisk
if: ${{ github.event.inputs.root_sol == 'magisk' || github.event.inputs.root_sol == '' }}
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 cp magisk.zip system/sbin/magisk.apk
sudo tee -a system/sbin/loadpolicy.sh <<EOF
#!/system/bin/sh
mkdir -p /data/adb/magisk
cp /sbin/* /data/adb/magisk/
chmod -R 755 /data/adb/magisk
restorecon -R /data/adb/magisk
for module in \$(ls /data/adb/modules); do
if ! [ -f "/data/adb/modules/\$module/disable" ] && [ -f "/data/adb/modules/\$module/sepolicy.rule" ]; then
/sbin/magiskpolicy --live --apply "/data/adb/modules/\$module/sepolicy.rule"
fi
done
EOF
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 {} \;
sudo patchelf --replace-needed libc.so "${HOME}/libc.so" ./magiskpolicy || true
sudo patchelf --replace-needed libm.so "${HOME}/libm.so" ./magiskpolicy || true
sudo patchelf --replace-needed libdl.so "${HOME}/libdl.so" ./magiskpolicy || true
sudo patchelf --set-interpreter "${HOME}/linker64" ./magiskpolicy || true
chmod +x ./magiskpolicy
echo '/dev/wsa-magisk(/.*)? u:object_r:magisk_file:s0' | sudo tee -a system/vendor/etc/selinux/vendor_file_contexts
echo '/data/adb/magisk(/.*)? u:object_r:magisk_file:s0' | sudo tee -a system/vendor/etc/selinux/vendor_file_contexts
sudo ./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 <<EOF
on post-fs-data
start logd
start adbd
mkdir /dev/wsa-magisk
mount tmpfs tmpfs /dev/wsa-magisk mode=0755
copy /sbin/magisk64 /dev/wsa-magisk/magisk64
chmod 0755 /dev/wsa-magisk/magisk64
symlink ./magisk64 /dev/wsa-magisk/magisk
symlink ./magisk64 /dev/wsa-magisk/su
symlink ./magisk64 /dev/wsa-magisk/resetprop
copy /sbin/magisk32 /dev/wsa-magisk/magisk32
chmod 0755 /dev/wsa-magisk/magisk32
copy /sbin/magiskinit /dev/wsa-magisk/magiskinit
chmod 0755 /dev/wsa-magisk/magiskinit
copy /sbin/magiskpolicy /dev/wsa-magisk/magiskpolicy
chmod 0755 /dev/wsa-magisk/magiskpolicy
mkdir /dev/wsa-magisk/.magisk 700
mkdir /dev/wsa-magisk/.magisk/mirror 700
mkdir /dev/wsa-magisk/.magisk/block 700
copy /sbin/magisk.apk /dev/wsa-magisk/stub.apk
rm /dev/.magisk_unblock
start IhhslLhHYfse
start FAhW7H9G5sf
wait /dev/.magisk_unblock 40
rm /dev/.magisk_unblock
service IhhslLhHYfse /system/bin/sh /sbin/loadpolicy.sh
user root
seclabel u:r:magisk:s0
oneshot
service FAhW7H9G5sf /dev/wsa-magisk/magisk --post-fs-data
user root
seclabel u:r:magisk:s0
oneshot
service HLiFsR1HtIXVN6 /dev/wsa-magisk/magisk --service
class late_start
user root
seclabel u:r:magisk:s0
oneshot
on property:sys.boot_completed=1
mkdir /data/adb/magisk 755
copy /sbin/magisk.apk /data/adb/magisk/magisk.apk
start YqCTLTppv3ML
service YqCTLTppv3ML /dev/wsa-magisk/magisk --boot-complete
user root
seclabel u:r:magisk:s0
oneshot
EOF
- name: Merge Language Resources
run: |
cp ${{ matrix.arch }}/resources.pri pri/en-us.pri
cp ${{ matrix.arch }}/AppxManifest.xml xml/en-us.xml
tee priconfig.xml <<EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources targetOsVersion="10.0.0" majorVersion="1">
<index root="\" startIndexAt="\">
<indexer-config type="folder" foldernameAsQualifier="true" filenameAsQualifier="true" qualifierDelimiter="."/>
<indexer-config type="PRI"/>
</index>
</resources>
EOF
wine64 ~/makepri.exe new /pr pri /in MicrosoftCorporationII.WindowsSubsystemForAndroid /cf priconfig.xml /of ${{ matrix.arch }}/resources.pri /o
sed -i -zE "s/<Resources.*Resources>/<Resources>\n$(cat xml/* | grep -Po '<Resource [^>]*/>' | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/\$/\\$/g' | sed 's/\//\\\//g')\n<\/Resources>/g" ${{ matrix.arch }}/AppxManifest.xml
- name: Add extra packages
run: |
wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- --strip-component=2 '*/${{ matrix.arch }}/system/*'
sudo find system/system/priv-app -type d -exec chmod 0755 {} \;
sudo find system/system/priv-app -type f -exec chmod 0644 {} \;
sudo find system/system/priv-app -exec chcon --reference=system/system/priv-app {} \;
- name: Integrate GApps
if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }}
run: |
wget -qO- "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_REF.tar.gz" | sudo tar --wildcards -zxvf- --strip-component=2 '*/${{ matrix.arch }}/gapps/*'
shopt -s extglob
sudo cp -vr gapps/!(product) system/system
sudo cp -vr gapps/product/* system/product/
sudo find system/system/{app,etc,framework,priv-app} -exec chown root:root {} \;
sudo find system/product/{app,etc,overlay,priv-app} -exec chown root:root {} \;
sudo find system/system/{app,etc,framework,priv-app} -type d -exec chmod 0755 {} \;
sudo find system/product/{app,etc,overlay,priv-app} -type d -exec chmod 0755 {} \;
sudo find system/system/{app,framework,priv-app} -type f -exec chmod 0644 {} \;
ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type f -exec chmod 0644 {} \;
sudo find system/product/{app,etc,overlay,priv-app} -type f -exec chmod 0644 {} \;
sudo find system/system/{app,framework,priv-app} -type d -exec chcon --reference=system/system/app {} \;
sudo find system/product/{app,etc,overlay,priv-app} -type d -exec chcon --reference=system/product/app {} \;
ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type d -exec chcon --reference=system/system/etc/permissions {} \;
sudo find system/system/{app,framework,priv-app} -type f -exec chcon --reference=system/system/framework/ext.jar {} \;
ls gapps/etc/ | xargs -n 1 -I dir sudo find system/system/etc/dir -type f -exec chcon --reference=system/system/etc/permissions {} \;
sudo find system/product/{app,etc,overlay,priv-app} -type f -exec chcon --reference=system/product/etc/permissions/com.android.settings.intelligence.xml {} \;
sudo patchelf --replace-needed libc.so "${HOME}/libc.so" ./magiskpolicy || true
sudo patchelf --replace-needed libm.so "${HOME}/libm.so" ./magiskpolicy || true
sudo patchelf --replace-needed libdl.so "${HOME}/libdl.so" ./magiskpolicy || true
sudo patchelf --set-interpreter "${HOME}/linker64" ./magiskpolicy || true
chmod +x ./magiskpolicy
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"
- name: Fix GApps prop
if: ${{ github.event.inputs.gapps_variant != 'none' && github.event.inputs.gapps_variant != '' }}
shell: sudo python {0}
run: |
from __future__ import annotations
from io import TextIOWrapper
from os import system, path
from typing import OrderedDict
class Prop(OrderedDict):
def __init__(self, file: TextIOWrapper) -> 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):
if not path.exists(prop):
return
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 find system -exec touch -amt 200901010000.00 {} \;> /dev/null 2>&1
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 and add scripts
run: |
rm -rf ${{ matrix.arch }}/\[Content_Types\].xml ${{ matrix.arch }}/AppxBlockMap.xml ${{ matrix.arch }}/AppxSignature.p7x ${{ matrix.arch }}/AppxMetadata
cp vclibs.appx xaml.appx ${{ matrix.arch }}
tee ${{ matrix.arch }}/Install.ps1 <<EOF
# Automated Install script by Mioki
# http://github.com/okibcn
function Test-Administrator {
[OutputType([bool])]
param()
process {
[Security.Principal.WindowsPrincipal]\$user = [Security.Principal.WindowsIdentity]::GetCurrent();
return \$user.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator);
}
}
function Finish {
Clear-Host
Start-Process "wsa://com.topjohnwu.magisk"
Start-Process "wsa://com.android.vending"
}
if (-not (Test-Administrator)) {
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force
\$proc = Start-Process -PassThru -WindowStyle Hidden -Verb RunAs powershell.exe -Args "-executionpolicy bypass -command Set-Location '\$PSScriptRoot'; &'\$PSCommandPath' EVAL"
\$proc.WaitForExit()
if (\$proc.ExitCode -ne 0) {
Clear-Host
Write-Warning "Failed to launch start as Administrator\`r\`nPress any key to exit"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}
exit
}
elseif ((\$args.Count -eq 1) -and (\$args[0] -eq "EVAL")) {
Start-Process powershell.exe -Args "-executionpolicy bypass -command Set-Location '\$PSScriptRoot'; &'\$PSCommandPath'"
exit
}
if (((Test-Path -Path $(ls -Q ./${{ matrix.arch }} | paste -sd "," -)) -eq \$false).Count) {
Write-Error "Some files are missing in the zip. Please try to download it again from the browser downloader, or try to run the workflow again. Press any key to exist"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 1
}
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
\$VMP = Get-WindowsOptionalFeature -Online -FeatureName 'VirtualMachinePlatform'
if (\$VMP.State -ne "Enabled") {
Enable-WindowsOptionalFeature -Online -NoRestart -FeatureName 'VirtualMachinePlatform'
Clear-Host
Write-Warning "Need restart to enable virtual machine platform\`r\`nPress y to restart or press any key to exit"
\$key = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
If ("y" -eq \$key.Character) {
Restart-Computer -Confirm
}
Else {
exit 1
}
}
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Path vclibs.appx
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Path xaml.appx
\$Installed = \$null
\$Installed = Get-AppxPackage -Name 'MicrosoftCorporationII.WindowsSubsystemForAndroid'
If ((\$null -ne \$Installed) -and (-not (\$Installed.IsDevelopmentMode))) {
Clear-Host
Write-Warning "There is already one installed WSA. Please uninstall it first.\`r\`nPress y to uninstall existing WSA or press any key to exit"
\$key = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
If ("y" -eq \$key.Character) {
Remove-AppxPackage -Package \$Installed.PackageFullName
}
Else {
exit 1
}
}
Clear-Host
Write-Host "Installing MagiskOnWSA..."
Stop-Process -Name "wsaclient" -ErrorAction "silentlycontinue"
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Register .\AppxManifest.xml
if (\$?) {
Finish
}
Elseif (\$null -ne \$Installed) {
Clear-Host
Write-Host "Failed to update, try to uninstall existing installation while preserving userdata..."
Remove-AppxPackage -PreserveApplicationData -Package \$Installed.PackageFullName
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Register .\AppxManifest.xml
if (\$?) {
Finish
}
}
Write-Host "All Done\`r\`nPress any key to exit"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
EOF
- name: Generate artifact name
run: |
variant="${{ github.event.inputs.gapps_variant }}"
root="${{ github.event.inputs.root_sol }}"
if [[ "$root" = "none" ]]; then
name1=""
elif [[ "$root" = "" ]]; then
name1="-with-magisk"
else
name1="-with-${root}"
fi
if [[ "$variant" = "none" || "$variant" = "" ]]; then
name2="-NoGApps"
else
if [[ ${{ env.WSA_MAIN_VER }} -ge 2204 && "$variant" != "pico" ]]; then
echo "### MagiskOnWSA" >> $GITHUB_STEP_SUMMARY
echo ":warning: Since OpenGapps doesn't officially support Android 12.1 yet, lock the variant to pico!" >> $GITHUB_STEP_SUMMARY
variant="pico"
fi
name2="-GApps-${variant}"
fi
echo "artifact_name=WSA${name1}${name2}_${{ env.WSA_VER }}_${{ matrix.arch }}_${{ env.WSA_REL }}" >> $GITHUB_ENV
- name: Upload WSA
uses: actions/upload-artifact@v3
with:
name: ${{ env.artifact_name }}
path: "./${{ matrix.arch }}/*"
- name: Delete workflow runs
uses: Mattraks/delete-workflow-runs@v2
with:
token: ${{ github.token }}
repository: ${{ github.repository }}
retain_days: 0
keep_minimum_runs: 0

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
download
output

View File

@ -14,25 +14,15 @@
- Merged all language packs
- Support managing start menu icons (manually installing [WSAHelper](https://github.com/LSPosed/WSAHelper/releases/latest) to use this feature)
## Video Guide
https://user-images.githubusercontent.com/5022927/145696886-e13ebfc1-ff25-4410-893e-d3e517af70ea.mp4
## Text Guide
1. Star (if you like) and fork this repo (keep it PUBLIC, private repo is not supported)
1. Go to the **Action** tab in your forked repo
![Action Tab](https://docs.github.com/assets/images/help/repository/actions-tab.png)
1. In the left sidebar, click the **Build WSA** workflow.
![Workflow](https://docs.github.com/assets/images/actions-select-workflow.png)
1. Above the list of workflow runs, select **Run workflow**
![Run Workflow](https://docs.github.com/assets/images/actions-workflow-dispatch.png)
1. Select the version of Magisk and select the [OpenGApps variant](https://github.com/opengapps/opengapps/wiki#variants) (none is no OpenGApps) you like, select the root solution (none means no root), select WSA version and its architecture (mostly x64) and click **Run workflow**
![Run Workflow](https://docs.github.com/assets/images/actions-manually-run-workflow.png)
1. Wait for the action to complete and download the artifact **DO NOT download it via multithread downloaders like IDM or ADM**
![Download](https://docs.github.com/assets/images/help/repository/artifact-drop-down-updated.png)
1. Unzip the artifact
- The size shown in the webpage is uncompressed size and the zip you download will be compressed. So the size of the zip will be much less than the size shown in the webpage.
1. Clone the repo to local
1. Run `scripts/run.sh`
1. Select the version of Magisk and select the [OpenGApps variant](https://github.com/opengapps/opengapps/wiki#variants) you like, select the root solution (none means no root), select WSA version and its architecture (mostly x64)
1. Wait for the script to complete and the artifact will in `output` folder
1. Move the artifact to a places you like
1. Right-click `Install.ps1` and select `Run with PowerShell`
- If you previously have a MagiskOnWSA installation, it will automatically uninstall the previous while **preserving all userdata** and install the new one, so don't worry about your data.
- If you have an official WSA installation, you should uninstall it first. (In case you want to preserve your data, you can backup `%LOCALAPPDATA%\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalCache\userdata.vhdx` before uninstallation and restore it after installation.) (If you want to restore the icons to start menu, please install and use [WSAHelper](https://github.com/LSPosed/WSAHelper/releases/latest).)
@ -46,26 +36,13 @@ https://user-images.githubusercontent.com/5022927/145696886-e13ebfc1-ff25-4410-8
## FAQ
- Actions workflow task `Delete workflow runs` run Failed
Check workflow permissions, should be `Read and write permissions`
![permissions](https://user-images.githubusercontent.com/40033067/168649322-dadaafc9-dd31-4922-afe1-8aa933b7b036.png)
Read the [Github Docs](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#configuring-the-default-github_token-permissions) to find out how to change this setting
- Why should we delete old workflow runs?
Keeping old workflow runs can take up a lot of storage resources and is suspected to be abusive, which can lead to banning.
- Can I delete the unzipped folder?
- Can I delete the installed folder?
No.
- Why the size of the zip does not match the one shown?
The zip you downloaded is compressed and Github is showing the uncompressed size.
- How can I update WSA to new version?
Rerun the Github action, download the new artifact, replace the content of your previous installation and rerun `Install.ps1`. Don't worry, your data will be preserved.
Delete `download` folder
Rerun the script, replace the content of your previous installation and rerun `Install.ps1`. Don't worry, your data will be preserved.
- How can I get the logcat from WSA?
`%LOCALAPPDATA%\Packages\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\LocalState\diagnostics\logcat`
@ -93,7 +70,7 @@ https://user-images.githubusercontent.com/5022927/145696886-e13ebfc1-ff25-4410-8
- How can I get rid of Magisk?
Choose `none` as root solution.
- Github Action script is updated, how can I synchronize it?
- Github script is updated, how can I synchronize it?
1. In your fork repository, click `fetch upstream`
![fetch](https://docs.github.com/assets/cb-33284/images/help/repository/fetch-upstream-drop-down.png)

43
scripts/downloadGapps.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/python
import sys
import requests
import zipfile
import os
import urllib.request
import json
import re
from pathlib import Path
if not os.path.exists(Path.cwd().parent / "download"):
os.makedirs(Path.cwd().parent / "download")
download_dir = Path.cwd().parent / "download"
arch = sys.argv[1]
# TODO: Keep it pico since other variants of opengapps are unable to boot successfully
variant = sys.argv[2] if 0 else "pico"
abi_map = {"x64": "x86_64", "arm64": "arm64"}
# TODO: keep it 11.0 since opengapps does not support 12+ yet
# As soon as opengapps is available for 12+, we need to get the sdk/release from build.prop and
# download the corresponding version
release = "11.0"
try:
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"][release]["variants"]}[variant]["zip"]
except Exception:
print("Failed to fetch from opengapps api, fallbacking to sourceforge rss...")
res = requests.get(
f'https://sourceforge.net/projects/opengapps/rss?path=/{abi_map[arch]}&limit=100')
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')
print(f"downloading link: {link}", flush=True)
out_file = download_dir / "gapps.zip"
if not os.path.isfile(out_file):
urllib.request.urlretrieve(link, out_file)
print("done", flush=True)

75
scripts/downloadMagisk.py Normal file
View File

@ -0,0 +1,75 @@
#!/usr/bin/python
import sys
import urllib.request
import zipfile
import os
import json
import requests
from pathlib import Path
magisk_apk = sys.argv[2]
if not os.path.exists(Path.cwd().parent / "download"):
os.makedirs(Path.cwd().parent / "download")
download_dir = Path.cwd().parent / "download"
if not os.path.exists(Path.cwd().parent / "workdir" / "magisk"):
os.makedirs(Path.cwd().parent / "workdir" / "magisk")
workdir = Path.cwd().parent / "workdir" / "magisk"
if not magisk_apk:
magisk_apk = "stable"
if magisk_apk == "stable" or magisk_apk == "beta" or magisk_apk == "canary" or magisk_apk == "debug":
magisk_apk = json.loads(requests.get(
f"https://github.com/topjohnwu/magisk-files/raw/master/{magisk_apk}.json").content)['magisk']['link']
out_file = download_dir / "magisk.zip"
arch = sys.argv[1]
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, workdir / 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")
standalone_policy = False
try:
zip.getinfo(f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so")
standalone_policy = True
except:
pass
extract_as(
zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskinit", "magisk")
if standalone_policy:
extract_as(
zip, f"lib/{ abi_map[arch][0] }/libmagiskpolicy.so", "magiskpolicy", "magisk")
else:
extract_as(
zip, f"lib/{ abi_map[arch][0] }/libmagiskinit.so", "magiskpolicy", "magisk")
extract_as(
zip, f"lib/{ abi_map[arch][0] }/libmagiskboot.so", "magiskboot", "magisk")
extract_as(
zip, f"lib/{ abi_map[arch][0] }/libbusybox.so", "busybox", "magisk")
if standalone_policy:
extract_as(
zip, f"lib/{ abi_map['x64'][0] }/libmagiskpolicy.so", "magiskpolicy", ".")
else:
extract_as(
zip, f"lib/{ abi_map['x64'][0] }/libmagiskinit.so", "magiskpolicy", ".")
extract_as(zip, f"assets/boot_patch.sh", "boot_patch.sh", "magisk")
extract_as(zip, f"assets/util_functions.sh",
"util_functions.sh", "magisk")

90
scripts/downloadWSA.py Normal file
View File

@ -0,0 +1,90 @@
#!/usr/bin/python
import sys
import requests
from xml.dom import minidom
import html
import warnings
import re
import zipfile
import os
import urllib.request
from pathlib import Path
warnings.filterwarnings("ignore")
arch = sys.argv[1]
release_type_map = {"retail": "Retail", "release preview": "RP",
"insider slow": "WIS", "insider fast": "WIF"}
release_type = release_type_map[sys.argv[2]] if sys.argv[2] != "" else "Retail"
cat_id = '858014f3-3934-4abe-8078-4aa193e74ca8'
print("arch=" + arch + " release_type=" + release_type)
with open(Path.cwd().parent / ("xml/GetCookie.xml"), "r") as f:
cookie_content = f.read()
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cookie_content,
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(out.text)
cookie = doc.getElementsByTagName('EncryptedData')[0].firstChild.nodeValue
print(cookie)
with open(Path.cwd().parent / "xml/WUIDRequest.xml", "r") as f:
cat_id_content = f.read().format(cookie, cat_id, release_type)
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cat_id_content,
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(html.unescape(out.text))
filenames = {}
for node in doc.getElementsByTagName('Files'):
filenames[node.parentNode.parentNode.getElementsByTagName(
'ID')[0].firstChild.nodeValue] = f"{node.firstChild.attributes['InstallerSpecificIdentifier'].value}_{node.firstChild.attributes['FileName'].value}"
pass
identities = []
for node in doc.getElementsByTagName('SecuredFragment'):
filename = filenames[node.parentNode.parentNode.parentNode.getElementsByTagName('ID')[
0].firstChild.nodeValue]
update_identity = node.parentNode.parentNode.firstChild
identities += [(update_identity.attributes['UpdateID'].value,
update_identity.attributes['RevisionNumber'].value, filename)]
with open(Path.cwd().parent / "xml/FE3FileUrl.xml", "r") as f:
file_content = f.read()
if not os.path.exists(Path.cwd().parent / "download"):
os.makedirs(Path.cwd().parent / "download")
for i, v, f in identities:
if re.match(f"Microsoft\.UI\.Xaml\..*_{arch}_.*\.appx", f):
out_file = Path.cwd().parent / "download/xaml.appx"
elif re.match(f"Microsoft\.VCLibs\..*_{arch}_.*\.appx", f):
out_file = Path.cwd().parent / "download/vclibs.appx"
elif re.match(f"MicrosoftCorporationII\.WindowsSubsystemForAndroid_.*\.msixbundle", f):
out_file = Path.cwd().parent / "download/wsa.zip"
else:
continue
out = requests.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured',
data=file_content.format(i, v, release_type),
headers={'Content-Type': 'application/soap+xml; charset=utf-8'},
verify=False
)
doc = minidom.parseString(out.text)
for l in doc.getElementsByTagName("FileLocation"):
url = l.getElementsByTagName("Url")[0].firstChild.nodeValue
if len(url) != 99:
if not os.path.isfile(out_file):
print(f"downloading link: {url} to {out_file}", flush=True)
urllib.request.urlretrieve(url, out_file)

60
scripts/extractWSA.py Normal file
View File

@ -0,0 +1,60 @@
#!/usr/bin/python
import sys
import requests
from xml.dom import minidom
import html
import warnings
import re
import zipfile
import os
import urllib.request
from pathlib import Path
warnings.filterwarnings("ignore")
arch = sys.argv[1]
if not os.path.exists(Path.cwd().parent / "workdir" / "wsa"):
os.makedirs(Path.cwd().parent / "workdir" / "wsa")
zip_name = ""
workdir = Path.cwd().parent / "workdir" / "wsa"
with zipfile.ZipFile(Path.cwd().parent / "download/wsa.zip") as zip:
for f in zip.filelist:
if arch in f.filename.lower():
zip_name = f.filename
if not os.path.isfile(workdir / zip_name):
zip_path = workdir / zip_name
print(f"unzipping to {workdir}", flush=True)
zip.extract(f, workdir)
ver_no = zip_name.split("_")
long_ver = ver_no[1]
ver = long_ver.split(".")
main_ver = ver[0]
with open(os.environ['WSA_WORK_ENV'], 'a') as g:
g.write(f'WSA_VER={long_ver}\n')
with open(os.environ['WSA_WORK_ENV'], 'a') as g:
g.write(f'WSA_MAIN_VER={main_ver}\n')
rel = ver_no[3].split(".")
rell = str(rel[0])
with open(os.environ['WSA_WORK_ENV'], 'a') as g:
g.write(f'WSA_REL={rell}\n')
if 'language' in f.filename.lower() or 'scale' in f.filename.lower():
name = f.filename.split("-", 1)[1].split(".")[0]
zip.extract(f, workdir)
with zipfile.ZipFile(workdir / f.filename) as l:
for g in l.filelist:
if g.filename == 'resources.pri':
g.filename = f'{name}.pri'
l.extract(g, workdir / 'pri')
print(f"extract resource pack {g.filename}")
elif g.filename == 'AppxManifest.xml':
g.filename = f'{name}.xml'
l.extract(g, workdir / 'xml')
with zipfile.ZipFile(zip_path) as zip:
if not os.path.isdir(workdir / arch):
print(f"unzipping from {zip_path}", flush=True)
zip.extractall(workdir / arch)
print("done", flush=True)

73
scripts/fixGappsProp.py Normal file
View File

@ -0,0 +1,73 @@
from __future__ import annotations
from io import TextIOWrapper
from os import system, path
from typing import OrderedDict
import sys
class Prop(OrderedDict):
def __init__(self, file: TextIOWrapper) -> 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):
if not path.exists(prop):
return
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))
sys_path = sys.argv[1]
for sec, prop in {"system": sys_path+"/system/build.prop", "product": sys_path+"/product/build.prop", "system_ext": sys_path+"/system_ext/build.prop", "vendor": sys_path+"/vendor/build.prop", "odm": sys_path+"/vendor/odm/etc/build.prop"}.items():
fix_prop(sec, prop)

435
scripts/run.sh Normal file
View File

@ -0,0 +1,435 @@
#!/bin/bash
function Radiolist {
declare -A o="$1"
shift
whiptail --nocancel --radiolist "${o[title]}" \
0 0 0 "$@" 3>&1 1>&2 2>&3
if [ $? != 0 ]; then
echo "${o[default]}"
fi
}
function YesNoBox {
declare -A o="$1"
shift
whiptail --title "${o[title]}" --yesno "${o[text]}" 0 0
}
echo "Dependencies"
sudo apt update && sudo apt -y install setools lzip wine winetricks patchelf
cp -r ../wine/.cache/* ~/.cache
winetricks msxml6
# ARCH=$(whiptail --nocancel --separate-output --checklist 'Build arch' 0 0 0 'x64' "X86_64" 'on' 'arm64' "AArch64" 'off' 3>&1 1>&2 2>&3)
# if [ $? != 0 ]; then
# ARCH=x64
# fi
ARCH=$(
Radiolist '([title]="Build arch"
[default]="x64")' \
\
'x64' "X86_64" 'on' \
'arm64' "AArch64" 'off'
)
RELEASE_TYPE=$(
Radiolist '([title]="WSA release type"
[default]="retail")' \
\
'retail' "Stable Channel" 'on' \
'release preview' "Release Preview Channel" 'off' \
'insider slow' "Beta Channel" 'off' \
'insider fast' "Dev Channel" 'off'
)
MAGISK_VER=$(
Radiolist '([title]="Magisk version"
[default]="stable")' \
\
'stable' "Stable Channel" 'on' \
'beta' "Beta Channel" 'off' \
'canary' "Canary Channel" 'off' \
'debug' "Canary Channel Debug Build" 'off'
)
if (YesNoBox '([title]="Install Gapps" [text]="Do you want to install gapps?")'); then
GAPPS_VARIANT=$(
Radiolist '([title]="Variants of gapps"
[default]="pico")' \
\
'super' "" 'off' \
'stock' "" 'off' \
'full' "" 'off' \
'mini' "" 'off' \
'micro' "" 'off' \
'nano' "" 'off' \
'pico' "" 'on' \
'tvstock' "" 'off' \
'tvmini' "" 'off'
)
else
GAPPS_VARIANT="none"
fi
if (YesNoBox '([title]="Remove Amazon AppStore" [text]="Do you want to remove amazon appStore?")'); then
REMOVE_AMAZON="remove"
else
REMOVE_AMAZON="keep"
fi
ROOT_SOL=$(
Radiolist '([title]="Root solution"
[default]="magisk")' \
\
'magisk' "" 'on' \
'none' "" 'off'
)
clear
echo -e "ARCH=$ARCH\nRELEASE_TYPE=$RELEASE_TYPE\nMAGISK_VER=$MAGISK_VER\nGAPPS_VARIANT=$GAPPS_VARIANT\nREMOVE_AMAZON=$REMOVE_AMAZON\nROOT_SOL=$ROOT_SOL"
echo "Download WSA"
python3 downloadWSA.py "$ARCH" "$RELEASE_TYPE"
echo "extractWSA"
WSA_WORK_ENV=../workdir/ENV
if [ -f $WSA_WORK_ENV ]; then rm -f $WSA_WORK_ENV; fi
export WSA_WORK_ENV
python3 extractWSA.py "$ARCH"
echo "Download Magisk"
python3 downloadMagisk.py "$ARCH" "$MAGISK_VER"
echo "Download OpenGApps"
python3 downloadGapps.py "$ARCH" "$MAGISK_VER"
echo "Extract GApps"
if [ $GAPPS_VARIANT != 'none' ] && [ $GAPPS_VARIANT != '' ]; then
mkdir ../workdir/gapps
unzip -p ../download/gapps.zip {Core,GApps}/'*.lz' | tar --lzip -C ../workdir/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'
fi
echo "Expand images"
e2fsck -yf ../workdir/wsa/$ARCH/system_ext.img
SYSTEM_EXT_SIZE=$(($(du -sB512 ../workdir/wsa/$ARCH/system_ext.img | cut -f1) + 20000))
resize2fs ../workdir/wsa/$ARCH/system_ext.img "$SYSTEM_EXT_SIZE"s
e2fsck -yf ../workdir/wsa/$ARCH/product.img
PRODUCT_SIZE=$(($(du -sB512 ../workdir/wsa/$ARCH/product.img | cut -f1) + 20000))
if [ -d ../workdir/gapps/product ]; then
PRODUCT_SIZE=$(($PRODUCT_SIZE + $(du -sB512 ../workdir/gapps/product | cut -f1)))
fi
resize2fs ../workdir/wsa/$ARCH/product.img "$PRODUCT_SIZE"s
e2fsck -yf ../workdir/wsa/$ARCH/system.img
SYSTEM_SIZE=$(($(du -sB512 ../workdir/wsa/$ARCH/system.img | cut -f1) + 20000))
if [ -d ../workdir/gapps ]; then
SYSTEM_SIZE=$(($SYSTEM_SIZE + $(du -sB512 ../workdir/gapps | cut -f1) - $(du -sB512 ../workdir/gapps/product | cut -f1)))
fi
if [ -d ../workdir/magisk ]; then
SYSTEM_SIZE=$(($SYSTEM_SIZE + $(du -sB512 ../workdir/magisk/magisk | cut -f1)))
fi
if [ -f ../download/magisk.zip ]; then
SYSTEM_SIZE=$(($SYSTEM_SIZE + $(du -sB512 ../download/magisk.zip | cut -f1)))
fi
resize2fs ../workdir/wsa/$ARCH/system.img "$SYSTEM_SIZE"s
e2fsck -yf ../workdir/wsa/$ARCH/vendor.img
VENDOR_SIZE=$(($(du -sB512 ../workdir/wsa/$ARCH/vendor.img | cut -f1) + 20000))
resize2fs ../workdir/wsa/$ARCH/vendor.img "$VENDOR_SIZE"s
echo "Mount images"
MOUNT_DIR=../workdir/system
sudo mkdir $MOUNT_DIR
sudo mount -o loop ../workdir/wsa/$ARCH/system.img $MOUNT_DIR
sudo mount -o loop ../workdir/wsa/$ARCH/vendor.img $MOUNT_DIR/vendor
sudo mount -o loop ../workdir/wsa/$ARCH/product.img $MOUNT_DIR/product
sudo mount -o loop ../workdir/wsa/$ARCH/system_ext.img $MOUNT_DIR/system_ext
echo "Remove Amazon AppStore"
if [ $REMOVE_AMAZON = 'remove' ]; then
find $MOUNT_DIR/product/{etc/permissions,etc/sysconfig,framework,priv-app} | grep -e amazon -e venezia | sudo xargs rm -rf
fi
echo "Integrate Magisk"
if [ $ROOT_SOL = 'magisk' ] || [ $ROOT_SOL = '' ]; then
sudo mkdir $MOUNT_DIR/sbin
sudo chcon --reference $MOUNT_DIR/init.environ.rc $MOUNT_DIR/sbin
sudo chown root:root $MOUNT_DIR/sbin
sudo chmod 0700 $MOUNT_DIR/sbin
sudo cp ../workdir/magisk/magisk/* $MOUNT_DIR/sbin/
sudo cp ../download/magisk.zip $MOUNT_DIR/sbin/magisk.apk
sudo tee -a $MOUNT_DIR/sbin/loadpolicy.sh <<EOF
#!/system/bin/sh
mkdir -p /data/adb/magisk
cp /sbin/* /data/adb/magisk/
chmod -R 755 /data/adb/magisk
restorecon -R /data/adb/magisk
for module in \$(ls /data/adb/modules); do
if ! [ -f "/data/adb/modules/\$module/disable" ] && [ -f "/data/adb/modules/\$module/sepolicy.rule" ]; then
/sbin/magiskpolicy --live --apply "/data/adb/modules/\$module/sepolicy.rule"
fi
done
EOF
sudo find $MOUNT_DIR/sbin -type f -exec chmod 0755 {} \;
sudo find $MOUNT_DIR/sbin -type f -exec chown root:root {} \;
sudo find $MOUNT_DIR/sbin -type f -exec chcon --reference $MOUNT_DIR/product {} \;
sudo patchelf --replace-needed libc.so "../linker/libc.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --replace-needed libm.so "../linker/libm.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --replace-needed libdl.so "../linker/libdl.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --set-interpreter "../linker/linker64" ../workdir/magisk/magiskpolicy || true
chmod +x ../workdir/magisk/magiskpolicy
echo '/dev/wsa-magisk(/.*)? u:object_r:magisk_file:s0' | sudo tee -a $MOUNT_DIR/vendor/etc/selinux/vendor_file_contexts
echo '/data/adb/magisk(/.*)? u:object_r:magisk_file:s0' | sudo tee -a $MOUNT_DIR/vendor/etc/selinux/vendor_file_contexts
sudo ../workdir/magisk/magiskpolicy --load $MOUNT_DIR/vendor/etc/selinux/precompiled_sepolicy --save $MOUNT_DIR/vendor/etc/selinux/precompiled_sepolicy --magisk "allow * magisk_file lnk_file *"
sudo tee -a $MOUNT_DIR/system/etc/init/hw/init.rc <<EOF
on post-fs-data
start logd
start adbd
mkdir /dev/wsa-magisk
mount tmpfs tmpfs /dev/wsa-magisk mode=0755
copy /sbin/magisk64 /dev/wsa-magisk/magisk64
chmod 0755 /dev/wsa-magisk/magisk64
symlink ./magisk64 /dev/wsa-magisk/magisk
symlink ./magisk64 /dev/wsa-magisk/su
symlink ./magisk64 /dev/wsa-magisk/resetprop
copy /sbin/magisk32 /dev/wsa-magisk/magisk32
chmod 0755 /dev/wsa-magisk/magisk32
copy /sbin/magiskinit /dev/wsa-magisk/magiskinit
chmod 0755 /dev/wsa-magisk/magiskinit
copy /sbin/magiskpolicy /dev/wsa-magisk/magiskpolicy
chmod 0755 /dev/wsa-magisk/magiskpolicy
mkdir /dev/wsa-magisk/.magisk 700
mkdir /dev/wsa-magisk/.magisk/mirror 700
mkdir /dev/wsa-magisk/.magisk/block 700
copy /sbin/magisk.apk /dev/wsa-magisk/stub.apk
rm /dev/.magisk_unblock
start IhhslLhHYfse
start FAhW7H9G5sf
wait /dev/.magisk_unblock 40
rm /dev/.magisk_unblock
service IhhslLhHYfse /system/bin/sh /sbin/loadpolicy.sh
user root
seclabel u:r:magisk:s0
oneshot
service FAhW7H9G5sf /dev/wsa-magisk/magisk --post-fs-data
user root
seclabel u:r:magisk:s0
oneshot
service HLiFsR1HtIXVN6 /dev/wsa-magisk/magisk --service
class late_start
user root
seclabel u:r:magisk:s0
oneshot
on property:sys.boot_completed=1
mkdir /data/adb/magisk 755
copy /sbin/magisk.apk /data/adb/magisk/magisk.apk
start YqCTLTppv3ML
service YqCTLTppv3ML /dev/wsa-magisk/magisk --boot-complete
user root
seclabel u:r:magisk:s0
oneshot
EOF
fi
echo "Merge Language Resources"
cp ../workdir/wsa/$ARCH/resources.pri ../workdir/wsa/pri/en-us.pri
cp ../workdir/wsa/$ARCH/AppxManifest.xml ../workdir/wsa/xml/en-us.xml
tee ../workdir/wsa/priconfig.xml <<EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources targetOsVersion="10.0.0" majorVersion="1">
<index root="\" startIndexAt="\">
<indexer-config type="folder" foldernameAsQualifier="true" filenameAsQualifier="true" qualifierDelimiter="."/>
<indexer-config type="PRI"/>
</index>
</resources>
EOF
wine64 ../wine/makepri.exe new /pr ../workdir/wsa/pri /in MicrosoftCorporationII.WindowsSubsystemForAndroid /cf ../workdir/wsa/priconfig.xml /of ../workdir/wsa/$ARCH/resources.pri /o
sed -i -zE "s/<Resources.*Resources>/<Resources>\n$(cat ../workdir/wsa/xml/* | grep -Po '<Resource [^>]*/>' | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/\$/\\$/g' | sed 's/\//\\\//g')\n<\/Resources>/g" ../workdir/wsa/$ARCH/AppxManifest.xml
echo "Add extra packages"
sudo cp -r ""../$ARCH/system/*"" $MOUNT_DIR
sudo find $MOUNT_DIR/system/priv-app -type d -exec chmod 0755 {} \;
sudo find $MOUNT_DIR/system/priv-app -type f -exec chmod 0644 {} \;
sudo find $MOUNT_DIR/system/priv-app -exec chcon --reference=$MOUNT_DIR/system/priv-app {} \;
echo "Integrate GApps"
if [ $GAPPS_VARIANT != 'none' ] && [ $GAPPS_VARIANT != '' ]; then
cp -r ../$ARCH/gapps/* ../workdir/gapps
shopt -s extglob
sudo cp -vr ../workdir/gapps/product/* $MOUNT_DIR/product/
rm -rf ../workdir/gapps/product
sudo cp -vr ../workdir/gapps/* $MOUNT_DIR/system
sudo find $MOUNT_DIR/system/{app,etc,framework,priv-app} -exec chown root:root {} \;
sudo find $MOUNT_DIR/product/{app,etc,overlay,priv-app} -exec chown root:root {} \;
sudo find $MOUNT_DIR/system/{app,etc,framework,priv-app} -type d -exec chmod 0755 {} \;
sudo find $MOUNT_DIR/product/{app,etc,overlay,priv-app} -type d -exec chmod 0755 {} \;
sudo find $MOUNT_DIR/system/{app,framework,priv-app} -type f -exec chmod 0644 {} \;
ls ../workdir/gapps/etc/ | xargs -n 1 -I dir sudo find $MOUNT_DIR/system/etc/dir -type f -exec chmod 0644 {} \;
sudo find $MOUNT_DIR/product/{app,etc,overlay,priv-app} -type f -exec chmod 0644 {} \;
sudo find $MOUNT_DIR/system/{app,framework,priv-app} -type d -exec chcon --reference=$MOUNT_DIR/system/app {} \;
sudo find $MOUNT_DIR/product/{app,etc,overlay,priv-app} -type d -exec chcon --reference=$MOUNT_DIR/product/app {} \;
ls ../workdir/gapps/etc/ | xargs -n 1 -I dir sudo find $MOUNT_DIR/system/etc/dir -type d -exec chcon --reference=$MOUNT_DIR/system/etc/permissions {} \;
sudo find $MOUNT_DIR/system/{app,framework,priv-app} -type f -exec chcon --reference=$MOUNT_DIR/system/framework/ext.jar {} \;
ls ../workdir/gapps/etc/ | xargs -n 1 -I dir sudo find $MOUNT_DIR/system/etc/dir -type f -exec chcon --reference=$MOUNT_DIR/system/etc/permissions {} \;
sudo find $MOUNT_DIR/product/{app,etc,overlay,priv-app} -type f -exec chcon --reference=$MOUNT_DIR/product/etc/permissions/com.android.settings.intelligence.xml {} \;
sudo patchelf --replace-needed libc.so "../linker/libc.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --replace-needed libm.so "../linker/libm.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --replace-needed libdl.so "../linker/libdl.so" ../workdir/magisk/magiskpolicy || true
sudo patchelf --set-interpreter "../linker/linker64" ../workdir/magisk/magiskpolicy || true
chmod +x ../workdir/magisk/magiskpolicy
sudo ../workdir/magisk/magiskpolicy --load $MOUNT_DIR/vendor/etc/selinux/precompiled_sepolicy --save $MOUNT_DIR/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"
fi
echo "Fix GApps prop"
if [ $GAPPS_VARIANT != 'none' ] && [ $GAPPS_VARIANT != '' ]; then
sudo python3 fixGappsProp.py $MOUNT_DIR
fi
echo "Umount images"
sudo find $MOUNT_DIR -exec touch -amt 200901010000.00 {} \; >/dev/null 2>&1
sudo umount $MOUNT_DIR/vendor
sudo umount $MOUNT_DIR/product
sudo umount $MOUNT_DIR/system_ext
sudo umount $MOUNT_DIR
echo "Shrink images"
e2fsck -yf ../workdir/wsa/$ARCH/system.img
resize2fs -M ../workdir/wsa/$ARCH/system.img
e2fsck -yf ../workdir/wsa/$ARCH/vendor.img
resize2fs -M ../workdir/wsa/$ARCH/vendor.img
e2fsck -yf ../workdir/wsa/$ARCH/product.img
resize2fs -M ../workdir/wsa/$ARCH/product.img
e2fsck -yf ../workdir/wsa/$ARCH/system_ext.img
resize2fs -M ../workdir/wsa/$ARCH/system_ext.img
echo "Remove signature and add scripts"
rm -rf ../workdir/wsa/$ARCH/\[Content_Types\].xml ../workdir/wsa/$ARCH/AppxBlockMap.xml ../workdir/wsa/$ARCH/AppxSignature.p7x ../workdir/wsa/$ARCH/AppxMetadata
cp ../download/vclibs.appx ../download/xaml.appx ../workdir/wsa/$ARCH
tee ../workdir/wsa/$ARCH/Install.ps1 <<EOF
# Automated Install script by Mioki
# http://github.com/okibcn
function Test-Administrator {
[OutputType([bool])]
param()
process {
[Security.Principal.WindowsPrincipal]\$user = [Security.Principal.WindowsIdentity]::GetCurrent();
return \$user.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator);
}
}
function Finish {
Clear-Host
Start-Process "wsa://com.topjohnwu.magisk"
Start-Process "wsa://com.android.vending"
}
if (-not (Test-Administrator)) {
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force
\$proc = Start-Process -PassThru -WindowStyle Hidden -Verb RunAs powershell.exe -Args "-executionpolicy bypass -command Set-Location '\$PSScriptRoot'; &'\$PSCommandPath' EVAL"
\$proc.WaitForExit()
if (\$proc.ExitCode -ne 0) {
Clear-Host
Write-Warning "Failed to launch start as Administrator\`r\`nPress any key to exit"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}
exit
}
elseif ((\$args.Count -eq 1) -and (\$args[0] -eq "EVAL")) {
Start-Process powershell.exe -Args "-executionpolicy bypass -command Set-Location '\$PSScriptRoot'; &'\$PSCommandPath'"
exit
}
if (((Test-Path -Path $(ls -Q ../workdir/wsa/$ARCH | paste -sd "," -)) -eq \$false).Count) {
Write-Error "Some files are missing in the zip. Please try to download it again from the browser downloader, or try to run the workflow again. Press any key to exist"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 1
}
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
\$VMP = Get-WindowsOptionalFeature -Online -FeatureName 'VirtualMachinePlatform'
if (\$VMP.State -ne "Enabled") {
Enable-WindowsOptionalFeature -Online -NoRestart -FeatureName 'VirtualMachinePlatform'
Clear-Host
Write-Warning "Need restart to enable virtual machine platform\`r\`nPress y to restart or press any key to exit"
\$key = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
If ("y" -eq \$key.Character) {
Restart-Computer -Confirm
}
Else {
exit 1
}
}
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Path vclibs.appx
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Path xaml.appx
\$Installed = \$null
\$Installed = Get-AppxPackage -Name 'MicrosoftCorporationII.WindowsSubsystemForAndroid'
If ((\$null -ne \$Installed) -and (-not (\$Installed.IsDevelopmentMode))) {
Clear-Host
Write-Warning "There is already one installed WSA. Please uninstall it first.\`r\`nPress y to uninstall existing WSA or press any key to exit"
\$key = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
If ("y" -eq \$key.Character) {
Remove-AppxPackage -Package \$Installed.PackageFullName
}
Else {
exit 1
}
}
Clear-Host
Write-Host "Installing MagiskOnWSA..."
Stop-Process -Name "wsaclient" -ErrorAction "silentlycontinue"
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Register .\AppxManifest.xml
if (\$?) {
Finish
}
Elseif (\$null -ne \$Installed) {
Clear-Host
Write-Host "Failed to update, try to uninstall existing installation while preserving userdata..."
Remove-AppxPackage -PreserveApplicationData -Package \$Installed.PackageFullName
Add-AppxPackage -ForceApplicationShutdown -ForceUpdateFromAnyVersion -Register .\AppxManifest.xml
if (\$?) {
Finish
}
}
Write-Host "All Done\`r\`nPress any key to exit"
\$null = \$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
EOF
echo "Generate info"
if [[ "$ROOT_SOL" = "none" ]]; then
name1=""
elif [[ "$ROOT_SOL" = "" ]]; then
name1="-with-magisk"
else
name1="-with-$ROOT_SOL"
fi
if [[ "$GAPPS_VARIANT" = "none" || "$GAPPS_VARIANT" = "" ]]; then
name2="-NoGApps"
else
if [[ "$GAPPS_VARIANT" != "pico" ]]; then
echo ":warning: Since OpenGapps doesn't officially support Android 12.1 yet, lock the variant to pico!"
fi
name2="-GApps-${GAPPS_VARIANT}"
fi
echo "WSA${name1}${name2}_${ARCH}"
cat ../workdir/ENV
rm -rf ../output
mv ../workdir/wsa/$ARCH ../output
rm -rf ../workdir

Binary file not shown.