├── fastlane └── metadata │ └── android │ └── en-US │ ├── title.txt │ ├── short_description.txt │ └── full_description.txt ├── tools ├── win │ ├── zip.exe │ ├── busybox.exe │ ├── unzip.exe │ ├── busybox-legacy.bin │ ├── man │ │ └── cat1 │ │ │ ├── busybox.1.gz │ │ │ ├── pdpmake.1.license │ │ │ ├── busybox.1.gz.license │ │ │ └── pdpmake.1 │ ├── zip.exe.license │ ├── unzip.exe.license │ ├── ver.sh │ ├── busybox.exe.license │ ├── start.sh │ ├── busybox-legacy.bin.license │ └── etc │ │ └── profile ├── zipsigner.jar ├── zipsigner-dvk.jar ├── zipsigner.jar.license ├── zipsigner-dvk.jar.license ├── README.rst ├── help.sh ├── get-signature.sh ├── list-app-perms.sh └── dl-perm-list.sh ├── docs ├── CODEOWNERS ├── SUPPORT.rst ├── CONTRIBUTING.rst ├── SECURITY.rst └── INSTRUCTIONS.rst ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ ├── gradle-wrapper.jar.license │ └── gradle-wrapper.properties ├── .tool-versions ├── zip-content ├── misc │ ├── aapt │ │ ├── aapt-arm.bin │ │ ├── aapt-arm64.bin │ │ └── aapt-x86.bin │ ├── busybox │ │ ├── busybox-arm.bin │ │ ├── busybox-mips.bin │ │ ├── busybox-x86.bin │ │ ├── busybox-arm64.bin │ │ ├── busybox-mips64.bin │ │ ├── busybox-mipseb.bin │ │ └── busybox-x86_64.bin │ ├── README.rst │ └── REUSE.toml ├── origin │ ├── file-list.dat.license │ ├── etc │ │ ├── sysconfig │ │ │ └── sysconfig-backup.xml │ │ ├── permissions │ │ │ ├── privapp-permissions-GoogleContactsSyncAdapter12.xml │ │ │ ├── privapp-permissions-GoogleContactsSyncAdapter8.xml │ │ │ └── privapp-permissions-GoogleBackupTransport4.4.xml │ │ └── default-permissions │ │ │ ├── default-permissions-GoogleBackupTransport4.4.xml │ │ │ ├── default-permissions-GoogleCalendarSyncAdapter5.xml │ │ │ ├── default-permissions-GoogleCalendarSyncAdapter6.xml │ │ │ ├── default-permissions-GoogleContactsSyncAdapter4.4.xml │ │ │ ├── default-permissions-GoogleContactsSyncAdapter8.xml │ │ │ └── default-permissions-GoogleContactsSyncAdapter12.xml │ └── addon.d │ │ └── 00-1-google-sync.sh ├── META-INF │ ├── com │ │ └── google │ │ │ └── android │ │ │ ├── updater-script.dat │ │ │ └── update-binary.sh │ └── REUSE.toml ├── setprop-settings-list.csv.license ├── module.prop ├── settings-full.conf ├── scripts │ ├── install.sh │ └── uninstall.sh ├── CONTENTS.rst └── zip-install.sh ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature-request.yml │ └── bug-report.yml ├── release.yml ├── dependabot.yml └── workflows │ ├── code-lint.yml │ ├── periodic-checks.yml │ ├── generate-perm-xml.yml │ ├── coverage.yml │ ├── code-scan.yml │ ├── tag-and-release.yml │ ├── auto-release-from-tag.yml │ └── scripts-testing.yml ├── addition.sh ├── recovery-simulator ├── override │ ├── su │ ├── sudo │ ├── chown │ ├── umount │ ├── getprop │ └── mount ├── recovery.bat ├── inc │ └── configure-overrides.sh └── updater.sh ├── .yamllint.yml ├── gradle.properties ├── SECURITY.md ├── Gemfile ├── conf-1.sh ├── .codecov.yml ├── .mailmap ├── .vscode ├── extensions.json ├── settings.json └── tasks.json ├── .tgitconfig ├── .simplecov ├── .shellcheckrc ├── settings.gradle ├── sonar-project.properties ├── dependencies.gradle ├── .gitlab └── security-scans.yml ├── REUSE.toml ├── Gemfile.lock ├── allowed_signers ├── Makefile ├── .gitignore ├── .git-hooks ├── prepare-commit-msg └── commit-msg ├── .editorconfig ├── cmdline.bat ├── LICENSES ├── Unlicense.txt ├── Info-ZIP.txt └── CC0-1.0.txt ├── .gitattributes ├── README.rst ├── .gitlab-ci.yml ├── CHANGELOG.rst ├── .public-keys └── github.gpg ├── conf-2.sh ├── config-git.sh ├── gradlew.bat ├── LICENSE-ADDITION.rst ├── cmdline.sh └── gradlew /fastlane/metadata/android/en-US/title.txt: -------------------------------------------------------------------------------- 1 | Google sync add-on 2 | -------------------------------------------------------------------------------- /tools/win/zip.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/win/zip.exe -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | It installs Google sync adapters on Android. 2 | -------------------------------------------------------------------------------- /tools/win/busybox.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/win/busybox.exe -------------------------------------------------------------------------------- /tools/win/unzip.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/win/unzip.exe -------------------------------------------------------------------------------- /tools/zipsigner.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/zipsigner.jar -------------------------------------------------------------------------------- /tools/zipsigner-dvk.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/zipsigner-dvk.jar -------------------------------------------------------------------------------- /docs/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | * @ale5000-git 5 | -------------------------------------------------------------------------------- /tools/win/busybox-legacy.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/win/busybox-legacy.bin -------------------------------------------------------------------------------- /tools/win/man/cat1/busybox.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/tools/win/man/cat1/busybox.1.gz -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | java temurin-17 5 | gradle 8.11.1 6 | -------------------------------------------------------------------------------- /zip-content/misc/aapt/aapt-arm.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/aapt/aapt-arm.bin -------------------------------------------------------------------------------- /zip-content/misc/aapt/aapt-arm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/aapt/aapt-arm64.bin -------------------------------------------------------------------------------- /zip-content/misc/aapt/aapt-x86.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/aapt/aapt-x86.bin -------------------------------------------------------------------------------- /zip-content/origin/file-list.dat.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: NONE 2 | SPDX-License-Identifier: CC0-1.0 3 | SPDX-FileType: OTHER 4 | -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-arm.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-arm.bin -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-mips.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-mips.bin -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-x86.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-x86.bin -------------------------------------------------------------------------------- /tools/zipsigner.jar.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: (c) 2019 John Wu 2 | SPDX-License-Identifier: GPL-3.0-or-later 3 | SPDX-FileType: ARCHIVE 4 | -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-arm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-arm64.bin -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-mips64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-mips64.bin -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-mipseb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-mipseb.bin -------------------------------------------------------------------------------- /zip-content/misc/busybox/busybox-x86_64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro5k/google-sync-addon/HEAD/zip-content/misc/busybox/busybox-x86_64.bin -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | blank_issues_enabled: false 6 | -------------------------------------------------------------------------------- /tools/zipsigner-dvk.jar.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: (c) 2019 John Wu 2 | SPDX-License-Identifier: GPL-3.0-or-later 3 | SPDX-FileType: ARCHIVE 4 | -------------------------------------------------------------------------------- /zip-content/META-INF/com/google/android/updater-script.dat: -------------------------------------------------------------------------------- 1 | Dummy file, the real script is inside update-binary. 2 | This is kept for compatibility. 3 | -------------------------------------------------------------------------------- /addition.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | # Custom code to run during build goes here. 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | Google sync add-on is a flashable zip created by ale5000 for a simple installation of Google sync adapters on Android. 2 | -------------------------------------------------------------------------------- /tools/win/zip.exe.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 2 | SPDX-License-Identifier: Info-ZIP 3 | SPDX-FileType: APPLICATION 4 | -------------------------------------------------------------------------------- /tools/win/unzip.exe.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 2 | SPDX-License-Identifier: Info-ZIP 3 | SPDX-FileType: APPLICATION 4 | -------------------------------------------------------------------------------- /tools/win/man/cat1/pdpmake.1.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2024 Ron Yorston 2 | SPDX-License-Identifier: Unlicense 3 | SPDX-FileType: DOCUMENTATION 4 | 5 | Sources: https://github.com/rmyorston/pdpmake 6 | -------------------------------------------------------------------------------- /zip-content/setprop-settings-list.csv.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: NONE 2 | SPDX-License-Identifier: CC0-1.0 3 | 4 | NOTE: The referenced file contains the list of all the options configurable with setprop. 5 | -------------------------------------------------------------------------------- /recovery-simulator/override/su: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | echo 1>&2 "su: bad usage" 8 | return 1 2>&- || exit 1 9 | -------------------------------------------------------------------------------- /recovery-simulator/override/sudo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | echo 1>&2 "sudo: bad usage" 8 | return 1 2>&- || exit 1 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2007 the original author or authors. 2 | SPDX-License-Identifier: Apache-2.0 3 | SPDX-FileType: ARCHIVE 4 | 5 | Sources: https://github.com/gradle/gradle/tree/master/subprojects/wrapper 6 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | extends: default 6 | rules: 7 | truthy: 8 | allowed-values: ["true", "false", "on"] 9 | line-length: 10 | max: 89 11 | level: warning 12 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | systemProp.file.encoding=UTF-8 5 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 6 | org.gradle.warning.mode=all 7 | org.gradle.parallel=true 8 | org.gradle.caching=true 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Security policy 8 | 9 | You will found the security policy [here](./docs/SECURITY.rst). 10 | -------------------------------------------------------------------------------- /zip-content/META-INF/REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = [ 5 | "com/google/android/updater-script*", 6 | "CERT.RSA", 7 | "CERT.SF", 8 | "MANIFEST.MF" 9 | ] 10 | SPDX-FileCopyrightText = "NONE" 11 | SPDX-License-Identifier = "CC0-1.0" 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8; mode: ruby; frozen_string_literal: true -*- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | source 'https://rubygems.org' 6 | 7 | ruby ">=3.0" 8 | 9 | gem 'bashcov', '>=3.2' 10 | gem 'simplecov-lcov' 11 | -------------------------------------------------------------------------------- /conf-1.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | is_oss_only_build_enabled() 6 | { # 0 => true, 1 => false 7 | return 1 8 | } 9 | 10 | oss_files_to_download() 11 | { 12 | cat << 'EOF' 13 | EOF 14 | } 15 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | coverage: 6 | status: 7 | project: 8 | default: 9 | threshold: 10% 10 | patch: 11 | default: 12 | threshold: 20% 13 | 14 | comment: false 15 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | ale5000 <15793015+ale5000-git@users.noreply.github.com> 5 | ale5000 <15793015+ale5000-git@users.noreply.github.com> <920414-ale5000-git@users.noreply.gitlab.com> 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "timonwong.shellcheck", 4 | "marcovr.actions-shell-scripts", 5 | "codecov.codecov" 6 | ], 7 | "unwantedRecommendations": [ 8 | "vscjava.vscode-java-pack", 9 | "codacy-app.codacy" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tools/win/ver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2024 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # shellcheck enable=all 6 | 7 | if test "${1-}" = '-h' || test "${1-}" = '--help'; then set -- '/?'; fi 8 | MSYS_NO_PATHCONV=1 "${COMSPEC:-${ComSpec:-cmd.exe}}" /c ver "${@}" 9 | -------------------------------------------------------------------------------- /.tgitconfig: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | [core] 5 | hooksPath = .git-hooks 6 | [gpg "ssh"] 7 | allowedSignersFile = allowed_signers 8 | [format] 9 | signOff = true 10 | [tgit] 11 | projectlanguage = 1033 12 | warnnosignedoffby = true 13 | logminsize = 1 14 | -------------------------------------------------------------------------------- /tools/win/busybox.exe.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (C) tons of folks. 2 | SPDX-License-Identifier: GPL-2.0-only 3 | SPDX-FileType: APPLICATION 4 | 5 | Sources: https://github.com/rmyorston/busybox-w32 6 | Binary: https://frippery.org/busybox/ 7 | -------------------------------------------------------------------------------- /tools/win/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2024 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # shellcheck enable=all 6 | 7 | if test "${1-}" = '-h' || test "${1-}" = '--help'; then set -- '/?'; fi 8 | MSYS_NO_PATHCONV=1 "${COMSPEC:-${ComSpec:-cmd.exe}}" /c start "${@}" 9 | -------------------------------------------------------------------------------- /tools/win/busybox-legacy.bin.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (C) tons of folks. 2 | SPDX-License-Identifier: GPL-2.0-only 3 | SPDX-FileType: APPLICATION 4 | 5 | Sources: https://github.com/rmyorston/busybox-w32 6 | Binary: https://frippery.org/busybox/ 7 | -------------------------------------------------------------------------------- /tools/win/man/cat1/busybox.1.gz.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (C) tons of folks. 2 | SPDX-License-Identifier: GPL-2.0-only 3 | SPDX-FileType: DOCUMENTATION 4 | 5 | Sources: https://github.com/rmyorston/busybox-w32 6 | Binary: https://frippery.org/busybox/ 7 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # -*- coding: utf-8; mode: ruby; frozen_string_literal: true -*- 3 | # SPDX-FileCopyrightText: NONE 4 | # SPDX-License-Identifier: CC0-1.0 5 | 6 | require 'simplecov-lcov' 7 | 8 | SimpleCov.configure do 9 | formatter SimpleCov::Formatter::LcovFormatter 10 | add_filter 'gradlew' 11 | end 12 | -------------------------------------------------------------------------------- /recovery-simulator/override/chown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | if test -n "$1"; then 8 | #echo "Dummy chown: $*" 9 | return 0 2>&- || exit 0 10 | fi 11 | 12 | echo 1>&2 "chown: bad usage" 13 | return 1 2>&- || exit 1 14 | -------------------------------------------------------------------------------- /recovery-simulator/override/umount: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | if test -n "$1"; then 8 | echo "Dummy umount: $*" 9 | return 0 2>&- || exit 0 10 | fi 11 | 12 | echo 1>&2 "umount: bad usage" 13 | return 1 2>&- || exit 1 14 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | changelog: 6 | categories: 7 | - title: 🏕 Features 8 | labels: 9 | - '*' 10 | exclude: 11 | labels: 12 | - dependencies 13 | - title: 👒 Dependencies 14 | labels: 15 | - dependencies 16 | -------------------------------------------------------------------------------- /.shellcheckrc: -------------------------------------------------------------------------------- 1 | # mode: conf-unix -*- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | # Follow source statements even when the file is not specified as input 6 | external-sources=true 7 | 8 | # Enable all optional checks 9 | enable=all 10 | 11 | # Disable "Command appears to be unreachable" check 12 | disable=SC2317 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8; mode: conf-javaprop -*- 2 | // SPDX-FileCopyrightText: NONE 3 | // SPDX-License-Identifier: CC0-1.0 4 | 5 | buildscript { 6 | apply from: 'dependencies.gradle' 7 | } 8 | 9 | plugins { 10 | id 'com.gradle.develocity' version "${gradleDevelocityVersion}" /* New name of com.gradle.build-scan */ 11 | } 12 | 13 | rootProject.name = 'Google sync add-on' 14 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | sonar.projectKey=micro5k_google-sync-addon 6 | sonar.organization=micro5k 7 | 8 | # This is the name displayed in the SonarCloud UI 9 | sonar.projectName=Google sync add-on 10 | 11 | # Encoding of the source code. Default is default system encoding 12 | sonar.sourceEncoding=UTF-8 13 | -------------------------------------------------------------------------------- /docs/SUPPORT.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | The best way to get support is to open an Issue_ here on GitHub or to post in the `official support thread`_ on the XDA forum. 7 | 8 | .. _Issue: https://github.com/micro5k/google-sync-addon/issues 9 | .. _Official support thread: https://xdaforums.com/t/3432360/ 10 | -------------------------------------------------------------------------------- /dependencies.gradle: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8; mode: conf-javaprop -*- 2 | // SPDX-FileCopyrightText: NONE 3 | // SPDX-License-Identifier: CC0-1.0 4 | 5 | ext { 6 | // -- GRADLE => https://gradle.org/release-checksums/ -- 7 | gradleVersionTarget = '8.11.1' 8 | gradleSha256Sum = 'f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6' 9 | 10 | // -- DEPENDENCIES -- 11 | gradleDevelocityVersion = '4.3' 12 | } 13 | -------------------------------------------------------------------------------- /zip-content/origin/etc/sysconfig/sysconfig-backup.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitlab/security-scans.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | include: 6 | - template: Security/SAST.gitlab-ci.yml 7 | #- template: Security/License-Scanning.gitlab-ci.yml 8 | #- template: Security/Secret-Detection.gitlab-ci.yml 9 | 10 | sast: 11 | inherit: 12 | variables: false 13 | default: false 14 | 15 | #license_scanning: 16 | # cache: [] 17 | # inherit: 18 | # variables: false 19 | # default: false 20 | -------------------------------------------------------------------------------- /zip-content/module.prop: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8; mode: conf-unix -*- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | numericId=928871 6 | id=google-sync-addon 7 | name=Google sync add-on 8 | version=v1.3.2.39-alpha 9 | versionCode=6 10 | author=ale5000 11 | description=It installs Google sync adapters on Android. 12 | group=net.ale5000 13 | support=https://github.com/micro5k/google-sync-addon/issues 14 | donate=https://liberapay.com/microg-unofficial-by-ale5000/donate 15 | minApi=19 16 | maxApi=36 17 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | 7 | **Want to contribute?** 8 | 9 | If you have a bug or an idea, browse the open issues before opening a new one. You can also take a look at the `Open Source Guide `_. 10 | 11 | 12 | **Working on your first Pull request?** 13 | 14 | You can learn how from this `guide `_. 15 | -------------------------------------------------------------------------------- /recovery-simulator/recovery.bat: -------------------------------------------------------------------------------- 1 | @REM SPDX-FileCopyrightText: (c) 2022 ale5000 2 | @REM SPDX-License-Identifier: GPL-3.0-or-later 3 | @REM SPDX-FileType: SOURCE 4 | 5 | @echo off 6 | SETLOCAL 2> nul 7 | 8 | REM Fix the working directory when using "Run as administrator" 9 | IF "%CD%" == "%windir%\system32" CD /D "%~dp0" 10 | 11 | SET "LANG=en_US.UTF-8" 12 | SET "MAIN_DIR=%~dp0..\" 13 | 14 | "%~dp0..\tools\win\busybox.exe" ash -- "%~dp0recovery.sh" %* 15 | 16 | ENDLOCAL 2> nul 17 | IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% 18 | -------------------------------------------------------------------------------- /zip-content/misc/README.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: NONE 3 | SPDX-License-Identifier: CC0-1.0 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | ==== 7 | MISC 8 | ==== 9 | 10 | - `Android Asset Packaging Tool`_ **0.2-2a587ba28f** (AAPT) => aapt/aapt-\*.bin 11 | - `BusyBox for Android`_ **1.29.2-YDS-201808012015** (`original thread `_) => busybox/busybox-\*.bin 12 | 13 | .. _Android Asset Packaging Tool: https://elinux.org/Android_aapt 14 | .. _BusyBox for Android: https://github.com/yashdsaraf/busybox 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | version: 2 6 | updates: 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | commit-message: 12 | prefix: "build" 13 | include: "scope" 14 | open-pull-requests-limit: 1 15 | - package-ecosystem: "gradle" 16 | directory: "/" 17 | schedule: 18 | interval: "daily" 19 | commit-message: 20 | prefix: "build" 21 | include: "scope" 22 | open-pull-requests-limit: 1 23 | -------------------------------------------------------------------------------- /zip-content/origin/etc/permissions/privapp-permissions-GoogleContactsSyncAdapter12.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /zip-content/origin/etc/permissions/privapp-permissions-GoogleContactsSyncAdapter8.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = [ 5 | ".public-keys/*.gpg", 6 | "fastlane/metadata/android/en-US/*.txt", 7 | "gradle/wrapper/gradle-wrapper.properties", 8 | "allowed_signers", 9 | "Gemfile.lock" 10 | ] 11 | SPDX-FileCopyrightText = "NONE" 12 | SPDX-License-Identifier = "CC0-1.0" 13 | 14 | [[annotations]] 15 | path = [ 16 | ".vscode/*.json" 17 | ] 18 | SPDX-FileCopyrightText = "NONE" 19 | SPDX-License-Identifier = "CC0-1.0" 20 | SPDX-FileComment = [ 21 | "https://code.visualstudio.com/docs/editor/tasks", 22 | "https://code.visualstudio.com/docs/editor/variables-reference" 23 | ] 24 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleBackupTransport4.4.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | bashcov (3.2.0) 5 | simplecov (~> 0.21) 6 | docile (1.4.1) 7 | simplecov (0.22.0) 8 | docile (~> 1.1) 9 | simplecov-html (~> 0.11) 10 | simplecov_json_formatter (~> 0.1) 11 | simplecov-html (0.13.2) 12 | simplecov-lcov (0.9.0) 13 | simplecov_json_formatter (0.1.4) 14 | 15 | PLATFORMS 16 | arm64-darwin 17 | ruby 18 | x64-mingw-ucrt 19 | x86_64-darwin 20 | x86_64-linux 21 | 22 | DEPENDENCIES 23 | bashcov (>= 3.2) 24 | simplecov-lcov 25 | 26 | RUBY VERSION 27 | ruby 3.4.5p51 28 | 29 | BUNDLED WITH 30 | 2.7.2 31 | -------------------------------------------------------------------------------- /zip-content/origin/etc/permissions/privapp-permissions-GoogleBackupTransport4.4.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /allowed_signers: -------------------------------------------------------------------------------- 1 | 15793015+ale5000-git@users.noreply.github.com namespaces="git",valid-after="20250825Z" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBCshlgMBJ9Xo9sjYAJ7Bu9ScHuv6PjfKQlKASmQsHyc 2 | 15793015+ale5000-git@users.noreply.github.com namespaces="git",valid-after="20180802Z",valid-before="20250826Z" ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAgubqZ9RkrK/biXtuFHS9fPaWy/LZPqOpucy/WYLtDz9Br/0ri8H3MetKt92leBMkqWtuecies1Yr4gRRY/FX6DpdBYyogcYfNQFGsL4vonAjzYT3Lx0GUfIvuxldd9N5Q2xa/THVtQDRZdRTJVRRDj14ERu+N8Mh1QjZwY2jZ8STmXMoxWo6HK/UgpFTbD+NsGy/aNQBhy6cPRE9yPzcUyeDNmrWRt3YyzOQuQ8w5DM+CMxgceeu4wiDGeKmxRPG7RWxnQKF4J8kpdG44g91kvAMgs6vdAVnksY4moXUjz43+gQGlCpEdSjuK0NUhD83yN4fk9QzomUyUOTQySpanw== 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "shellcheck.enable": true, 3 | "shellcheck.enableQuickFix": true, 4 | "shellcheck.logLevel": "trace", 5 | "shellcheck.run": "onType", 6 | 7 | "codecov.coverage.enabled": true, 8 | 9 | "codacy.guardrails.analyzeGeneratedCode": "disabled", 10 | "codacy.guardrails.instructionsFile": "manual", 11 | 12 | "java.import.gradle.enabled": false, 13 | "java.import.maven.enabled": false, 14 | "java.autobuild.enabled": false, 15 | "java.showBuildStatusOnStart.enabled": "off", 16 | "java.server.launchMode": "LightWeight", 17 | 18 | "task.autoDetect": "off", 19 | "gradle.autoDetect": "off" 20 | } 21 | -------------------------------------------------------------------------------- /docs/SECURITY.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2022 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | =============== 7 | Security policy 8 | =============== 9 | 10 | Supported versions 11 | ------------------ 12 | 13 | ================= ========= 14 | Version Supported 15 | ================= ========= 16 | Latest version ✔ 17 | Previous versions ❌ 18 | ================= ========= 19 | 20 | 21 | Reporting a Vulnerability 22 | ------------------------- 23 | 24 | This is a flashable ZIP that must be installed manually, so security reports can be added directly in the `Issues <./../../../issues>`_ section. 25 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleCalendarSyncAdapter5.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleCalendarSyncAdapter6.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/INSTRUCTIONS.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | ============ 7 | Instructions 8 | ============ 9 | 10 | You can build it yourself or download the prebuilt version. 11 | 12 | 13 | Build 14 | ----- 15 | 16 | ``./gradlew buildOta`` 17 | 18 | 19 | Download 20 | -------- 21 | 22 | You can find the stable releases here: 23 | 24 | - `Stable - Full flavour `_ 25 | 26 | Instead if you want to try the nightly builds you can find them here: 27 | 28 | - `Nightly - Full flavour `_ 29 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleContactsSyncAdapter4.4.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tools/win/etc/profile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # SPDX-FileCopyrightText: (c) 2024 ale5000 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # shellcheck enable=all 5 | # shellcheck disable=SC3043 # Ignore: In POSIX sh, 'local' is undefined 6 | 7 | __git_ps1() 8 | { 9 | local __prev_exit="${?}" 10 | local __git_branch='' 11 | 12 | __git_branch="$(git 2> /dev/null symbolic-ref HEAD || :)" 13 | __git_branch="${__git_branch##"refs/heads/"}" 14 | if test -n "${__git_branch}"; then 15 | printf -- '%s\n' " (${__git_branch})" 16 | fi 17 | 18 | return "${__prev_exit}" 19 | } 20 | 21 | if test -n "${PS1-}"; then 22 | # shellcheck disable=SC3045 # Ignore: In POSIX sh, export -n is undefined 23 | export -n PS1 || : 24 | export PS1 25 | fi 26 | -------------------------------------------------------------------------------- /zip-content/settings-full.conf: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # -*- coding: utf-8 -*- 3 | # SPDX-FileCopyrightText: NONE 4 | # SPDX-License-Identifier: CC0-1.0 5 | 6 | #################### 7 | # DEFAULT SETTINGS # 8 | #################### 9 | 10 | export LIVE_SETUP_DEFAULT=0 # setprop; local; numeric-boolean 11 | export LIVE_SETUP_TIMEOUT=4 # setprop; local; integer 12 | export DEBUG_LOG=0 # setprop; common; numeric-boolean 13 | 14 | export APP_CONTACTSSYNC=1 # setprop; local; numeric-boolean 15 | export APP_CALENDARSYNC=1 # setprop; local; numeric-boolean 16 | 17 | ################## 18 | # SETTINGS GUIDE # 19 | ################## 20 | 21 | : ' 22 | 23 | :APP_CONTACTSSYNC: 24 | Possible values: 0, 1 25 | :APP_CALENDARSYNC: 26 | Possible values: 0, 1 27 | 28 | ' 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S make -f 2 | 3 | # SPDX-FileCopyrightText: (c) 2024 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | 6 | .POSIX: 7 | 8 | all: buildota buildotaoss ; 9 | 10 | .PHONY: all clean test check distcheck build cmdline 11 | 12 | buildota: 13 | BUILD_TYPE=full "$(CURDIR)/build.sh" --no-default-build-type --no-pause $(ARGS) 14 | 15 | buildotaoss: 16 | BUILD_TYPE=oss "$(CURDIR)/build.sh" --no-default-build-type --no-pause $(ARGS) 17 | build: buildotaoss ; 18 | 19 | test: 20 | "$(CURDIR)/recovery-simulator/recovery.sh" "$(CURDIR)"/output/*.zip 21 | check: test ; 22 | distcheck: check ; 23 | 24 | clean: 25 | rm -f "$(CURDIR)"/output/*.zip 26 | rm -f "$(CURDIR)"/output/*.zip.md5 27 | rm -f "$(CURDIR)"/output/*.zip.sha256 28 | 29 | cmdline: ; 30 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleContactsSyncAdapter8.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /zip-content/origin/etc/default-permissions/default-permissions-GoogleContactsSyncAdapter12.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /recovery-simulator/override/getprop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2023 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | main() 8 | { 9 | # shellcheck disable=SC3043 10 | local _val 11 | 12 | if test -z "${ANDROID_ROOT:-}" || test "${#}" -ge 3 || test ! -f "${ANDROID_ROOT:?}/build.prop"; then 13 | exit 1 14 | fi 15 | 16 | if test "${#}" -ge 1; then 17 | if test -n "${1:-}" && _val="$(grep -m 1 -F -e "${1:?}=" -- "${ANDROID_ROOT:?}/build.prop" | cut -d '=' -f '2-' -s)" && test -n "${_val:-}"; then 18 | printf '%s\n' "${_val:-}" 19 | else 20 | printf '%s\n' "${2:-}" 21 | fi 22 | exit 0 23 | fi 24 | 25 | sed -e 's/=/\]: \[/; s/^/\[/; s/$/\]/' -- "${ANDROID_ROOT:?}/build.prop" || exit 1 26 | } 27 | 28 | main "${@}" 29 | exit 0 30 | -------------------------------------------------------------------------------- /tools/README.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | ===== 7 | TOOLS 8 | ===== 9 | 10 | - zipsigner_ **3.0** => zipsigner.jar 11 | - zipsigner_ **3.0** (Dalvik) => zipsigner-dvk.jar 12 | - `BusyBox for Windows`_ **1.38.0-PRE-5856-g0a97e7906 (2025-10-09)** => win/busybox.exe 13 | - `BusyBox legacy for Windows`_ **1.21.0-TIG-931-g7e6a84d (2012-11-29)** => win/busybox-legacy.bin 14 | - Zip_ **3.0** => win/zip.exe 15 | - UnZip_ **6.0** => win/unzip.exe 16 | 17 | 18 | .. _zipsigner: https://github.com/topjohnwu/Magisk/tree/v20.4/signing 19 | .. _BusyBox for Windows: https://frippery.org/busybox/ 20 | .. _BusyBox legacy for Windows: https://frippery.org/busybox/ 21 | .. _Zip: https://infozip.sourceforge.net/Zip.html 22 | .. _UnZip: https://infozip.sourceforge.net/UnZip.html 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | # Files to ignore in all cases 5 | /.bundle/ 6 | /.cache/ 7 | /.git/ 8 | /.gnupg/ 9 | /.licenses/ 10 | /.ssh/ 11 | /coverage/ 12 | /dependency-graph-reports/ 13 | /vendor/ 14 | /.ash_history 15 | /.bash_history 16 | /.lesshst 17 | /.wget-hsts 18 | __pycache__/ 19 | .DS_Store 20 | Thumbs.db 21 | desktop.ini 22 | *.dex 23 | *.log 24 | *.sarif 25 | 26 | # VS Code files 27 | /.vscode/launch.json 28 | 29 | # Gradle files 30 | /.gradle/ 31 | /build/ 32 | 33 | # Local Gradle configuration files 34 | local.properties 35 | user.gradle 36 | 37 | # Local files to ignore 38 | .debug/ 39 | .local/ 40 | /local/ 41 | /build 42 | /cmdline 43 | 44 | # Custom project folders 45 | /cache/ 46 | /output/ 47 | /recovery-simulator/output/ 48 | /tools/data/ 49 | /utils/data/ 50 | /tools/output/ 51 | /utils/output/ 52 | -------------------------------------------------------------------------------- /.git-hooks/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | # An hook script to prepare the commit log message. 6 | # Called by "git commit" with the name of the file that has the 7 | # commit message, followed by the description of the commit 8 | # message's source. The hook's purpose is to edit the commit 9 | # message file. If the hook fails with a non-zero status, 10 | # the commit is aborted. 11 | 12 | COMMIT_MSG_FILE="${1:?}" 13 | #COMMIT_TYPE="${2?}" 14 | #AMENDED_COMMIT_SHA1="${3-}" 15 | 16 | COMMIT_MSG="$(cat "${COMMIT_MSG_FILE:?}")" || exit 2 17 | GIT_REVERT_REGEX='^Revert\s".*"' 18 | 19 | if [[ -n "${COMMIT_MSG?}" && "${COMMIT_MSG:?}" =~ ${GIT_REVERT_REGEX:?} ]]; then 20 | COMMIT_MSG="${COMMIT_MSG/#Revert/revert:}" 21 | COMMIT_MSG="${COMMIT_MSG/This reverts commit/Refs:}" 22 | printf '%s' "${COMMIT_MSG?}" 1> "${COMMIT_MSG_FILE:?}" 23 | fi 24 | 25 | exit 0 26 | -------------------------------------------------------------------------------- /zip-content/misc/REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = [ 5 | "busybox/busybox-*.bin" 6 | ] 7 | SPDX-FileCopyrightText = "Copyright (C) tons of folks. " 8 | SPDX-License-Identifier = "GPL-2.0-only" 9 | SPDX-FileType = "APPLICATION" 10 | SPDX-FileComment = [ 11 | "Sources: https://github.com/yashdsaraf/busybox", 12 | "Binaries: https://github.com/yashdsaraf/bb-bot/releases" 13 | ] 14 | 15 | [[annotations]] 16 | path = [ 17 | "aapt/aapt-*.bin" 18 | ] 19 | SPDX-FileCopyrightText = "(c) 2005-2008 The Android Open Source Project" 20 | SPDX-License-Identifier = "Apache-2.0" 21 | SPDX-FileType = "APPLICATION" 22 | SPDX-FileComment = [ 23 | "Sources: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/tools/aapt/", 24 | "Binaries: https://github.com/substratum/substratum/tree/83f0847194c5d0adad714fbccd5573323c21be5b/app/src/main/assets" 25 | ] 26 | -------------------------------------------------------------------------------- /recovery-simulator/inc/configure-overrides.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | if test -z "${OVERRIDE_DIR:-}" || test -z "${BB_OVERRIDE_APPLETS:-}"; then 6 | echo 'Failed to configure overrides!!!' 7 | exit 124 8 | fi 9 | 10 | rs_function_exists() 11 | { 12 | # shellcheck disable=SC2312 13 | LC_ALL=C type "${1:?}" 2> /dev/null | grep -Fq -- 'is a function' 14 | return "${?}" 15 | } 16 | 17 | rs_override_command() 18 | { 19 | if rs_function_exists "${1:?}"; then return 0; fi 20 | if test ! -e "${OVERRIDE_DIR:?}/${1:?}"; then return 1; fi 21 | eval " ${1:?}() { '${OVERRIDE_DIR:?}/${1:?}' \"\${@}\"; }" # The folder expands when defined, not when used 22 | return "${?}" 23 | } 24 | 25 | for _rs_cur_override_applet in ${BB_OVERRIDE_APPLETS:?}; do 26 | rs_override_command "${_rs_cur_override_applet:?}" || exit 125 27 | done 28 | unset _rs_cur_override_applet 29 | 30 | unset -f rs_override_command 31 | unset -f rs_function_exists 32 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | root = true 5 | 6 | [{cache,output,gradlew,gradlew.bat,.git,.gradle,.ash_history}] 7 | ignore = true 8 | 9 | [*.{jar,apk,bin,exe}] 10 | ignore = true 11 | 12 | [*] 13 | charset = utf-8 14 | end_of_line = lf 15 | 16 | indent_style = space 17 | indent_size = 2 18 | trim_trailing_whitespace = true 19 | insert_final_newline = true 20 | 21 | max_line_length = 80 22 | quote_type = single 23 | curly_bracket_next_line = true 24 | 25 | shell_variant = posix 26 | switch_case_indent = true 27 | space_redirects = true 28 | function_next_line = true 29 | 30 | [Makefile] 31 | indent_style = tab 32 | 33 | [*.bat] 34 | end_of_line = crlf 35 | 36 | [*.{xml,json,gradle}] 37 | indent_size = 4 38 | 39 | [*.{yml,yaml,rst,md,json}] 40 | quote_type = double 41 | 42 | [zip-content/customize.sh] 43 | keep_padding = true 44 | 45 | [.git-hooks/*] 46 | shell_variant = bash 47 | 48 | [recovery-simulator/recovery.sh] 49 | shell_variant = bash 50 | -------------------------------------------------------------------------------- /cmdline.bat: -------------------------------------------------------------------------------- 1 | @REM SPDX-FileCopyrightText: (c) 2016 ale5000 2 | @REM SPDX-License-Identifier: GPL-3.0-or-later 3 | @REM SPDX-FileType: SOURCE 4 | 5 | @echo off 6 | SETLOCAL 2> nul 7 | 8 | REM Fix the working directory when using "Run as administrator" 9 | IF "%CD%" == "%windir%\system32" CD /D "%~dp0" 10 | 11 | IF NOT EXIST "%~dp0tools\win\busybox.exe" ( 12 | ENDLOCAL 2> nul 13 | ECHO BusyBox is missing 14 | EXIT /B 127 15 | ) 16 | 17 | SET "LANG=en_US.UTF-8" 18 | SET "MAIN_DIR=%~dp0" 19 | 20 | IF "%USER_HOME%" == "" ( 21 | IF "%TERM_PROGRAM%" == "mintty" SET "TERM_PROGRAM=mintty-" 22 | SET "USER_HOME=%USERPROFILE%" 23 | SET "HOME=%MAIN_DIR%" 24 | ) 25 | 26 | SET "DO_INIT_CMDLINE=1" 27 | SET "KILL_PPID=1" 28 | SET "STARTED_FROM_BATCH_FILE=1" 29 | SET "IS_PATH_INITIALIZED=" 30 | SET "__QUOTED_PARAMS=" 31 | SET "__SHELL_EXE=%~dp0tools\win\busybox.exe" 32 | 33 | "%__SHELL_EXE%" ash -s -c ". '%~dp0includes\common.sh' || exit ${?}" "ash" %* 34 | 35 | ENDLOCAL 2> nul 36 | IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% 37 | -------------------------------------------------------------------------------- /recovery-simulator/updater.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # shellcheck enable=all 6 | 7 | # Ensure that the overridden commands are preferred over BusyBox applets (and that unsafe commands aren't accessible) 8 | export BB_OVERRIDE_APPLETS='mount umount chown su sudo' || exit 125 9 | 10 | # shellcheck source=SCRIPTDIR/inc/configure-overrides.sh 11 | . "${RS_OVERRIDE_SCRIPT:?}" || exit "${?}" 12 | 13 | # Note: Bashcov use PS4, LINENO, BASH_XTRACEFD, SHELLOPTS (don't touch them) 14 | # ToDO: Check BASHCOV_BASH_PATH 15 | 16 | unset OUR_TEMP_DIR 17 | unset HOSTNAME 18 | unset HOSTTYPE 19 | unset MACHTYPE 20 | unset OSTYPE 21 | unset OPTERR 22 | unset OPTIND 23 | 24 | # IFS change is intended 25 | # nosemgrep 26 | IFS=' 27 | ' 28 | PS1='\w \$ ' 29 | PS2='> ' 30 | if test "${COVERAGE:-false}" = 'false'; then 31 | PS4='+ ' 32 | fi 33 | 34 | OSTYPE='linux-androideabi' 35 | 36 | # shellcheck source=SCRIPTDIR/../zip-content/META-INF/com/google/android/update-binary.sh 37 | . "${TMPDIR:?}/update-binary" || exit "${?}" 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "✅ Feature request" 6 | description: Suggest a new feature or an idea to improve this software. 7 | labels: ["enhancement", "needs triage"] 8 | assignees: 9 | - ale5000-git 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: | 14 | Thanks for taking the time to fill out this feature request! 15 | - type: checkboxes 16 | id: checklist 17 | attributes: 18 | label: Checklist 19 | options: 20 | - label: I have updated your software to the **latest version** and I have verified that the requested feature is **NOT** already in it. 21 | required: true 22 | - label: I made sure that there weren't already **[feature requests](../labels/enhancement)** for the same feature. 23 | required: true 24 | - type: textarea 25 | id: feature-description 26 | attributes: 27 | label: Feature description 28 | description: Explain in detail the feature you would like to have. 29 | validations: 30 | required: true 31 | -------------------------------------------------------------------------------- /.github/workflows/code-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Code lint" 6 | permissions: {} 7 | on: 8 | push: 9 | paths: 10 | - "**" 11 | branches: 12 | - "**" 13 | tags: 14 | - "v*.*" 15 | pull_request: 16 | jobs: 17 | shellchecker: 18 | name: "ShellChecker" 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 5 21 | 22 | steps: 23 | - name: "Checkout sources" 24 | uses: actions/checkout@v6 25 | - name: "ShellChecker" 26 | uses: a5k-actions/shellchecker@v0 27 | 28 | reuse: 29 | name: "REUSE compliance check" 30 | runs-on: ubuntu-latest 31 | timeout-minutes: 5 32 | #if: "${{ false }}" 33 | 34 | steps: 35 | - name: "Checkout sources" 36 | uses: actions/checkout@v6 37 | - name: "REUSE compliance check" 38 | uses: fsfe/reuse-action@v6 39 | 40 | json-yaml-validate: 41 | name: "JSON and YAML" 42 | runs-on: ubuntu-latest 43 | timeout-minutes: 10 44 | 45 | steps: 46 | - name: "Checkout sources" 47 | uses: actions/checkout@v6 48 | - name: "JSON and YAML - Validator" 49 | uses: GrantBirki/json-yaml-validate@v4 50 | -------------------------------------------------------------------------------- /LICENSES/Unlicense.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /tools/help.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2024 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # shellcheck enable=all 6 | 7 | if test -z "${MODULE_NAME-}" || test -z "${MAIN_DIR-}" || test -z "${PLATFORM-}" || test -z "${IS_BUSYBOX-}"; then 8 | echo 'ERROR: You must first run cmdline.sh or cmdline.bat and then you can type: help' 9 | exit 1 10 | fi 11 | 12 | aligned_print() 13 | { 14 | printf '%-15s %s\n' "${@}" 15 | } 16 | 17 | printf '%s\n' "${MODULE_NAME:?} help" 18 | printf '%s\n\n' 'Licensed under GPLv3+' 19 | 20 | aligned_print 'COMMAND' 'DESCRIPTION' 21 | aligned_print '-------' '-----------' 22 | printf '\n' 23 | 24 | aligned_print 'help' 'Show this help' 25 | aligned_print 'shellhelp' 'Show the original help of the shell' 26 | printf '\n' 27 | 28 | aligned_print 'build' 'Build the flashable OTA zip (set the BUILD_TYPE env var to choose what to build)' 29 | aligned_print 'make' 'Execute "make" of your PC (on Windows it fallback to internal "pdpmake" if no make is found)' 30 | if test "${PLATFORM:?}" = 'win'; then 31 | aligned_print 'pdpmake' 'Execute the internal "pdpmake"' 32 | else 33 | aligned_print 'pdpmake' 'Execute "pdpmake" of your PC' 34 | fi 35 | aligned_print 'gradlew' 'Execute the Gradle wrapper' 36 | aligned_print 'cmdline' 'Execute our command-line (if you are already inside, then it will be executed in a subshell)' 37 | printf '\n' 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "🐞 Bug report" 6 | description: Report a bug to help improve this software. 7 | labels: ["bug", "needs triage"] 8 | assignees: 9 | - ale5000-git 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: | 14 | Thanks for taking the time to fill out this bug report! 15 | - type: textarea 16 | id: what-happened 17 | attributes: 18 | label: What happened? 19 | description: Also tell us, what did you expect to happen? 20 | validations: 21 | required: true 22 | - type: input 23 | id: version 24 | attributes: 25 | label: Version 26 | description: What version of our software are you running? 27 | placeholder: "e.g. 1.2.0-beta" 28 | validations: 29 | required: true 30 | - type: input 31 | id: android-version 32 | attributes: 33 | label: Android version 34 | description: What version of Android do you use? 35 | placeholder: "e.g. 10" 36 | validations: 37 | required: true 38 | - type: input 39 | id: custom-rom 40 | attributes: 41 | label: Custom ROM 42 | description: What ROM are you using? 43 | placeholder: "e.g. LineageOS 17.1" 44 | validations: 45 | required: true 46 | - type: textarea 47 | id: logs 48 | attributes: 49 | label: Relevant log output 50 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 51 | render: log 52 | -------------------------------------------------------------------------------- /recovery-simulator/override/mount: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: (c) 2022 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # SPDX-FileType: SOURCE 6 | 7 | if test -n "$1"; then 8 | echo "Dummy mount: $*" 9 | return 0 2>&- || exit 0 10 | fi 11 | 12 | echo "\ 13 | rootfs on / type rootfs (rw,seclabel) 14 | tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,mode=755) 15 | devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600) 16 | proc on /proc type proc (rw,relatime) 17 | sysfs on /sys type sysfs (rw,seclabel,relatime) 18 | selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime) 19 | tmpfs on ${TMPDIR:?} type tmpfs (rw,seclabel,relatime) 20 | ${TMPDIR:?} on /tmp type tmpfs (rw,seclabel,relatime) 21 | /dev/block/bootdevice/by-name/userdata on ${ANDROID_DATA:?} type ext4 (rw,seclabel,relatime,data=ordered) 22 | ${ANDROID_DATA:?} on /data type ext4 (rw,seclabel,relatime,data=ordered) 23 | /dev/block/bootdevice/by-name/cache on /cache type ext4 (rw,seclabel,relatime,data=ordered) 24 | /dev/block/bootdevice/by-name/sdcard0 on /sdcard0 type vfat (rw,relatime,errors=remount-ro) 25 | /dev/block/bootdevice/by-name/sdcard1 on /sdcard1 type vfat (rw,relatime,errors=remount-ro) 26 | /dev/block/bootdevice/by-name/system on ${ANDROID_ROOT:?} type ext4 (rw,seclabel,relatime,data=ordered) 27 | ${ANDROID_ROOT:?} on /system type ext4 (rw,seclabel,relatime,data=ordered)\ 28 | /system/system_ext on /system_ext type ext4 (rw,seclabel,relatime,data=ordered)\ 29 | /system/product on /product type ext4 (rw,seclabel,relatime,data=ordered)\ 30 | /system/vendor on /vendor type ext4 (rw,seclabel,relatime,data=ordered)\ 31 | " 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: NONE 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | * text=auto 5 | 6 | .git-hooks/* text eol=lf 7 | .gitattributes text eol=lf 8 | .gitignore text eol=lf 9 | .gitmodules text eol=lf 10 | .tgitconfig text eol=lf 11 | allowed_signers text eol=lf 12 | 13 | docs/CODEOWNERS text eol=lf 14 | .editorconfig text eol=lf 15 | .mailmap text eol=lf 16 | .semgrepignore text eol=lf 17 | .shellcheckrc text eol=lf 18 | .tool-versions text eol=lf 19 | 20 | *.gpg text eol=lf 21 | *.yml text eol=lf 22 | *.xml text eol=lf 23 | *.json text eol=lf 24 | *.dis text eol=lf 25 | 26 | # Reuse 27 | .reuse/dep5 text eol=lf 28 | *.toml text eol=lf 29 | *.license text eol=lf 30 | *.spdx text eol=lf 31 | 32 | # Ruby 33 | .simplecov text eol=lf 34 | Gemfile* text eol=lf 35 | 36 | # Make 37 | Makefile text eol=lf 38 | 39 | # Batch scripts 40 | *.bat text eol=crlf 41 | 42 | # Gradle files 43 | gradlew text eol=lf 44 | *.gradle text eol=lf 45 | 46 | # Textual formats 47 | *.properties text eol=lf 48 | *.rst text eol=lf 49 | *.md text eol=lf 50 | *.txt text eol=lf 51 | 52 | # Textual data 53 | *.dat text eol=lf 54 | 55 | # Our files 56 | *.prop text eol=lf 57 | *.conf text eol=lf 58 | *.bats text eol=lf 59 | *.sh text eol=lf 60 | *.ash text eol=lf 61 | *.bash text eol=lf 62 | *.py text eol=lf 63 | 64 | # Our custom files 65 | recovery-simulator/override/* text eol=lf 66 | tools/win/etc/profile text eol=lf 67 | 68 | # Uncompressed text manuals 69 | *.1 text eol=lf 70 | 71 | # Binaries 72 | *.exe binary 73 | *.bin binary 74 | *.apk binary 75 | *.zip binary 76 | *.jar binary 77 | *.gz binary 78 | *.png binary 79 | *.jpg binary 80 | -------------------------------------------------------------------------------- /.git-hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | # An hook script to check the commit log message. 6 | # Called by "git commit" with one argument, the name of the file 7 | # that has the commit message. The hook should exit with non-zero 8 | # status after issuing an appropriate message if it wants to stop the 9 | # commit. The hook is allowed to edit the commit message file. 10 | 11 | COMMIT_MSG_FILE="${1:?}" 12 | 13 | COMMIT_MSG="$(cat "${COMMIT_MSG_FILE:?}")" || exit 2 14 | CONVENTIONAL_COMMIT_REGEX='^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\([a-zA-Z0-9_.-]+\))?(!)?:\s.*$' 15 | 16 | # Check if the commit message matches the regex. 17 | if ! [[ "${COMMIT_MSG?}" =~ ${CONVENTIONAL_COMMIT_REGEX:?} ]]; then 18 | { 19 | echo "ERROR: Commit message does not follow Conventional Commits format." 20 | echo "" 21 | echo "The commit message should be structured as follows:" 22 | echo "(): " 23 | echo "[optional body]" 24 | echo "[optional footer(s)]" 25 | echo "" 26 | echo "Valid types are:" 27 | echo " feat: A new feature." 28 | echo " fix: A bug fix." 29 | echo " docs: Documentation changes." 30 | echo " style: Code style changes (formatting, missing semicolons, etc.)." 31 | echo " refactor: Code refactoring (neither fixes a bug nor adds a feature)." 32 | echo " test: Adding or updating tests." 33 | echo " chore: Routine tasks like updating dependencies or build tools." 34 | echo " build: Changes affecting the build system or external dependencies." 35 | echo " ci: Changes to CI configuration files or scripts." 36 | echo " perf: Performance improvements." 37 | echo " revert: Reverting a previous commit." 38 | echo "" 39 | echo "Examples:" 40 | echo " feat(auth): add login functionality" 41 | echo " fix(api)!: resolve timeout issue" 42 | echo " docs(readme): update installation instructions" 43 | echo "" 44 | } 1>&2 45 | exit 1 46 | fi 47 | 48 | grep -m 1 -e '^Signed-off-by: ' -- "${COMMIT_MSG_FILE:?}" || { 49 | echo 1>&2 "Missing Signed-off-by line." 50 | exit 46 51 | } 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-License-Identifier: GPL-3.0-or-later 3 | SPDX-FileType: DOCUMENTATION 4 | 5 | ================== 6 | Google sync add-on 7 | ================== 8 | :Author: `ale5000 `_ 9 | :License: `GPLv3.0 or later `_ 10 | 11 | .. image:: https://codecov.io/gh/micro5k/google-sync-addon/branch/main/graph/badge.svg 12 | :alt: Coverage 13 | :target: https://codecov.io/gh/micro5k/google-sync-addon 14 | 15 | 16 | Description 17 | ----------- 18 | Google sync add-on is a flashable zip created by ale5000 for a simple installation of Google sync adapters on Android from 4.4 to 16 (excluding Android 6.x). 19 | 20 | This project is available on GitHub_, on GitLab_ as well as on XDA_. 21 | 22 | .. _GitHub: https://github.com/micro5k/google-sync-addon 23 | .. _GitLab: https://gitlab.com/micro5k/google-sync-addon 24 | .. _XDA: https://xdaforums.com/t/3432360/ 25 | 26 | .. image:: https://liberapay.com/assets/widgets/donate.svg 27 | :alt: Donate using Liberapay 28 | :target: https://liberapay.com/microg-unofficial-by-ale5000/donate 29 | 30 | 31 | Download 32 | -------- 33 | .. image:: https://img.shields.io/github/v/release/micro5k/google-sync-addon.svg?cacheSeconds=3600 34 | :alt: GitHub latest release 35 | :target: `Download`_ 36 | 37 | `Download instructions `_ 38 | 39 | 40 | Copyright 41 | --------- 42 | © 2016-2019, 2021-2025 ale5000 43 | 44 | 45 | Code analysis 46 | ------------- 47 | .. image:: https://github.com/micro5k/google-sync-addon/actions/workflows/code-lint.yml/badge.svg 48 | :alt: Code lint workflow 49 | :target: https://github.com/micro5k/google-sync-addon/actions/workflows/code-lint.yml 50 | 51 | .. image:: https://www.codefactor.io/repository/github/micro5k/google-sync-addon/badge 52 | :alt: CodeFactor Badge 53 | :target: https://www.codefactor.io/repository/github/micro5k/google-sync-addon 54 | 55 | .. image:: https://app.codacy.com/project/badge/Grade/0a3cd4857c224c59afa38e4cdfeb9486 56 | :alt: Codacy Badge 57 | :target: https://app.codacy.com/gh/micro5k/google-sync-addon/dashboard 58 | 59 | .. image:: https://sonarcloud.io/api/project_badges/measure?project=micro5k_google-sync-addon&metric=reliability_rating 60 | :alt: SonarQube reliability rating 61 | :target: https://sonarcloud.io/summary/new_code?id=micro5k_google-sync-addon 62 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | variables: 6 | GIT_DEPTH: 1 7 | FF_USE_FASTZIP: true 8 | CACHE_COMPRESSION_LEVEL: "fastest" 9 | ARTIFACT_COMPRESSION_LEVEL: "fastest" 10 | 11 | workflow: 12 | auto_cancel: 13 | on_new_commit: "interruptible" 14 | 15 | default: 16 | image: "eclipse-temurin:17-jdk-alpine" 17 | interruptible: true 18 | cache: 19 | key: "cache-build" 20 | paths: [cache/build] 21 | when: "always" 22 | before_script: | 23 | # Install dependencies 24 | apk add bash zip~=3.0 wget || exit "${?}" 25 | 26 | stages: 27 | - build 28 | - test 29 | 30 | # Temporarily disabled 31 | .build-oss-job: 32 | stage: build 33 | timeout: "5 minutes" 34 | rules: 35 | - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 36 | changes: 37 | - "LICENSES/**" 38 | - "includes/**" 39 | - "tools/*.jar" 40 | - "tools/*.sh" 41 | - "zip-content/**" 42 | - "CHANGELOG.rst" 43 | - "LICENSE*.rst" 44 | - "build.sh" 45 | - "conf-*.sh" 46 | when: always 47 | cache: [] 48 | script: "BUILD_TYPE='oss' './build.sh'" 49 | 50 | build-job: 51 | stage: build 52 | timeout: "5 minutes" 53 | rules: 54 | - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 55 | changes: 56 | - "LICENSES/**" 57 | - "includes/**" 58 | - "tools/*.jar" 59 | - "tools/*.sh" 60 | - "zip-content/**" 61 | - "CHANGELOG.rst" 62 | - "LICENSE*.rst" 63 | - "build.sh" 64 | - "conf-*.sh" 65 | when: always 66 | - if: $CI_PIPELINE_SOURCE == "schedule" 67 | when: always 68 | - if: $CI_PIPELINE_SOURCE == "web" # Started manually on the GitLab website 69 | when: always 70 | script: "BUILD_TYPE='full' './build.sh'" 71 | artifacts: 72 | paths: 73 | - "output/*.zip*" 74 | expire_in: "15 minutes" 75 | 76 | # Cache expiration: 14 days 77 | ping-cache: 78 | stage: build 79 | interruptible: false 80 | timeout: "5 minutes" 81 | rules: 82 | - if: $CI_PIPELINE_SOURCE == "schedule" 83 | when: always 84 | before_script: [] 85 | script: "test ! -d './cache/build' || date -u -- '+%s' 1> './cache/build/last-ping.dat'" 86 | 87 | # Temporarily disabled 88 | #include: ".gitlab/security-scans.yml" 89 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | ========= 7 | Changelog 8 | ========= 9 | 10 | All notable changes to this project will be documented in this file. 11 | 12 | 13 | `Unreleased`_ 14 | ------------- 15 | - Click above to see all the changes. 16 | 17 | `1.2.0-beta`_ - 2022-12-31 18 | -------------------------- 19 | - Update Google Contacts Sync to 8.1.0 on recent devices (tested) 20 | - Update Google Calendar Sync to 5.2.3 on older devices 21 | - Add Google Calendar Sync 6.0.44 for recent devices (tested) 22 | - Improve installation performance by verifying only the files that are really installed 23 | - Add support for addon.d 24 | - Improve uninstaller 25 | - Refactored some code, now most apps can be enabled/disabled directly in the Live setup 26 | - Add an helper script (:code:`zip-install.sh`) for the installation of the flashable zip via terminal or via ADB (recovery not needed) 27 | - Sync setup with microG unofficial installer 28 | 29 | `1.0.3-beta`_ 30 | ------------- 31 | - Updated Google Contacts Sync to 8.0.0 for Nougat (tested) 32 | - Improved Google sync add-on / GApps uninstaller 33 | 34 | `1.0.2-alpha`_ 35 | -------------- 36 | - Released sources on GitHub 37 | - Added Google Calendar Sync for KitKat 38 | - Changed signing process to fix a problem with Dingdong Recovery and maybe other old recoveries 39 | - Added default permissions 40 | - Reset permissions on dirty installations 41 | - Temporarily disabled support for Marshmallow until the problems are fixed 42 | - Almost complete rewrite of the installer, so the error 4 is finally gone 43 | - Too many changes to remember 44 | 45 | 1.0.1-beta 46 | ---------- 47 | - Added support for Android 6.0 - 8.0 48 | - Added Google Contacts Sync O 49 | - Added Google Calendar Sync 5.2.3-99827563 50 | 51 | 1.0.0-beta 52 | ---------- 53 | - Initial release 54 | 55 | 56 | .. _Unreleased: https://github.com/micro5k/google-sync-addon/compare/v1.2.0-beta...HEAD 57 | .. _1.2.0-beta: https://github.com/micro5k/google-sync-addon/compare/7d869eb31a90645b742c434001df9f0ac6df0a76...v1.2.0-beta 58 | .. _1.0.3-beta: https://github.com/micro5k/google-sync-addon/compare/572b41b384523f24028ff5c11dc898054b0b3145...7d869eb31a90645b742c434001df9f0ac6df0a76 59 | .. _1.0.2-alpha: https://github.com/micro5k/google-sync-addon/tree/572b41b384523f24028ff5c11dc898054b0b3145 60 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "presentation": { 4 | "reveal": "always", 5 | "revealProblems": "onProblem" 6 | }, 7 | "tasks": [ 8 | { 9 | "label": "buildOta", 10 | "detail": "$(tools) Build the flashable OTA zip.", 11 | "type": "shell", 12 | "command": "${workspaceFolder}/build.sh", 13 | "windows": { 14 | "command": "${workspaceFolder}\\build.bat" 15 | }, 16 | "options": { 17 | "env": { 18 | "BUILD_TYPE": "full" 19 | } 20 | }, 21 | "group": { 22 | "kind": "build" 23 | }, 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "label": "buildOtaOSS", 28 | "detail": "$(tools) Build the flashable OTA zip (open-source components only).", 29 | "type": "shell", 30 | "command": "${workspaceFolder}/build.sh", 31 | "windows": { 32 | "command": "${workspaceFolder}\\build.bat" 33 | }, 34 | "options": { 35 | "env": { 36 | "BUILD_TYPE": "oss" 37 | } 38 | }, 39 | "group": { 40 | "kind": "build", 41 | "isDefault": true 42 | }, 43 | "problemMatcher": [] 44 | }, 45 | { 46 | "label": "test", 47 | "detail": "Emulate an Android recovery on your PC and run the flashable zip file inside it to see the result.", 48 | "type": "shell", 49 | "command": "${workspaceFolder}/recovery-simulator/recovery.sh", 50 | "args": [ 51 | "${workspaceFolder}/output/*.zip" 52 | ], 53 | "windows": { 54 | "command": "${workspaceFolder}\\recovery-simulator\\recovery.bat", 55 | "args": [ 56 | "${workspaceFolder}\\output\\*.zip" 57 | ] 58 | }, 59 | "options": { 60 | "env": { 61 | "BB_GLOBBING": "1" 62 | } 63 | }, 64 | "group": { 65 | "kind": "test", 66 | "isDefault": true 67 | }, 68 | "presentation": { 69 | "panel": "dedicated" 70 | }, 71 | "problemMatcher": [] 72 | } 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /.public-keys/github.gpg: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | xsBNBFmUaEEBCACzXTDt6ZnyaVtueZASBzgnAmK13q9Urgch+sKYeIhdymjuMQta 4 | x15OklctmrZtqre5kwPUosG3/B2/ikuPYElcHgGPL4uL5Em6S5C/oozfkYzhwRrT 5 | SQzvYjsE4I34To4UdE9KA97wrQjGoz2Bx72WDLyWwctD3DKQtYeHXswXXtXwKfjQ 6 | 7Fy4+Bf5IPh76dA8NJ6UtjjLIDlKqdxLW4atHe6xWFaJ+XdLUtsAroZcXBeWDCPa 7 | buXCDscJcLJRKZVc62gOZXXtPfoHqvUPp3nuLA4YjH9bphbrMWMf810Wxz9JTd3v 8 | yWgGqNY0zbBqeZoGv+TuExlRHT8ASGFS9SVDABEBAAHNNUdpdEh1YiAod2ViLWZs 9 | b3cgY29tbWl0IHNpZ25pbmcpIDxub3JlcGx5QGdpdGh1Yi5jb20+wsBoBBMBCAAc 10 | BQJZlGhBCRBK7hj4Ov3rIwIbAwUJDBJ3/wIZAQAA0O4IAJd0k8M+urETyMvTqNTj 11 | /U6nbqyOdKE4V93uUj5G7sNTfno7wod/Qjj6Zv5KodvA93HmEdQqsmVq5YJ5KGiw 12 | cmGCpd/GqJRPaYSY0hSUSBqYHiHLusCJkPBpQTBhcEMtfVCB2J6fVeoX2DV0K1xf 13 | CGblrSVB0viAxUMnmL5C55RuvbYZsTu8szXhkvIR96CtWbJ8QGaEf1/KSpWz8ept 14 | Y/omf3UPfvdOjnsxc8jVEqPNaR9xC6Q6t53rBa/XgMY6IYyesnyYnc5O6JuexUFa 15 | VjykRFtAiYfDaMARpXOmgMm0lhoBRKb/uMUaN3CSYTmE4pZweJcUi7eWgmoQljX2 16 | ut6ZAg0EZabFdgEQALI37i+IVAzpBCgqvQDZbSsZ0yhtMnA5myjZA+l7BvIGy4ve 17 | s1bk6YetbBcCE8o2pQjI7N2rwyhLGhNO6ouSyhqGLEQv9fafKE4HFH0aRjP+gj1H 18 | edhwtFoVChImhV863rWimQtTNtYB6GluBPwQqWfwmwQ2rT7ScOVZCLSHZD2gaaqW 19 | BXOyTCZVnwt7K/gyDuE3qzDJnuahl+SSkPn5TtnZdW6sLORJJ+DjNvaUxEsmizZ4 20 | IBzvj0QKxfS3s4F+0X5iqCMheLFeybZGtSq9Tjs6Q61l4CG8Bh6dsLemv0WFrk3G 21 | gFQRr7XUwr1bo5xGHC/FUJSsxRHoVNJnIL/9WldNO2tGU6qlTnAYxs/fOmf2B6o5 22 | cKXysXv7WAA8b+j5AVBMGxUSu7CLglaiCJC5DI7AAiUV7/t29rFZkam//Jbb4veC 23 | 4vvFocoVUaxrKGWK1BDldr4/WJKApJcPJF4Jtai1+oB6ak/JIjbkseHdJxcjo2B0 24 | dKtIFoWiPAB+DFs9MRDpp0iwocJCh+ucus1rdQ54YMaI44rRphXeOIQMYCi5q2Q1 25 | /arzkSiyPV/2VoKoAfdgskPt1xKd7WIKErmpFMHIy8jJ5IPQ1s2dUwU4alfJLJa0 26 | pvaV2m7wBYFAmwmz0WZgFxYAYEDamn4jFoKfqsEgcixRUVE3w5VkqwSwGRbLABEB 27 | AAG0G0dpdEh1YiA8bm9yZXBseUBnaXRodWIuY29tPokCTgQTAQoAOBYhBJaEeaGv 28 | +SfjfRpWa7VpDu67lSGUBQJlpsV2AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA 29 | AAoJELVpDu67lSGUgy4QAKW9XAL416iKrQB2LElmxqAoenHVCswlau0xGLh5dVNN 30 | p5f4/W6eEL8CZI7hfF3e5Gh6Me99aHgXSCK1QnxcqCJ6Oea4ZyrsNu3k6g7Um5ca 31 | VbYFD4yIahhXDYHSw6FYM2sgFY479YvgvKRwacC2tFfChLRbHgwLJ3O1dBjmVycJ 32 | Zpbyu+7taZ26g6KQfgcj3uuo3nz3p1ziIEpLHwtl/7joNEIIP/lJ8AKmUHPiGznN 33 | 6fxMvzN37PGMWtdvOi1rSNIMQYr1YY7jPnlLbFJwLrO/q/cGPU5HwGzlqh0a2ZqY 34 | dnuwT3DREmgJ83H71xH+sTzZKs5oGlVTu6st7iWDvNpo2GoN01XzKa5caYglqsOC 35 | uZ6IHlsdL50sXMtSROCi3hEWU9r1sWIm4k3pNz20y7lElD2X/MqbEMcgpawCV7lH 36 | rm7MSrTgu6BNAF0SisbF9AKwXaBr2dwpMMyIBOFZO9mk4/c0n9q2FlGY4GkbgH2J 37 | HqulFTwX/4yiQbh8gzCe+06FZAWITN1OQntTkkCQ+1MCZPf+bOfC08RTsOsVZIYB 38 | 2qAgw6XE0IF4a+PAtHSoYftwH2ocMY2gMuSNpQWm7m0+/j+K+RBoeUcnGNPQgszq 39 | N60IDMqkqHjyubrm2aslfopWmPSvaQoyxwV/uztdo+UI0IV2z9gD7Sm49vMkpYp8 40 | =uMz0 41 | -----END PGP PUBLIC KEY BLOCK----- -------------------------------------------------------------------------------- /zip-content/origin/addon.d/00-1-google-sync.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # ADDOND_VERSION=3 3 | # SPDX-FileCopyrightText: NONE 4 | # SPDX-License-Identifier: CC0-1.0 5 | 6 | VANITY_NAME='Google sync add-on' 7 | 8 | _fix_tmpdir() 9 | { 10 | # In some cases ${TMPDIR} is not set and it cause errors with HereDocs 11 | if test -z "${TMPDIR-}" || test ! -w "${TMPDIR:?}"; then 12 | if test -w '/tmp'; then TMPDIR='/tmp'; elif test -w '/data/local/tmp'; then TMPDIR='/data/local/tmp'; elif test -w '/postinstall/tmp'; then TMPDIR='/postinstall/tmp'; fi 13 | fi 14 | } 15 | 16 | _init_debug_log() 17 | { 18 | test -z "${DEBUG_LOG-}" || return 19 | _fix_tmpdir 20 | DEBUG_LOG=0 21 | DEBUG_LOG_FILE='' 22 | 23 | if command 1> /dev/null -v 'getprop' && test "$(getprop 'zip.common.DEBUG_LOG' '0' || :)" = 1; then 24 | if test -n "${TMPDIR-}" && test -w "${TMPDIR:?}" && DEBUG_LOG_FILE="${TMPDIR:?}/debug-a5k.log" && touch "${DEBUG_LOG_FILE:?}"; then 25 | echo 1>&2 "Writing log: ${DEBUG_LOG_FILE?}" 26 | DEBUG_LOG=1 27 | fi 28 | fi 29 | } 30 | 31 | _display_msg() 32 | { 33 | _init_debug_log 34 | echo "${1?}" 35 | test "${DEBUG_LOG:?}" = 0 || echo "${1?}" 1>> "${DEBUG_LOG_FILE:?}" 36 | } 37 | 38 | # NOTE: The following file come from => https://github.com/LineageOS/android_vendor_lineage/blob/HEAD/prebuilt/common/bin/backuptool.functions 39 | # shellcheck source=/dev/null 40 | command . /tmp/backuptool.functions || { 41 | _display_msg 1>&2 'ERROR: Failed to source backuptool.functions' 42 | # shellcheck disable=SC2317 43 | return 9 || exit 9 44 | } 45 | 46 | list_files() 47 | { 48 | { 49 | cat << 'EOF' 50 | %PLACEHOLDER-1% 51 | EOF 52 | } || { 53 | _display_msg 1>&2 'ERROR: HereDoc failed' 54 | return 1 55 | } 56 | } 57 | 58 | case "${1-}" in 59 | backup) 60 | _display_msg "${VANITY_NAME?} - stage: ${1?}..." 61 | list_files | while IFS='|' read -r FILE _; do 62 | test -n "${FILE?}" || continue 63 | _display_msg " ${S:?}/${FILE:?}" 64 | backup_file "${S:?}/${FILE:?}" 65 | done 66 | _display_msg 'Done.' 67 | ;; 68 | restore) 69 | _display_msg "${VANITY_NAME?} - stage: ${1?}..." 70 | list_files | while IFS='|' read -r FILE REPLACEMENT; do 71 | test -n "${FILE?}" || continue 72 | R='' 73 | test -n "${REPLACEMENT?}" && R="${S:?}/${REPLACEMENT:?}" 74 | test -f "${C:?}/${S:?}/${FILE:?}" && restore_file "${S:?}/${FILE:?}" "${R?}" 75 | done 76 | _display_msg 'Done.' 77 | ;; 78 | pre-backup) 79 | # Stub 80 | ;; 81 | post-backup) 82 | # Stub 83 | ;; 84 | pre-restore) 85 | # Stub 86 | ;; 87 | post-restore) 88 | # Stub 89 | ;; 90 | *) 91 | _display_msg 1>&2 "WARNING: addon.d unknown phase => ${1-}" 92 | ;; 93 | esac 94 | -------------------------------------------------------------------------------- /conf-2.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | files_to_download() 6 | { 7 | cat << 'EOF' 8 | GoogleContactsSyncAdapter12|priv-app|31||GoogleContactsSyncAdapter|com.google.android.syncadapters.contacts|3ea3976e9b9858c7c7013b35a7cfe861b66fef31|www.apkmirror.com/apk/google-inc/google-contacts-sync/google-contacts-sync-12-8361351-release/google-contacts-sync-12-8361351-android-apk-download/|cold1.gofile.io/download/web/e9cee2f5-0c8c-4fe1-9d5a-3cf13ab395f7/GoogleContactsSyncAdapter12.apk 9 | GoogleContactsSyncAdapter8|priv-app|24|30|GoogleContactsSyncAdapter|com.google.android.syncadapters.contacts|d6913b4a2fa5377b2b2f9e43056599b5e987df83|www.apkmirror.com/apk/google-inc/google-contacts-sync/google-contacts-sync-8-1-0-release/google-contacts-sync-8-1-0-2-android-apk-download/|gitlab.opengapps.org/opengapps/all/-/raw/b458223777512c97639cb6bb54bfad93047406d7/app/com.google.android.syncadapters.contacts/27/nodpi/27.apk 10 | GoogleContactsSyncAdapter4.4|app|19|20|GoogleContactsSyncAdapter|com.google.android.syncadapters.contacts|68597be59f16d2e26a79def6fa20bc85d1d2c3b3|www.apkmirror.com/apk/google-inc/google-contacts-sync/google-contacts-sync-4-4-4-1227136-release/google-contacts-sync-4-4-4-1227136-android-apk-download/|gitlab.opengapps.org/opengapps/all/-/raw/b458223777512c97639cb6bb54bfad93047406d7/app/com.google.android.syncadapters.contacts/19/nodpi/19.apk 11 | GoogleCalendarSyncAdapter6|app|24||GoogleCalendarSyncAdapter|com.google.android.syncadapters.calendar|7711e226ef5939d015ac031d83df4aa28a065bdc|www.apkmirror.com/apk/google-inc/google-calendar-sync/google-calendar-sync-6-0-44-267540251-release-release/google-calendar-sync-6-0-44-267540251-release-android-apk-download/|gitlab.opengapps.org/opengapps/all/-/raw/b458223777512c97639cb6bb54bfad93047406d7/app/com.google.android.syncadapters.calendar/21/nodpi/2016267990.apk 12 | GoogleCalendarSyncAdapter5|app|15|22|GoogleCalendarSyncAdapter|com.google.android.syncadapters.calendar|aa482580c87a43c83882c05a4757754917d47f32|www.apkmirror.com/apk/google-inc/google-calendar-sync/google-calendar-sync-5-2-3-99827563-release-release/google-calendar-sync-5-2-3-99827563-release-2-android-apk-download/|gitlab.opengapps.org/opengapps/all/-/raw/b458223777512c97639cb6bb54bfad93047406d7/app/com.google.android.syncadapters.calendar/15/nodpi/2015080710.apk 13 | GoogleBackupTransport4.4|priv-app|19|20|GoogleBackupTransport|com.google.android.backuptransport|6f186d368014022b0038ad2f5d8aa46bb94b5c14|www.apkmirror.com/apk/google-inc/google-backup-transport/google-backup-transport-4-4-4-1227136-release/google-backup-transport-4-4-4-1227136-android-apk-download/|gitlab.opengapps.org/opengapps/all/-/raw/b458223777512c97639cb6bb54bfad93047406d7/priv-app/com.google.android.backuptransport/19/nodpi/19.apk 14 | EOF 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/periodic-checks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Periodic checks" 6 | permissions: {} 7 | on: 8 | push: 9 | paths: 10 | - "gradle/wrapper/gradle-wrapper.jar" 11 | - "**codecov.yml" 12 | - "Makefile" 13 | pull_request: 14 | paths: 15 | - "gradle/wrapper/gradle-wrapper.jar" 16 | - "**codecov.yml" 17 | - "Makefile" 18 | schedule: 19 | # At 03:00 AM, every 30 days (UTC) 20 | - cron: "0 3 */30 * *" 21 | workflow_dispatch: 22 | 23 | jobs: 24 | base-job: 25 | name: "Base" 26 | runs-on: ubuntu-latest 27 | timeout-minutes: 10 28 | 29 | steps: 30 | - name: "Checkout sources" 31 | uses: actions/checkout@v6 32 | - name: "Validate Gradle Wrapper" 33 | uses: gradle/actions/wrapper-validation@v5 34 | - name: "Validate Codecov configuration" 35 | shell: bash 36 | run: | 37 | # Validating Codecov configuration 38 | codecovyml_path='${{ github.workspace }}/.codecov.yml' 39 | if test -f "${codecovyml_path}"; then 40 | status='0' 41 | wget -qO- --post-file "${codecovyml_path:?}" https://codecov.io/validate || status="${?}" 42 | if test "${status:?}" -eq 0; then echo 'Result: pass'; else echo 'Result: fail'; exit "${status:?}"; fi 43 | fi 44 | codecovyml_path='${{ github.workspace }}/codecov.yml' 45 | if test -f "${codecovyml_path}"; then 46 | status='0' 47 | wget -qO- --post-file "${codecovyml_path:?}" https://codecov.io/validate || status="${?}" 48 | if test "${status:?}" -eq 0; then echo 'Result: pass'; else echo 'Result: fail'; exit "${status:?}"; fi 49 | fi 50 | 51 | makefile-validation: 52 | name: "Validate makefile" 53 | runs-on: ubuntu-latest 54 | timeout-minutes: 10 55 | 56 | steps: 57 | - name: "Checkout sources" 58 | uses: actions/checkout@v6 59 | - name: "Validation" 60 | uses: Uno-Takashi/checkmake-action@v2 61 | with: 62 | makefile: "Makefile" 63 | 64 | dep5-validation: 65 | name: "Validate dep5" 66 | runs-on: ubuntu-latest 67 | timeout-minutes: 20 68 | 69 | steps: 70 | - name: "Checkout sources" 71 | uses: actions/checkout@v6 72 | - name: "Validation" 73 | shell: bash 74 | run: | 75 | # Validating dep5 76 | if ! test -e './.reuse/dep5'; then exit 0; fi 77 | sudo apt-get -qq update 78 | sudo apt-get -qq -y install cme 1> /dev/null 79 | status='0' 80 | cme check dpkg-copyright -file './.reuse/dep5' || status="${?}" 81 | if test "${status:?}" -eq 0; then echo 'Result: pass'; else echo 'Result: fail'; exit "${status:?}"; fi 82 | -------------------------------------------------------------------------------- /config-git.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | pause_if_needed() 6 | { 7 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, SHLVL is undefined 8 | if test "${NO_PAUSE:-0}" = '0' && test "${no_pause:-0}" = '0' && test "${CI:-false}" = 'false' && test "${TERM_PROGRAM:-unknown}" != 'vscode' && test "${SHLVL:-1}" = '1' && test -t 0 && test -t 1 && test -t 2; then 9 | if test -n "${NO_COLOR-}"; then 10 | printf 1>&2 '\n%s' 'Press any key to exit... ' || : 11 | else 12 | printf 1>&2 '\n\033[1;32m\r%s' 'Press any key to exit... ' || : 13 | fi 14 | # shellcheck disable=SC3045 # Ignore: In POSIX sh, read -s / -n is undefined 15 | IFS='' read 2> /dev/null 1>&2 -r -s -n1 _ || IFS='' read 1>&2 -r _ || : 16 | printf 1>&2 '\n' || : 17 | test -n "${NO_COLOR-}" || printf 1>&2 '\033[0m\r \r' || : 18 | fi 19 | unset no_pause || : 20 | return "${1:-0}" 21 | } 22 | 23 | config_var() 24 | { 25 | printf '%s' "Configuring ${1:?}: " 26 | 27 | if test -n "${3-}" && test "${3:?}" != 0; then 28 | printf '%s\n' 'Missing' 29 | return 44 30 | fi 31 | 32 | if HOME="${USER_HOME:-${HOME:?}}" git config set --local "${1:?}" "${2:?}"; then 33 | printf '%s\n' 'OK' 34 | else 35 | _status="${?}" 36 | printf '%s\n' 'Error' 37 | return "${_status:?}" 38 | fi 39 | } 40 | 41 | import_gpg_keys() 42 | { 43 | printf '%s' "Importing ${1:?} public keys: " 44 | 45 | if test -n "${3-}" && test "${3:?}" != 0; then 46 | printf '%s\n' 'Missing' 47 | return 44 48 | fi 49 | 50 | if HOME="${USER_HOME:-${HOME:?}}" gpg 2> /dev/null --import -- "${2:?}"; then 51 | printf '%s\n' 'OK' 52 | else 53 | _status="${?}" 54 | printf '%s\n' 'Error' 55 | return "${_status:?}" 56 | fi 57 | } 58 | 59 | setup_gpg() 60 | { 61 | command 1> /dev/null -v 'gpg' || { 62 | printf '%s\n' 'WARNING: gpg is missing' 63 | return 255 64 | } 65 | 66 | # GitHub => https://github.com/web-flow.gpg 67 | test -f "${PWD:?}/.public-keys/github.gpg" 68 | import_gpg_keys 'GitHub' "${PWD:?}/.public-keys/github.gpg" "${?}" || return "${?}" 69 | printf '%s\n' '968479A1AFF927E37D1A566BB5690EEEBB952194:6:' | HOME="${USER_HOME:-${HOME:?}}" gpg --import-ownertrust || return "${?}" 70 | } 71 | 72 | STATUS=0 73 | 74 | printf '%s\n' "Repo dir: ${PWD?}" || STATUS="${?}" 75 | 76 | test -d "${PWD:?}/.git-hooks" 77 | config_var core.hooksPath '.git-hooks' "${?}" || STATUS="${?}" 78 | 79 | test -f "${PWD:?}/allowed_signers" 80 | config_var gpg.ssh.allowedSignersFile 'allowed_signers' "${?}" || STATUS="${?}" 81 | 82 | setup_gpg || STATUS="${?}" 83 | 84 | config_var format.signOff 'true' || STATUS="${?}" 85 | config_var alias.cm 'commit -s' || STATUS="${?}" 86 | 87 | test "${STATUS:?}" = 0 || printf '%s\n' "Error code: ${STATUS:?}" 88 | 89 | pause_if_needed "${STATUS:?}" 90 | exit "${?}" 91 | -------------------------------------------------------------------------------- /zip-content/scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # SPDX-FileCopyrightText: (c) 2016 ale5000 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | ### GLOBAL VARIABLES ### 6 | 7 | TMP_PATH="${2:?}" 8 | 9 | ### FUNCTIONS ### 10 | 11 | # shellcheck source=SCRIPTDIR/../inc/common-functions.sh 12 | command . "${TMP_PATH:?}/inc/common-functions.sh" || exit "${?}" 13 | 14 | ### CODE ### 15 | 16 | if test "${API:?}" -ge 24; then 17 | : # Supported Android version 18 | elif test "${API:?}" -ge 23; then 19 | ui_error 'Unsupported Android version' 20 | elif test "${API:?}" -ge 19; then 21 | : # Supported Android version 22 | else 23 | ui_error "Your Android version is too old, API: ${API?}" 24 | fi 25 | 26 | APP_CONTACTSSYNC="$(parse_setting 'app' 'CONTACTSSYNC' "${APP_CONTACTSSYNC:?}")" 27 | APP_CALENDARSYNC="$(parse_setting 'app' 'CALENDARSYNC' "${APP_CALENDARSYNC:?}")" 28 | 29 | if test "${SETUP_TYPE:?}" = 'install'; then 30 | ui_msg 'Configuring...' 31 | ui_msg_empty_line 32 | 33 | # IMPORTANT: Some Google Contacts Sync Adapters are disabled because they no longer work 34 | 35 | BACKUP_TRANSPORT_IS_OPTIONAL='true' 36 | if 37 | #setup_app "${APP_CONTACTSSYNC:?}" 'APP_CONTACTSSYNC' 'Google Contacts Sync 12' 'GoogleContactsSyncAdapter12' 'priv-app' || 38 | # setup_app "${APP_CONTACTSSYNC:?}" 'APP_CONTACTSSYNC' 'Google Contacts Sync 8' 'GoogleContactsSyncAdapter8' 'priv-app' || 39 | setup_app "${APP_CONTACTSSYNC:?}" 'APP_CONTACTSSYNC' 'Google Contacts Sync 4.4' 'GoogleContactsSyncAdapter4.4' 'app' 40 | then 41 | BACKUP_TRANSPORT_IS_OPTIONAL='false' 42 | fi 43 | 44 | setup_app "${APP_CALENDARSYNC:?}" 'APP_CALENDARSYNC' 'Google Calendar Sync 6' 'GoogleCalendarSyncAdapter6' 'app' || 45 | setup_app "${APP_CALENDARSYNC:?}" 'APP_CALENDARSYNC' 'Google Calendar Sync 5' 'GoogleCalendarSyncAdapter5' 'app' 46 | 47 | setup_app 1 '' 'Google Backup Transport 4.4' 'GoogleBackupTransport4.4' 'priv-app' false "${BACKUP_TRANSPORT_IS_OPTIONAL:?}" 48 | fi 49 | 50 | if test "${SETUP_TYPE:?}" = 'install'; then 51 | disable_app 'com.google.android.syncadapters.calendar' 52 | disable_app 'com.google.android.syncadapters.contacts' 53 | disable_app 'com.google.android.backuptransport' 54 | fi 55 | 56 | # Clean previous installations 57 | clean_previous_installations 58 | 59 | if test "${SETUP_TYPE:?}" = 'uninstall'; then 60 | clear_app 'com.google.android.syncadapters.calendar' 61 | clear_app 'com.google.android.syncadapters.contacts' 62 | clear_app 'com.google.android.backuptransport' 63 | 64 | finalize_correctly 65 | exit 0 66 | fi 67 | 68 | # Prepare installation 69 | prepare_installation 70 | 71 | # Install 72 | perform_installation 73 | reset_runtime_permissions_if_needed 74 | reset_appops_if_needed 75 | reset_authenticator_and_sync_adapter_caches 76 | 77 | clear_and_enable_app 'com.google.android.backuptransport' 78 | clear_and_enable_app 'com.google.android.syncadapters.contacts' 79 | clear_and_enable_app 'com.google.android.syncadapters.calendar' 80 | 81 | install_survival_script '00-1-google-sync' 82 | 83 | finalize_correctly 84 | -------------------------------------------------------------------------------- /LICENSES/Info-ZIP.txt: -------------------------------------------------------------------------------- 1 | Info-ZIP License 2 | 3 | Copyright (c) 1990-2009 Info-ZIP. All rights reserved. 4 | 5 | For the purposes of this copyright and license, "Info-ZIP" is defined as the following set of individuals: 6 | 7 | Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, Rich Wales, Mike White. 8 | 9 | This software is provided "as is," without warranty of any kind, express or implied. In no event shall Info-ZIP or its contributors be held liable for any direct, indirect, incidental, special or consequential damages arising out of the use of or inability to use this software. 10 | 11 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the above disclaimer and the following restrictions: 12 | 13 | * Redistributions of source code (in whole or in part) must retain the above copyright notice, definition, disclaimer, and this list of conditions. 14 | * Redistributions in binary form (compiled executables and libraries) must reproduce the above copyright notice, definition, disclaimer, and this list of conditions in documentation and/or other materials provided with the distribution. Additional documentation is not needed for executables where a command line license option provides these and a note regarding this option is in the executable's startup banner. The sole exception to this condition is redistribution of a standard UnZipSFX binary (including SFXWiz) as part of a self-extracting archive; that is permitted without inclusion of this license, as long as the normal SFX banner has not been removed from the binary or disabled. 15 | * Altered versions--including, but not limited to, ports to new operating systems, existing ports with new graphical interfaces, versions with modified or added functionality, and dynamic, shared, or static library versions not from Info-ZIP--must be plainly marked as such and must not be misrepresented as being the original source or, if binaries, compiled from the original source. Such altered versions also must not be misrepresented as being Info-ZIP releases--including, but not limited to, labeling of the altered versions with the names "Info-ZIP" (or any variation thereof, including, but not limited to, different capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the explicit permission of Info-ZIP. Such altered versions are further prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP will provide support for the altered versions. 16 | * Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and binary releases. 17 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /.github/workflows/generate-perm-xml.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Generate permission XML files" 6 | permissions: {} 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | # At 02:00 AM, every 6 days (UTC) 11 | - cron: "0 2 */6 * *" 12 | 13 | jobs: 14 | generation: 15 | name: "Generation" 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 20 18 | if: "${{ github.event_name != 'schedule' }}" 19 | 20 | steps: 21 | - name: "Checkout sources" 22 | uses: actions/checkout@v6 23 | - name: "Use cache" 24 | id: cache-step 25 | uses: actions/cache@v5 26 | timeout-minutes: 5 27 | with: 28 | key: "perms-${{ hashFiles('tools/dl-perm-list.sh') }}" 29 | restore-keys: "perms-" 30 | path: "cache/tools/perms" 31 | enableCrossOsArchive: true 32 | - name: "Execute script" 33 | shell: bash 34 | timeout-minutes: 10 35 | run: | 36 | # Executing script... 37 | export TOOLS_DATA_DIR='./cache/tools' 38 | if test ! -d './cache/tools/perms' || '${{ steps.cache-step.outputs.cache-hit != 'true' }}'; then 39 | './tools/dl-perm-list.sh' || exit "${?}" 40 | fi 41 | find './zip-content' -name '*.apk' | './tools/generate-perm-xml.sh' --use-placeholders - || exit "${?}" 42 | - name: "Upload artifacts" 43 | uses: actions/upload-artifact@v6 44 | with: 45 | name: "XML permissions" 46 | path: "output/*.xml" 47 | overwrite: false 48 | retention-days: 10 49 | if-no-files-found: "error" 50 | 51 | keep-alive: 52 | name: "Keep alive" 53 | runs-on: ubuntu-latest 54 | timeout-minutes: 10 55 | if: "${{ github.event_name == 'schedule' }}" 56 | permissions: 57 | actions: write # Needed to keep alive the workflow 58 | 59 | steps: 60 | - name: "Checkout file" 61 | uses: actions/checkout@v6 62 | with: 63 | sparse-checkout: | 64 | tools/dl-perm-list.sh 65 | sparse-checkout-cone-mode: false 66 | - name: "Ping cache" # Cache expiration: 7 days 67 | uses: actions/cache@v5 68 | timeout-minutes: 5 69 | with: 70 | key: "perms-${{ hashFiles('tools/dl-perm-list.sh') }}" 71 | path: "cache/tools/perms" 72 | enableCrossOsArchive: true 73 | lookup-only: true 74 | - name: "Keep workflow alive" 75 | uses: actions/github-script@v8 76 | timeout-minutes: 5 77 | env: 78 | WORKFLOW_REF: "${{ github.workflow_ref }}" 79 | with: 80 | retries: 3 81 | script: | 82 | /* jshint esversion: 6 */ 83 | const workflow_filename = process.env.WORKFLOW_REF.split('@', 1).at(0).split('/').slice(2).join('/'); 84 | const response = await github.rest.actions.enableWorkflow({ 85 | owner: context.repo.owner, 86 | repo: context.repo.repo, 87 | workflow_id: workflow_filename 88 | }).catch(response => response); 89 | if(response && response.status === 204) { 90 | console.log('Workflow enabled.'); 91 | } else { 92 | let errorMsg = 'enableWorkflow failed'; 93 | if(response && response.status && response.message) errorMsg += ' with error ' + response.status + ' (' + response.message + ')'; 94 | throw new Error(errorMsg); 95 | } 96 | -------------------------------------------------------------------------------- /zip-content/CONTENTS.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | ======== 7 | CONTENTS 8 | ======== 9 | .. |star| replace:: ⭐️ 10 | .. |fire| replace:: 🔥 11 | .. |boom| replace:: 💥 12 | .. |yes| replace:: ✔ 13 | .. |no| replace:: ✖ 14 | .. |red-no| replace:: ❌ 15 | .. |no-upd| replace:: 🙈 16 | 17 | 18 | Apps 19 | ---- 20 | 21 | +----------------------------------------------------------------------------------------+---------------+-----------------------+------------------------------+ 22 | | | Android ver. | Updatable with | Signer | 23 | | Application +-------+-------+----------+------------+----------+--------+----------+ 24 | | | Min | Max | F-Droid | Play Store | F-Droid | Author | ale5000 | 25 | +========================================================================================+=======+=======+==========+============+==========+========+==========+ 26 | | [#]_ Google Contacts Sync 12-8361351 (31) | 12 | | | | | |fire| | | 27 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 28 | | [#]_ Google Contacts Sync 8.1.0 (27) | 7.0 | 11 | | | | |fire| | | 29 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 30 | | [#]_ Google Contacts Sync 4.4.4-1227136 (19) | 4.4 | 4.4.4 | | | | |fire| | | 31 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 32 | | [#]_ Google Calendar Sync 6.0.44-267540251 (2016267990) | 7.0 | | | | | |fire| | | 33 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 34 | | [#]_ Google Calendar Sync 5.2.3-99827563 (2015080710) | 4.4 | 5.1.1 | | | | |fire| | | 35 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 36 | | [#]_ Google Backup Transport 4.4.4-1227136 (19) | 4.4 | 4.4.4 | | | | |fire| | | 37 | +----------------------------------------------------------------------------------------+-------+-------+----------+------------+----------+--------+----------+ 38 | 39 | 40 | Notes 41 | ----- 42 | .. [#] 43 | .. [#] 44 | .. [#] 45 | .. [#] 46 | .. [#] 47 | .. [#] 48 | 49 | 50 | Components used only during setup (not installed) 51 | ------------------------------------------------- 52 | - BusyBox for Android (available `here `_) - See `here `_ for more info 53 | -------------------------------------------------------------------------------- /tools/get-signature.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # @name Find app signature 3 | # @brief Find the signature of Android applications 4 | # @author ale5000 5 | # Get the latest version from here: https://github.com/micro5k/microg-unofficial-installer/tree/main/tools 6 | 7 | # SPDX-FileCopyrightText: (c) 2025 ale5000 8 | # SPDX-License-Identifier: GPL-3.0-or-later 9 | 10 | # shellcheck enable=all 11 | # shellcheck disable=SC3043 # In POSIX sh, local is undefined 12 | 13 | readonly SCRIPT_NAME='Find app signature' 14 | readonly SCRIPT_SHORTNAME='FindAppSign' 15 | readonly SCRIPT_VERSION='0.1.0' 16 | readonly SCRIPT_AUTHOR='ale5000' 17 | 18 | pause_if_needed() 19 | { 20 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, SHLVL is undefined 21 | if test "${NO_PAUSE:-0}" = '0' && test "${no_pause:-0}" = '0' && test "${CI:-false}" = 'false' && test "${TERM_PROGRAM:-unknown}" != 'vscode' && test "${SHLVL:-1}" = '1' && test -t 0 && test -t 1 && test -t 2; then 22 | if test -n "${NO_COLOR-}"; then 23 | printf 1>&2 '\n%s' 'Press any key to exit... ' || : 24 | else 25 | printf 1>&2 '\n\033[1;32m\r%s' 'Press any key to exit... ' || : 26 | fi 27 | # shellcheck disable=SC3045 # Ignore: In POSIX sh, read -s / -n is undefined 28 | IFS='' read 2> /dev/null 1>&2 -r -s -n1 _ || IFS='' read 1>&2 -r _ || : 29 | printf 1>&2 '\n' || : 30 | test -n "${NO_COLOR-}" || printf 1>&2 '\033[0m\r \r' || : 31 | fi 32 | unset no_pause || : 33 | return "${1:-0}" 34 | } 35 | 36 | show_status() 37 | { 38 | printf 1>&2 '\033[1;32m%s\033[0m\n' "${1?}" 39 | } 40 | 41 | show_error() 42 | { 43 | printf 1>&2 '\033[1;31m%s\033[0m\n' "ERROR: ${1?}" 44 | } 45 | 46 | get_cert_sha256() 47 | { 48 | local _cert_sha256 49 | 50 | test -n "${1-}" || { 51 | show_error "You must pass the filename of the file to be processed." 52 | return 3 53 | } 54 | 55 | if : "${APKSIGNER_PATH:="$(command -v 'apksigner' || command -v 'apksigner.bat' || :)"}" && test -n "${APKSIGNER_PATH?}"; then 56 | _cert_sha256="$("${APKSIGNER_PATH:?}" verify --min-sdk-version 24 --print-certs -- "${1:?}" | grep -m 1 -F -e 'certificate SHA-256 digest:' | cut -d ':' -f '2-' -s | tr -d -- ' ' | tr -- '[:lower:]' '[:upper:]' | sed -e 's/../&:/g;s/:$//')" || return 4 57 | elif : "${KEYTOOL_PATH:="$(command -v 'keytool' || :)"}" && test -n "${KEYTOOL_PATH-}"; then 58 | _cert_sha256="$("${KEYTOOL_PATH:?}" -printcert -jarfile "${1:?}" | grep -m 1 -F -e 'SHA256:' | cut -d ':' -f '2-' -s | tr -d -- ' ')" || return 5 59 | else 60 | show_error "Neither apksigner nor keytool were found. You must set either APKSIGNER_PATH or KEYTOOL_PATH" 61 | return 255 62 | fi 63 | 64 | if test -n "${_cert_sha256?}"; then 65 | printf '%s\n' "sha256-cert-digest=\"${_cert_sha256:?}\"" 66 | else 67 | return 1 68 | fi 69 | } 70 | 71 | main() 72 | { 73 | get_cert_sha256 "${@}" 74 | } 75 | 76 | STATUS=0 77 | execute_script='true' 78 | 79 | while test "${#}" -gt 0; do 80 | case "${1?}" in 81 | -V | --version) 82 | printf '%s\n' "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?}" 83 | printf '%s\n' "Copy""right (c) 2025 ${SCRIPT_AUTHOR:?}" 84 | printf '%s\n' 'License GPLv3+' 85 | execute_script='false' 86 | ;; 87 | 88 | --) 89 | shift 90 | break 91 | ;; 92 | 93 | --*) 94 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: unrecognized option '${1}'" 95 | execute_script='false' 96 | STATUS=2 97 | ;; 98 | 99 | -*) 100 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: invalid option -- '${1#-}'" 101 | execute_script='false' 102 | STATUS=2 103 | ;; 104 | 105 | *) 106 | break 107 | ;; 108 | esac 109 | 110 | shift 111 | done 112 | 113 | if test "${execute_script:?}" = 'true'; then 114 | show_status "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?} by ${SCRIPT_AUTHOR:?}" 115 | 116 | if test "${#}" -eq 0; then set -- ''; fi 117 | main "${@}" || STATUS="${?}" 118 | fi 119 | 120 | pause_if_needed "${STATUS:?}" 121 | exit "${?}" 122 | -------------------------------------------------------------------------------- /tools/list-app-perms.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # @name List apps permissions 3 | # @brief List the permissions used by Android applications 4 | # @author ale5000 5 | # Get the latest version from here: https://github.com/micro5k/microg-unofficial-installer/tree/main/tools 6 | 7 | # SPDX-FileCopyrightText: (c) 2025 ale5000 8 | # SPDX-License-Identifier: GPL-3.0-or-later 9 | 10 | # shellcheck enable=all 11 | # shellcheck disable=SC3043 # In POSIX sh, local is undefined 12 | 13 | readonly SCRIPT_NAME='List apps permissions' 14 | readonly SCRIPT_SHORTNAME='ListAppPerms' 15 | readonly SCRIPT_VERSION='0.1.0' 16 | readonly SCRIPT_AUTHOR='ale5000' 17 | 18 | # shellcheck disable=SC3040 # Ignore: In POSIX sh, set option pipefail is undefined 19 | case "$(set 2> /dev/null -o || set || :)" in *'pipefail'*) set -o pipefail || echo 1>&2 'Failed: pipefail' ;; *) ;; esac 20 | 21 | pause_if_needed() 22 | { 23 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, SHLVL is undefined 24 | if test "${NO_PAUSE:-0}" = '0' && test "${no_pause:-0}" = '0' && test "${CI:-false}" = 'false' && test "${TERM_PROGRAM:-unknown}" != 'vscode' && test "${SHLVL:-1}" = '1' && test -t 0 && test -t 1 && test -t 2; then 25 | if test -n "${NO_COLOR-}"; then 26 | printf 1>&2 '\n%s' 'Press any key to exit... ' || : 27 | else 28 | printf 1>&2 '\n\033[1;32m\r%s' 'Press any key to exit... ' || : 29 | fi 30 | # shellcheck disable=SC3045 # Ignore: In POSIX sh, read -s / -n is undefined 31 | IFS='' read 2> /dev/null 1>&2 -r -s -n1 _ || IFS='' read 1>&2 -r _ || : 32 | printf 1>&2 '\n' || : 33 | test -n "${NO_COLOR-}" || printf 1>&2 '\033[0m\r \r' || : 34 | fi 35 | unset no_pause || : 36 | return "${1:-0}" 37 | } 38 | 39 | show_status() 40 | { 41 | printf 1>&2 '\033[1;32m%s\033[0m\n' "${1?}" 42 | } 43 | 44 | show_error() 45 | { 46 | printf 1>&2 '\033[1;31m%s\033[0m\n' "ERROR: ${1?}" 47 | } 48 | 49 | find_android_build_tool() 50 | { 51 | local _tool_path 52 | 53 | if _tool_path="$(command -v "${1:?}")" && test -n "${_tool_path?}"; then 54 | : 55 | elif test -n "${ANDROID_SDK_ROOT-}" && test -d "${ANDROID_SDK_ROOT:?}/build-tools" && _tool_path="$(find "${ANDROID_SDK_ROOT:?}/build-tools" -maxdepth 2 -iname "${1:?}*" | LC_ALL=C sort -V -r | head -n 1)" && test -n "${_tool_path?}"; then 56 | : 57 | else 58 | return 1 59 | fi 60 | 61 | printf '%s\n' "${_tool_path:?}" 62 | } 63 | 64 | main() 65 | { 66 | test -n "${1-}" || { 67 | show_error "You must pass the filename of the file to be processed." 68 | return 3 69 | } 70 | 71 | : "${AAPT_PATH:="$(find_android_build_tool 'aapt2' || find_android_build_tool 'aapt' || :)"}" 72 | 73 | if test -n "${AAPT_PATH-}"; then 74 | "${AAPT_PATH:?}" dump permissions "${@}" | grep -F -e 'uses-permission: ' | cut -d ':' -f '2-' -s | cut -b '2-' | LC_ALL=C sort || return "${?}" 75 | else 76 | return 255 77 | fi 78 | } 79 | 80 | STATUS=0 81 | execute_script='true' 82 | 83 | while test "${#}" -gt 0; do 84 | case "${1?}" in 85 | -V | --version) 86 | printf '%s\n' "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?}" 87 | printf '%s\n' "Copy""right (c) 2025 ${SCRIPT_AUTHOR:?}" 88 | printf '%s\n' 'License GPLv3+' 89 | execute_script='false' 90 | ;; 91 | 92 | --) 93 | shift 94 | break 95 | ;; 96 | 97 | --*) 98 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: unrecognized option '${1}'" 99 | execute_script='false' 100 | STATUS=2 101 | ;; 102 | 103 | -*) 104 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: invalid option -- '${1#-}'" 105 | execute_script='false' 106 | STATUS=2 107 | ;; 108 | 109 | *) 110 | break 111 | ;; 112 | esac 113 | 114 | shift 115 | done 116 | 117 | if test "${execute_script:?}" = 'true'; then 118 | show_status "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?} by ${SCRIPT_AUTHOR:?}" 119 | 120 | if test "${#}" -eq 0; then set -- ''; fi 121 | main "${@}" || STATUS="${?}" 122 | fi 123 | 124 | pause_if_needed "${STATUS:?}" 125 | exit "${?}" 126 | -------------------------------------------------------------------------------- /LICENSE-ADDITION.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: (c) 2016 ale5000 3 | SPDX-License-Identifier: GPL-3.0-or-later 4 | SPDX-FileType: DOCUMENTATION 5 | 6 | =================== 7 | License declaration 8 | =================== 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see https://www.gnu.org/licenses/. 22 | 23 | 24 | Google Sync add-on zip exception 25 | ================================ 26 | 27 | This Google Sync add-on GPLv3 licensed scripts exception ("Exception") is an additional 28 | permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). 29 | It applies to a given file (the "GPLv3 licensed scripts") that bears a notice placed by the 30 | copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. 31 | 32 | When you use Google Sync add-on to compile an installable zip, 33 | it combines portions of GPLv3 licensed scripts in this zip. 34 | The purpose of this Exception is to allow generation of non-GPL zips, 35 | in this way, these scripts are covered by this Exception. 36 | 37 | 0. Definitions. 38 | --------------- 39 | A file is an "Independent Module" if it either requires the GPLv3 licensed scripts for execution 40 | or installation after a Compilation Process, or makes use of an interface provided 41 | by the GPLv3 licensed scripts, but is not otherwise based on these GPLv3 scripts. 42 | 43 | "Google Sync add-on" means a version of The Google Sync add-on Project, with 44 | or without modifications, governed by version 3 (or a specified later version) of the 45 | GNU General Public License (GPL) with the option of using any subsequent versions published by the FSF. 46 | 47 | "GPL-compatible Software" is software whose conditions of propagation, 48 | modification and use would permit combination with Google Sync add-on in accord with 49 | the license of Google Sync add-on. 50 | 51 | "Installable zip" refers to output from any scripts that can be executed on Android compatible devices. 52 | Notwithstanding that, "Installable zip" does not include data in any format that is used as 53 | an intermediate representation, or used for producing an intermediate representation. 54 | 55 | The "Compilation Process" transforms code entirely represented in non-intermediate languages 56 | designed for human-written code, into an Installable Zip. 57 | 58 | A Compilation Process is "Eligible" if it is done using Google Sync add-on, 59 | alone or with other GPL-compatible software, or if it is done without using any work 60 | based on Google Sync add-on. 61 | For example, using non-GPL-compatible Software to optimize any Google Sync add-on 62 | intermediate representations would not qualify as an Eligible Compilation Process. 63 | 64 | 1. Grant of Additional Permission. 65 | ---------------------------------- 66 | You have permission to propagate a work of installable zip formed 67 | by combining the GPLv3 licensed scripts with Independent Modules, 68 | even if such propagation would otherwise violate the terms of GPLv3, 69 | provided that all in the installable zip was generated by Eligible Compilation Processes. 70 | You may then convey such a combination under terms of your choice, 71 | consistent with the licensing of the Independent Modules. 72 | 73 | 2. Applicability of GPLv3 copyleft is retained on the GPLv3 licensed scripts. 74 | ----------------------------------------------------------------------------- 75 | Any file within the installable zip that is part of the GPLv3 licensed scripts, 76 | is in itself still licensed as GPLv3 and retains its copyleft permissions. 77 | It is to be treated as an "aggregate" as specified in the GPLv3. 78 | 79 | 3. No Weakening of Google Sync add-on Copyleft. 80 | ----------------------------------------------- 81 | The availability of this Exception does not imply any general presumption that third-party software 82 | is unaffected by the copyleft requirements of the license of Google Sync add-on. 83 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Coverage" 6 | permissions: {} 7 | on: 8 | push: 9 | paths-ignore: 10 | - ".github/**" 11 | - ".gitlab/**" 12 | - ".gitlab-ci.yml" 13 | - ".travis.yml" 14 | branches: 15 | - "**" 16 | tags: 17 | - "v*.*" 18 | pull_request: 19 | jobs: 20 | coverage: 21 | name: "Coverage" 22 | runs-on: ubuntu-latest 23 | timeout-minutes: 20 24 | concurrency: 25 | group: "${{ github.repository_id }}-${{ github.workflow }}-coverage" 26 | cancel-in-progress: false 27 | 28 | steps: 29 | - name: "Checkout sources" 30 | uses: actions/checkout@v6 31 | - name: "Setup Java" 32 | uses: actions/setup-java@v5 33 | with: 34 | distribution: "temurin" 35 | java-version-file: ".tool-versions" 36 | - name: "Setup Ruby" 37 | uses: ruby/setup-ruby@v1 38 | timeout-minutes: 10 39 | with: 40 | ruby-version: "3.4" 41 | bundler-cache: "true" 42 | - name: "Install Bashcov and simplecov-lcov" 43 | shell: bash 44 | timeout-minutes: 10 45 | run: | 46 | # Installing Bashcov and simplecov-lcov... 47 | gem install bashcov:3.2.0 simplecov-lcov 48 | - name: "Build (with coverage)" 49 | id: "build" 50 | shell: bash 51 | timeout-minutes: 10 52 | run: | 53 | # Executing code coverage... 54 | export BUILD_TYPE=oss 55 | #sudo apt-get -qq -y install moreutils 1>/dev/null 56 | bashcov '${{ github.workspace }}/build.sh' # To timestamp the output pipe it to: TZ=UTC ts '[%H:%M:%S]' 57 | - name: "Testing (with coverage)" 58 | shell: bash 59 | timeout-minutes: 10 60 | if: "${{ steps.build.outputs.ZIP_BUILD_TYPE_SUPPORTED == 'true' }}" 61 | run: | 62 | # Testing of zip installation... 63 | echo '===========================' 64 | echo 'TESTING OF ZIP INSTALLATION' 65 | echo '===========================' 66 | bashcov '${{ github.workspace }}/recovery-simulator/recovery.sh' '${{ steps.build.outputs.ZIP_FOLDER }}/${{ steps.build.outputs.ZIP_FILENAME }}' 67 | printf '\n' 68 | echo '===============' 69 | echo 'RECOVERY OUTPUT' 70 | echo '===============' 71 | if test -e '${{ github.workspace }}/recovery-simulator/output/recovery-output.log'; then 72 | cat '${{ github.workspace }}/recovery-simulator/output/recovery-output.log' 73 | fi 74 | printf '\n' 75 | echo '===============' 76 | echo 'INSTALLED FILES' 77 | echo '===============' 78 | if test -e '${{ github.workspace }}/recovery-simulator/output/installed-files.log'; then 79 | cat '${{ github.workspace }}/recovery-simulator/output/installed-files.log' 80 | fi 81 | - name: "Verify Codecov token" 82 | id: "codecov-token" 83 | shell: bash 84 | env: 85 | CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" 86 | run: | 87 | # Verifying token... 88 | if test -n "${CODECOV_TOKEN?}"; then token_set='true'; else token_set='false'; fi 89 | printf 'TOKEN_SET=%s\n' "${token_set:?}" 1>> "${GITHUB_OUTPUT?}" 90 | - name: "Upload coverage reports to Codecov" 91 | if: "${{ steps.codecov-token.outputs.TOKEN_SET == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/main' }}" 92 | uses: codecov/codecov-action@v5 93 | timeout-minutes: 10 94 | with: 95 | fail_ci_if_error: true 96 | token: "${{ secrets.CODECOV_TOKEN }}" 97 | - name: "Verify Codacy token" 98 | id: "codacy-token" 99 | shell: bash 100 | env: 101 | CODACY_TOKEN: "${{ secrets.CODACY_PROJECT_TOKEN }}" 102 | run: | 103 | # Verifying token... 104 | if test -n "${CODACY_TOKEN?}"; then token_set='true'; else token_set='false'; fi 105 | printf 'TOKEN_SET=%s\n' "${token_set:?}" 1>> "${GITHUB_OUTPUT?}" 106 | - name: "Upload coverage reports to Codacy" 107 | if: "${{ steps.codacy-token.outputs.TOKEN_SET == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/main' }}" 108 | uses: codacy/codacy-coverage-reporter-action@v1 109 | timeout-minutes: 10 110 | with: 111 | project-token: "${{ secrets.CODACY_PROJECT_TOKEN }}" 112 | -------------------------------------------------------------------------------- /cmdline.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: (c) 2016 ale5000 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # shellcheck enable=all 6 | 7 | # Workaround for shells without support for local (example: ksh pbosh obosh) 8 | command 1> /dev/null 2>&1 -v 'local' || { 9 | eval ' local() { :; } ' || : 10 | # On some variants of ksh this really works, but leave the function as dummy fallback 11 | if command 1> /dev/null 2>&1 -v 'typeset'; then alias 'local'='typeset'; fi 12 | } 13 | 14 | if test "${A5K_FUNCTIONS_INCLUDED:-false}" = 'false'; then 15 | main() 16 | { 17 | local _main_dir _run_strategy _applet _uname_os _nl 18 | 19 | # Execute only if the first initialization has not already been done 20 | if test -z "${MAIN_DIR-}" || test -z "${USER_HOME-}"; then 21 | 22 | # Avoid picturesque bugs on Bash under Windows 23 | if test -x '/usr/bin/uname' && _uname_os="$(/usr/bin/uname 2> /dev/null -o)" && test "${_uname_os}" = 'Msys'; then PATH="/usr/bin:${PATH:-%empty}"; fi 24 | 25 | if test -z "${MAIN_DIR-}"; then 26 | # shellcheck disable=SC3028,SC2128 # Intended: In POSIX sh, BASH_SOURCE is undefined / Expanding an array without an index only gives the first element 27 | if MAIN_DIR="${BASH_SOURCE-}" && test -n "${MAIN_DIR}"; then :; else MAIN_DIR="${1}"; fi 28 | case "${MAIN_DIR}" in *'cmdline.sh') ;; *) MAIN_DIR='' ;; esac 29 | 30 | if test -n "${MAIN_DIR}" && MAIN_DIR="$(dirname "${MAIN_DIR}")" && MAIN_DIR="$(realpath "${MAIN_DIR}")"; then export MAIN_DIR; else unset MAIN_DIR; fi 31 | fi 32 | 33 | if test -n "${MAIN_DIR-}" && test -z "${USER_HOME-}"; then 34 | if test "${TERM_PROGRAM-}" = 'mintty'; then TERM_PROGRAM='mintty-'; fi 35 | export USER_HOME="${HOME-}" 36 | export HOME="${MAIN_DIR}" 37 | fi 38 | 39 | fi 40 | 41 | shift 42 | 43 | get_shell_exe() 44 | { 45 | local _gse_shell_exe _gse_tmp_var 46 | 47 | if _gse_shell_exe="$(readlink 2> /dev/null "/proc/${$}/exe")" && test -n "${_gse_shell_exe}"; then 48 | # On Linux / Android / Windows (on Windows only some shells support it) 49 | printf '%s\n' "${_gse_shell_exe}" 50 | return 0 51 | elif _gse_tmp_var="$(ps 2> /dev/null -p "${$}" -o 'comm=')" && test -n "${_gse_tmp_var}" && _gse_tmp_var="$(command 2> /dev/null -v "${_gse_tmp_var}")"; then 52 | # On Linux / macOS 53 | # shellcheck disable=SC2230 # Ignore: 'which' is non-standard 54 | case "${_gse_tmp_var}" in *'/'* | *"\\"*) ;; *) _gse_tmp_var="$(which 2> /dev/null "${_gse_tmp_var}")" || return 3 ;; esac # We may not get the full path with "command -v" on some old versions of Oils 55 | elif _gse_tmp_var="${BASH:-${SHELL-}}" && test -n "${_gse_tmp_var}"; then 56 | if test "${_gse_tmp_var}" = '/bin/sh' && test "$(uname 2> /dev/null || :)" = 'Windows_NT'; then _gse_tmp_var="$(command 2> /dev/null -v 'busybox')" || return 2; fi 57 | if test ! -x "${_gse_tmp_var}" && test -x "${_gse_tmp_var}.exe"; then _gse_tmp_var="${_gse_tmp_var}.exe"; fi # Special fix for broken versions of Bash under Windows 58 | else 59 | return 1 60 | fi 61 | 62 | _gse_shell_exe="$(readlink 2> /dev/null -f "${_gse_tmp_var}" || realpath 2> /dev/null "${_gse_tmp_var}")" || _gse_shell_exe="${_gse_tmp_var}" 63 | printf '%s\n' "${_gse_shell_exe}" 64 | return 0 65 | } 66 | 67 | __SHELL_EXE="$(get_shell_exe)" || __SHELL_EXE='bash' 68 | export __SHELL_EXE 69 | unset _gse_shell_exe _gse_tmp_var 70 | 71 | _run_strategy='init-file' 72 | _applet='' 73 | case "${__SHELL_EXE}" in 74 | *'/busybox'*) # BusyBox 75 | _run_strategy='s-opt' 76 | _applet="${CUSTOM_APPLET:-ash}" 77 | ;; 78 | *'/oil.ovm' | *'/oils-for-unix') # Oils 79 | _run_strategy='source' 80 | _applet="${CUSTOM_APPLET:-osh}" 81 | ;; 82 | *'/osh') # Oils 83 | _run_strategy='source' 84 | ;; 85 | *) ;; 86 | esac 87 | 88 | if test -n "${MAIN_DIR-}"; then _main_dir="${MAIN_DIR}"; else _main_dir='.'; fi 89 | 90 | if test "${ONLY_FOR_TESTING-}" = 'true'; then 91 | printf '%s\n' "${__SHELL_EXE}" 92 | printf '%s\n' "${_main_dir}" 93 | _run_strategy='source' 94 | fi 95 | 96 | export DO_INIT_CMDLINE=1 97 | unset KILL_PPID 98 | unset STARTED_FROM_BATCH_FILE 99 | unset IS_PATH_INITIALIZED 100 | unset __QUOTED_PARAMS 101 | 102 | if test "${_run_strategy}" = 'source'; then 103 | . "${_main_dir}/includes/common.sh" "${@}" || return "${?}" 104 | elif test "${_run_strategy}" = 's-opt'; then 105 | # shellcheck disable=SC2086 # Ignore: Double quote to prevent globbing and word splitting 106 | exec "${__SHELL_EXE}" ${_applet} -s -c ". '${_main_dir}/includes/common.sh' || exit \${?}" "${_applet:-${0-}}" "${@}" 107 | else 108 | if test "${#}" -gt 0; then 109 | _nl="$(printf '\nx')" _nl="${_nl%x}" 110 | 111 | case "${*}" in 112 | *"${_nl}"*) printf 1>&2 '%s\n' 'WARNING: Newline character found, parameters dropped' ;; 113 | *) 114 | __QUOTED_PARAMS="$(printf '%s\n' "${@}")" 115 | export __QUOTED_PARAMS 116 | ;; 117 | esac 118 | fi 119 | 120 | # shellcheck disable=SC2086 # Ignore: Double quote to prevent globbing and word splitting 121 | exec "${__SHELL_EXE}" ${_applet} --init-file "${_main_dir}/includes/common.sh" 122 | fi 123 | } 124 | 125 | if test "${#}" -gt 0; then 126 | main "${0-}" "${@}" 127 | else 128 | main "${0-}" 129 | fi 130 | fi 131 | -------------------------------------------------------------------------------- /.github/workflows/code-scan.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Code scan" 6 | permissions: {} 7 | on: 8 | push: 9 | paths: 10 | - "**" 11 | branches: 12 | - "main" 13 | schedule: 14 | # At 12:00 AM, every 31 days, only in January (UTC) 15 | - cron: "0 0 */31 1 *" 16 | 17 | jobs: 18 | pre-requisites: 19 | name: "Pre-requisites" 20 | runs-on: ubuntu-latest 21 | timeout-minutes: 10 22 | if: "${{ github.event_name == 'push' }}" 23 | outputs: 24 | dependency-graph-enabled: "${{ steps.dependency-graph.outputs.result }}" 25 | codacy-token-set: "${{ steps.check-tokens.outputs.CODACY_TOKEN_SET }}" 26 | sonar-token-set: "${{ steps.check-tokens.outputs.SONAR_TOKEN_SET }}" 27 | 28 | steps: 29 | - name: "Verify tokens" 30 | id: check-tokens 31 | shell: bash 32 | env: 33 | CODACY_TOKEN: "${{ secrets.CODACY_PROJECT_TOKEN }}" 34 | SONAR_TOKEN: "${{ secrets.SONAR_TOKEN }}" 35 | run: | 36 | # Verifying tokens... 37 | # Codacy 38 | if test -n "${CODACY_TOKEN?}"; then token_set='true'; else token_set='false'; fi 39 | printf 'CODACY_TOKEN_SET=%s\n' "${token_set:?}" 1>> "${GITHUB_OUTPUT?}" 40 | # SonarQube 41 | if test -n "${SONAR_TOKEN?}"; then token_set='true'; else token_set='false'; fi 42 | printf 'SONAR_TOKEN_SET=%s\n' "${token_set:?}" 1>> "${GITHUB_OUTPUT?}" 43 | - name: "Verify the dependency graph" 44 | id: dependency-graph 45 | uses: actions/github-script@v8 46 | timeout-minutes: 5 47 | with: 48 | retries: 3 49 | script: | 50 | /* jshint esversion: 6 */ 51 | const response = await github.rest.dependencyGraph.exportSbom({ 52 | owner: context.repo.owner, 53 | repo: context.repo.repo, 54 | }).catch(response => response); 55 | if(response && response.status === 200) { 56 | console.log('The dependency graph is enabled.'); 57 | return true; 58 | } else if(response && response.status === 404) { 59 | console.error('::error::The dependency graph is disabled.'); 60 | } else { 61 | let errorMsg = 'exportSbom failed'; 62 | if(response && response.status && response.message) errorMsg += ' with error ' + response.status + ' (' + response.message + ')'; 63 | throw new Error(errorMsg); 64 | } 65 | return false; 66 | 67 | dependency-submission: 68 | name: "Dependency submission" 69 | needs: [pre-requisites] 70 | runs-on: ubuntu-latest 71 | timeout-minutes: 10 72 | if: "${{ github.event_name == 'push' && needs.pre-requisites.outputs.dependency-graph-enabled == 'true' }}" 73 | permissions: 74 | contents: write 75 | 76 | steps: 77 | - name: "Checkout sources" 78 | uses: actions/checkout@v6 79 | - name: "Setup Java" 80 | uses: actions/setup-java@v5 81 | with: 82 | distribution: "temurin" 83 | java-version-file: ".tool-versions" 84 | - name: "Generate and submit dependency graph" 85 | uses: gradle/actions/dependency-submission@v5 86 | with: 87 | cache-read-only: true 88 | dependency-graph: "generate-and-submit" 89 | validate-wrappers: true 90 | 91 | codacy: 92 | name: "Codacy" 93 | needs: [pre-requisites] 94 | runs-on: ubuntu-latest 95 | timeout-minutes: 20 96 | if: "${{ github.event_name == 'push' && needs.pre-requisites.outputs.codacy-token-set == 'true' }}" 97 | concurrency: 98 | group: "${{ github.repository_id }}-${{ github.workflow }}-codacy" 99 | cancel-in-progress: false 100 | permissions: 101 | security-events: write 102 | 103 | steps: 104 | - name: "Checkout sources" 105 | uses: actions/checkout@v6 106 | - name: "Codacy analysis" 107 | uses: codacy/codacy-analysis-cli-action@v4 108 | timeout-minutes: 10 109 | with: 110 | project-token: "${{ secrets.CODACY_PROJECT_TOKEN }}" 111 | #verbose: true 112 | output: "results.sarif" 113 | format: "sarif" 114 | # Adjust severity of non-security issues 115 | gh-code-scanning-compat: true 116 | # Force 0 exit code to allow SARIF file generation 117 | # This will hand over control about PR rejection to the GitHub side 118 | max-allowed-issues: 2147483647 119 | upload: false 120 | - name: "Combine multiple SARIF runs" 121 | shell: bash 122 | run: | 123 | jq '.runs |= unique_by({tool, invocations, results})' 0< './results.sarif' 1> './results-combined.sarif' 124 | - name: "Upload SARIF results file" 125 | uses: github/codeql-action/upload-sarif@v4 126 | with: 127 | sarif_file: "results-combined.sarif" 128 | category: "Codacy" 129 | 130 | sonarqube: 131 | name: "SonarQube" 132 | needs: [pre-requisites] 133 | runs-on: ubuntu-latest 134 | timeout-minutes: 20 135 | if: "${{ github.event_name == 'push' && needs.pre-requisites.outputs.sonar-token-set == 'true' }}" 136 | 137 | steps: 138 | - name: "Checkout sources" 139 | uses: actions/checkout@v6 140 | with: 141 | fetch-depth: "0" # Shallow clones should be disabled for a better relevancy of analysis 142 | - name: "SonarQube scan" 143 | uses: SonarSource/sonarqube-scan-action@v7 144 | timeout-minutes: 10 145 | env: 146 | SONAR_TOKEN: "${{ secrets.SONAR_TOKEN }}" 147 | -------------------------------------------------------------------------------- /.github/workflows/tag-and-release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | # IMPORTANT: Do NOT enable "Require linear history" inside rulesets for tags or this will fail with error 422 (Reference update failed)!!! 6 | name: "1) Tag and release" 7 | permissions: {} 8 | on: 9 | workflow_dispatch: 10 | 11 | jobs: 12 | create-tag: 13 | name: "Create tag" 14 | runs-on: ubuntu-latest 15 | timeout-minutes: 10 16 | if: "${{ github.ref_type == 'branch' && github.run_attempt == '1' }}" 17 | concurrency: 18 | group: "${{ github.repository_id }}-${{ github.workflow }}-tag" 19 | cancel-in-progress: false 20 | outputs: 21 | tag-name: "${{ steps.repo-info.outputs.version }}" 22 | tag-creation-success: "${{ steps.tag-creation.outputs.result }}" 23 | permissions: 24 | contents: write # Needed to create a tag 25 | 26 | steps: 27 | - name: "Checkout sources" 28 | uses: actions/checkout@v6 29 | with: 30 | sparse-checkout: | 31 | zip-content/module.prop 32 | sparse-checkout-cone-mode: false 33 | - name: "Parse info" 34 | id: "repo-info" 35 | shell: bash 36 | run: | 37 | # Parsing info... 38 | version="$(grep -m 1 -e '^version=' -- './zip-content/module.prop' | cut -d '=' -f '2-' -s)" || exit "${?}" 39 | now="$(date -u -Is)" || exit "${?}" 40 | printf 'version=%s\n' "${version:?}" 1>> "${GITHUB_OUTPUT?}" || exit "${?}" 41 | printf 'now=%s\n' "${now:?}" 1>> "${GITHUB_OUTPUT?}" || exit "${?}" 42 | - name: "Create annotated tag" 43 | id: tag-creation 44 | uses: actions/github-script@v8 45 | timeout-minutes: 5 46 | env: 47 | ACTOR_ID: "${{ github.actor_id }}" 48 | TAG_NAME: "${{ steps.repo-info.outputs.version }}" 49 | TAG_DATE: "${{ steps.repo-info.outputs.now }}" 50 | with: 51 | result-encoding: string 52 | retries: 3 53 | script: | 54 | /* jshint esversion: 6 */ 55 | function errorOut(apiName, e) 56 | { 57 | let errorMsg = apiName + '() failed'; 58 | if(e) 59 | { 60 | //console.warn('e.name: ' + e.name); 61 | //console.warn('e.statusText: ' + e.statusText); 62 | if(e.response && e.response.headers) console.warn('Rate limit - remaining: ' + e.response.headers['x-ratelimit-remaining']); 63 | if(e.status || e.message) errorMsg += ' with error ' + e.status + ' (' + e.message + ')'; 64 | } 65 | throw new Error(errorMsg); 66 | } 67 | const actor_id = process.env.ACTOR_ID; 68 | const tag_name = process.env.TAG_NAME; 69 | const tag_date = process.env.TAG_DATE; 70 | console.log('::notice::Tag name: ' + tag_name); 71 | console.log('::notice::Tag date: ' + tag_date); 72 | const responseUser = await github.rest.users.getByUsername({ 73 | username: context.actor 74 | }).catch(responseUser => responseUser); 75 | if(responseUser && responseUser.status === 200 && responseUser.data && responseUser.data.name) { 76 | // User data retrieved correctly 77 | } else { 78 | errorOut('users.getByUsername', responseUser); 79 | } 80 | // If public e-mail is missing, use default 81 | const email = responseUser.data.email ? responseUser.data.email : actor_id + '+' + context.actor + '@users.noreply.github.com'; 82 | const responseTag = await github.rest.git.createTag({ 83 | owner: context.repo.owner, 84 | repo: context.repo.repo, 85 | tag: tag_name, 86 | message: 'Release ' + tag_name, 87 | object: context.sha, 88 | type: 'commit', 89 | tagger: { 90 | name: responseUser.data.name, 91 | email: email, 92 | date: tag_date 93 | } 94 | }).catch(responseTag => responseTag); 95 | if(responseTag && responseTag.status === 201 && responseTag.data && responseTag.data.sha) { 96 | console.log('Tag object created correctly: ' + responseTag.data.sha); 97 | if(responseTag.data.verification) 98 | { 99 | console.log('Tag - verified: ' + responseTag.data.verification.verified); 100 | console.log('Tag - reason: ' + responseTag.data.verification.reason); 101 | console.log('Tag - verification date: ' + responseTag.data.verification.verified_at); 102 | } 103 | //console.log(JSON.stringify(responseTag.data)); 104 | } else { 105 | errorOut('git.createTag', responseTag); 106 | } 107 | const response = await github.rest.git.createRef({ 108 | owner: context.repo.owner, 109 | repo: context.repo.repo, 110 | ref: 'refs/tags/' + tag_name, 111 | sha: responseTag.data.sha 112 | }).catch(response => response); 113 | if(response && response.status === 201 && response.data.ref) { 114 | console.log('Tag ref created correctly: ' + response.data.ref); 115 | return true; 116 | } else if(response && response.status === 422 && response.message === 'Reference already exists') { 117 | console.warn('::warning::Tag already exist!!!'); 118 | } else { 119 | errorOut('git.createRef', response); 120 | } 121 | return false; 122 | 123 | call-workflow: 124 | name: "Call workflow" 125 | needs: [create-tag] 126 | if: "${{ needs.create-tag.outputs.tag-creation-success == 'true' }}" 127 | uses: "./.github/workflows/auto-release-from-tag.yml" 128 | with: 129 | tag-name: "${{ needs.create-tag.outputs.tag-name }}" 130 | permissions: 131 | contents: write # Needed to create a release 132 | id-token: write # Needed to attest build provenance 133 | attestations: write # Needed to attest build provenance 134 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /.github/workflows/auto-release-from-tag.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Auto-release from tag" 6 | permissions: {} 7 | on: 8 | push: 9 | tags: 10 | - "v*.*" 11 | workflow_call: 12 | inputs: 13 | tag-name: 14 | required: true 15 | type: "string" 16 | 17 | jobs: 18 | release: 19 | name: "Release" 20 | runs-on: ubuntu-latest 21 | timeout-minutes: 30 22 | if: "${{ inputs.tag-name || startsWith(github.ref, 'refs/tags/v') }}" 23 | concurrency: 24 | group: "${{ github.repository_id }}-${{ github.workflow }}-release" 25 | cancel-in-progress: false 26 | permissions: 27 | contents: write # Needed to create a release 28 | id-token: write # Needed to attest build provenance 29 | attestations: write # Needed to attest build provenance 30 | 31 | steps: 32 | - name: "Checkout sources" 33 | uses: actions/checkout@v6 34 | - name: "Setup Java" 35 | uses: actions/setup-java@v5 36 | with: 37 | distribution: "temurin" 38 | java-version-file: ".tool-versions" 39 | - name: "Build the flashable OTA zip" 40 | id: "build" 41 | shell: bash 42 | timeout-minutes: 10 43 | run: | 44 | # Building... 45 | make clean buildotaoss 46 | - name: "Attest build provenance" 47 | id: "attest" 48 | uses: actions/attest-build-provenance@v3 49 | timeout-minutes: 10 50 | if: "${{ vars.ATTESTATION == 'true' && github.run_attempt == '1' && steps.build.outputs.ZIP_IS_ALPHA == 'false' && steps.build.outputs.ZIP_BUILD_TYPE_SUPPORTED == 'true' }}" 51 | with: 52 | subject-path: "${{ steps.build.outputs.ZIP_FOLDER }}/*.zip" 53 | show-summary: false 54 | - name: "ZIP info" 55 | id: "info" 56 | shell: bash 57 | run: | 58 | # Retrieving informations... 59 | test -n '${{ steps.build.outputs.ZIP_FOLDER }}' || exit 3 60 | ZIP_FILENAME='${{ steps.build.outputs.ZIP_FILENAME }}' 61 | ZIP_VERSION='${{ steps.build.outputs.ZIP_VERSION }}' 62 | ZIP_SHORT_COMMIT_ID='${{ steps.build.outputs.ZIP_SHORT_COMMIT_ID }}' 63 | ZIP_IS_ALPHA='${{ steps.build.outputs.ZIP_IS_ALPHA }}' 64 | ZIP_BUILD_TYPE='${{ steps.build.outputs.ZIP_BUILD_TYPE }}' 65 | ZIP_BUILD_TYPE_SUPPORTED='${{ steps.build.outputs.ZIP_BUILD_TYPE_SUPPORTED }}' 66 | ZIP_MD5='${{ steps.build.outputs.ZIP_MD5 }}' 67 | ZIP_SHA256='${{ steps.build.outputs.ZIP_SHA256 }}' 68 | ZIP_ATTESTATION_URL='${{ steps.attest.outputs.attestation-url }}' 69 | # Displaying informations... 70 | printf '%s\n' "::notice::Filename: ${ZIP_FILENAME:-Missing}" 71 | printf '%s\n' "::notice::Version: ${ZIP_VERSION:?} - Short commit ID: ${ZIP_SHORT_COMMIT_ID:?} - Is alpha: ${ZIP_IS_ALPHA:?} - Build type: ${ZIP_BUILD_TYPE:?}" 72 | printf '%s\n' "::notice::Build type supported: ${ZIP_BUILD_TYPE_SUPPORTED:?}" 73 | printf '%s\n' "::notice::MD5: ${ZIP_MD5:-Missing}" 74 | printf '%s\n' "::notice::SHA-256: ${ZIP_SHA256:-Missing}" 75 | printf '%s\n' "::notice::Logs retention days: ${{ github.retention_days }}" 76 | printf '%s\n' "::notice::Attestation: ${ZIP_ATTESTATION_URL:-Missing}" 77 | # Preparing temp folder... 78 | export TMPDIR="${TMPDIR:-${RUNNER_TEMP:-${TMP:-${TEMP:-/tmp}}}}" || exit "${?}" 79 | our_tmp_dir="$(mktemp -d -t -- "RELEASE-${ZIP_IS_ALPHA:?}-XXXXXX")" || exit "${?}" 80 | test -n "${our_tmp_dir?}" || exit "${?}" 81 | rm -r -f -- "${our_tmp_dir:?}"/* || exit "${?}" # Empty our temp dir (should be already empty, but we must be sure) 82 | # Preparing release notes... 83 | release_type='release' 84 | repo_url='${{ github.server_url }}/${{ github.repository }}' 85 | { 86 | printf '%s' '**If you want to help me you can donate to me using the `Sponsor` button at the top of ' 87 | printf '%s\n' "[this repository](${repo_url:?})." 88 | printf '%s\n' 'Donations are appreciated and will always remain optional.**' 89 | printf '\n' 90 | if test "${release_type:?}" != 'release'; then 91 | printf '%s\n\n' "Latest automatically built ZIP ($(date -u -- '+%Y/%m/%d' || :))." 92 | fi 93 | printf '%s\n\n' '## Verification' 94 | test -z "${ZIP_SHA256?}" || printf '%s\n' "SHA-256: ${ZIP_SHA256:?}" 95 | test -z "${ZIP_ATTESTATION_URL?}" || printf '\n%s\n' "Attestation: ${ZIP_ATTESTATION_URL:?}" 96 | if test "${release_type:?}" = 'release'; then 97 | printf '\n' 98 | printf '%s\n\n' '## Changelog' 99 | printf '\n%s\n' '[**Changelog**](./CHANGELOG.rst).' 100 | fi 101 | } 1> "${our_tmp_dir:?}/release-notes.md" || exit "${?}" 102 | printf 'ZIP_RELEASE_NOTES=%s\n' "${our_tmp_dir:?}/release-notes.md" 1>> "${GITHUB_OUTPUT?}" 103 | # Preparing attestation file... 104 | old_attest_file='${{ steps.attest.outputs.bundle-path }}' 105 | if test -n "${old_attest_file?}"; then 106 | new_attest_file="${our_tmp_dir:?}/${release_type:?}-$(basename -- "${old_attest_file:?}")" || exit "${?}" 107 | cp -f -T -- "${old_attest_file:?}" "${new_attest_file:?}" || exit "${?}" 108 | printf 'ZIP_ATTESTATION_FILE=%s\n' "${new_attest_file:?}" 1>> "${GITHUB_OUTPUT?}" 109 | fi 110 | - name: "Release logic" 111 | id: "release-logic" 112 | shell: bash 113 | run: | 114 | # Release logic... 115 | CREATE_RELEASE='false' 116 | if '${{ github.run_attempt == '1' && steps.build.outputs.ZIP_IS_ALPHA == 'false' && steps.build.outputs.ZIP_BUILD_TYPE_SUPPORTED == 'true' }}'; then 117 | CREATE_RELEASE='true' 118 | fi 119 | printf 'CREATE_RELEASE=%s\n' "${CREATE_RELEASE:?}" 1>> "${GITHUB_OUTPUT?}" 120 | printf 'Create release? %s\n' "${CREATE_RELEASE:?}" 121 | # Verifying tag name... 122 | if '${{ github.event_name == 'workflow_dispatch' && inputs.tag-name != '' }}'; then # The "workflow_call" event still pass as "workflow_dispatch" 123 | if '${{ startsWith(inputs.tag-name, 'v') }}'; then 124 | TAG_NAME='${{ inputs.tag-name }}' 125 | else 126 | printf '%s\n' '::error::Invalid "tag-name" parameter: ${{ inputs.tag-name }}' 127 | exit 3 128 | fi 129 | elif '${{ startsWith(github.ref, 'refs/tags/v') }}'; then 130 | TAG_NAME='${{ github.ref_name }}' 131 | else 132 | printf '%s\n' '::error::Invalid tag name: ${{ github.ref_name }}' 133 | exit 4 134 | fi 135 | printf 'TAG_NAME=%s\n' "${TAG_NAME:?}" 1>> "${GITHUB_OUTPUT?}" 136 | - name: "Create release" 137 | uses: softprops/action-gh-release@v2 138 | if: "${{ steps.release-logic.outputs.CREATE_RELEASE == 'true' }}" 139 | with: 140 | name: "${{ steps.release-logic.outputs.TAG_NAME }}" 141 | tag_name: "${{ steps.release-logic.outputs.TAG_NAME }}" 142 | target_commitish: "${{ github.sha }}" 143 | body_path: "${{ steps.info.outputs.ZIP_RELEASE_NOTES }}" 144 | append_body: true 145 | generate_release_notes: true 146 | draft: false 147 | overwrite_files: false 148 | files: | 149 | ${{ steps.build.outputs.ZIP_FOLDER }}/*.zip* 150 | ${{ steps.info.outputs.ZIP_ATTESTATION_FILE }} 151 | fail_on_unmatched_files: true 152 | -------------------------------------------------------------------------------- /tools/dl-perm-list.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # @name Android permissions retriever 3 | # @brief Retrieve the list of Android system permissions 4 | # @author ale5000 5 | # Get the latest version from here: https://github.com/micro5k/microg-unofficial-installer/tree/main/tools 6 | 7 | # SPDX-FileCopyrightText: (c) 2025 ale5000 8 | # SPDX-License-Identifier: GPL-3.0-or-later OR Apache-2.0 9 | 10 | # shellcheck enable=all 11 | # shellcheck disable=SC3043 # In POSIX sh, local is undefined 12 | 13 | readonly SCRIPT_NAME='Android permissions retriever' 14 | readonly SCRIPT_SHORTNAME='DlPermList' 15 | readonly SCRIPT_VERSION='0.3.0' 16 | readonly SCRIPT_AUTHOR='ale5000' 17 | 18 | set -u 19 | # shellcheck disable=SC3040,SC3041,SC2015 20 | { 21 | # Unsupported set options may cause the shell to exit (even without set -e), so first try them in a subshell to avoid this issue 22 | (set +H 2> /dev/null) && set +H || true 23 | (set -o pipefail 2> /dev/null) && set -o pipefail || true 24 | } 25 | 26 | readonly BASE_URL='https://android.googlesource.com/platform/frameworks/base/' 27 | readonly MAX_API='36' 28 | 29 | # shellcheck disable=SC2034 30 | { 31 | readonly TAG_API_23='android-6.0.1_r81' # Android 6 32 | readonly TAG_API_24='android-7.0.0_r36' # Android 7.0 33 | readonly TAG_API_25='android-7.1.2_r39' # Android 7.1 34 | readonly TAG_API_26='android-8.0.0_r51' # Android 8.0 35 | readonly TAG_API_27='android-8.1.0_r81' # Android 8.1 36 | readonly TAG_API_28='android-9.0.0_r61' # Android 9 37 | readonly TAG_API_29='android-10.0.0_r47' # Android 10 38 | readonly TAG_API_30='android-11.0.0_r48' # Android 11 39 | readonly TAG_API_31='android-12.0.0_r34' # Android 12.0 40 | readonly TAG_API_32='android-12.1.0_r27' # Android 12.1 41 | readonly TAG_API_33='android-13.0.0_r84' # Android 13 42 | readonly TAG_API_34='android-14.0.0_r75' # Android 14 43 | readonly TAG_API_35='android-15.0.0_r36' # Android 15 44 | readonly TAG_API_36='android-16.0.0_r2' # Android 16 45 | } 46 | 47 | readonly WGET_CMD='wget' 48 | readonly DL_UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0' 49 | readonly DL_ACCEPT_HEADER='Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 50 | readonly DL_ACCEPT_LANG_HEADER='Accept-Language: en-US,en;q=0.5' 51 | 52 | pause_if_needed() 53 | { 54 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, SHLVL is undefined 55 | if test "${NO_PAUSE:-0}" = '0' && test "${no_pause:-0}" = '0' && test "${CI:-false}" = 'false' && test "${TERM_PROGRAM:-unknown}" != 'vscode' && test "${SHLVL:-1}" = '1' && test -t 0 && test -t 1 && test -t 2; then 56 | if test -n "${NO_COLOR-}"; then 57 | printf 1>&2 '\n%s' 'Press any key to exit... ' || : 58 | else 59 | printf 1>&2 '\n\033[1;32m\r%s' 'Press any key to exit... ' || : 60 | fi 61 | # shellcheck disable=SC3045 # Ignore: In POSIX sh, read -s / -n is undefined 62 | IFS='' read 2> /dev/null 1>&2 -r -s -n1 _ || IFS='' read 1>&2 -r _ || : 63 | printf 1>&2 '\n' || : 64 | test -n "${NO_COLOR-}" || printf 1>&2 '\033[0m\r \r' || : 65 | fi 66 | unset no_pause || : 67 | return "${1:-0}" 68 | } 69 | 70 | show_status() 71 | { 72 | printf 1>&2 '\033[1;32m%s\033[0m\n' "${1?}" 73 | } 74 | 75 | show_error() 76 | { 77 | printf 1>&2 '\n\033[1;31m%s\033[0m\n' "ERROR: ${1?}" 78 | } 79 | 80 | find_data_dir() 81 | { 82 | local _path 83 | 84 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, BASH_SOURCE is undefined 85 | if test -n "${TOOLS_DATA_DIR-}" && _path="${TOOLS_DATA_DIR:?}" && test -d "${_path:?}"; then 86 | : 87 | elif test -n "${BASH_SOURCE-}" && _path="$(dirname "${BASH_SOURCE:?}")/data" && test -d "${_path:?}"; then 88 | : # It is expected: expanding an array without an index gives the first element 89 | elif test -n "${0-}" && _path="$(dirname "${0:?}")/data" && test -d "${_path:?}"; then 90 | : 91 | elif _path='./data' && test -d "${_path:?}"; then 92 | : 93 | else 94 | return 1 95 | fi 96 | 97 | _path="$(realpath 2> /dev/null "${_path:?}" || readlink -f "${_path:?}")" || return 1 98 | printf '%s\n' "${_path:?}" 99 | } 100 | 101 | create_and_return_data_dir() 102 | { 103 | local _path 104 | 105 | # shellcheck disable=SC3028 # Ignore: In POSIX sh, BASH_SOURCE is undefined 106 | if test -n "${TOOLS_DATA_DIR-}" && _path="${TOOLS_DATA_DIR:?}"; then 107 | : 108 | elif test -n "${BASH_SOURCE-}" && test -f "${BASH_SOURCE:?}" && _path="$(dirname "${BASH_SOURCE:?}")/data"; then 109 | : # It is expected: expanding an array without an index gives the first element 110 | elif test -n "${0-}" && test -f "${0:?}" && _path="$(dirname "${0:?}")/data"; then 111 | : 112 | elif _path='./data'; then 113 | : 114 | else 115 | return 1 116 | fi 117 | 118 | test -d "${_path:?}" || mkdir -p -- "${_path:?}" || return 1 119 | 120 | _path="$(realpath 2> /dev/null "${_path:?}" || readlink -f "${_path:?}")" || return 1 121 | printf '%s\n' "${_path:?}" 122 | } 123 | 124 | dl() 125 | { 126 | "${WGET_CMD:?}" -q -O "${2:?}" -U "${DL_UA:?}" --header "${DL_ACCEPT_HEADER:?}" --header "${DL_ACCEPT_LANG_HEADER:?}" --no-cache -- "${1:?}" || return "${?}" 127 | } 128 | 129 | download_and_parse_permissions() 130 | { 131 | printf '%s\n' '' 1> "${DATA_DIR:?}/perms/base-permissions-api-${1:?}.xml" || return "${?}" 132 | 133 | dl "${BASE_URL:?}+/refs/tags/${2:?}/core/res/AndroidManifest.xml?format=text" '-' | 134 | base64 -d | 135 | tr -s -- '\n' ' ' | 136 | sed -e 's|>|>\n|g' | 137 | grep -F -e '> "${DATA_DIR:?}/perms/base-permissions-api-${1:?}.xml" || return "${?}" 138 | 139 | printf '%s\n' '' 1>> "${DATA_DIR:?}/perms/base-permissions-api-${1:?}.xml" || return "${?}" 140 | } 141 | 142 | main() 143 | { 144 | local api tag 145 | 146 | command 1> /dev/null -v "${WGET_CMD:?}" || { 147 | show_error 'Missing: wget' 148 | return 255 149 | } 150 | 151 | DATA_DIR="$(find_data_dir || create_and_return_data_dir)" || return 1 152 | test -d "${DATA_DIR:?}/perms" || mkdir -p -- "${DATA_DIR:?}/perms" || return 1 153 | 154 | for api in $(seq -- 23 "${MAX_API:?}"); do 155 | tag="$(eval " printf '%s\n' \"\${TAG_API_${api:?}:?}\" ")" || { 156 | printf '%s\n' "Failed to get tag for API ${api?}" 157 | return 4 158 | } 159 | printf '%s\n' "API ${api:?}: ${tag:?}" 160 | download_and_parse_permissions "${api:?}" "${tag:?}" || { 161 | printf '%s\n' "Failed to download/parse XML for API ${api?}" 162 | return 5 163 | } 164 | done 165 | } 166 | 167 | STATUS=0 168 | execute_script='true' 169 | 170 | while test "${#}" -gt 0; do 171 | case "${1?}" in 172 | -V | --version) 173 | printf '%s\n' "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?}" 174 | printf '%s\n' "Copy""right (c) 2025 ${SCRIPT_AUTHOR:?}" 175 | printf '%s\n' 'License GPL-3.0+ OR Apache-2.0' 176 | execute_script='false' 177 | ;; 178 | 179 | --) 180 | shift 181 | break 182 | ;; 183 | 184 | --*) 185 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: unrecognized option '${1}'" 186 | execute_script='false' 187 | STATUS=2 188 | ;; 189 | 190 | -*) 191 | printf 1>&2 '%s\n' "${SCRIPT_SHORTNAME?}: invalid option -- '${1#-}'" 192 | execute_script='false' 193 | STATUS=2 194 | ;; 195 | 196 | *) 197 | break 198 | ;; 199 | esac 200 | 201 | shift 202 | done 203 | 204 | if test "${execute_script:?}" = 'true'; then 205 | show_status "${SCRIPT_NAME:?} v${SCRIPT_VERSION:?} by ${SCRIPT_AUTHOR:?}" 206 | 207 | if test "${#}" -eq 0; then set -- ''; fi 208 | main "${@}" || STATUS="${?}" 209 | fi 210 | 211 | pause_if_needed "${STATUS:?}" 212 | exit "${?}" 213 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /zip-content/scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # SPDX-FileCopyrightText: (c) 2016 ale5000 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | list_app_data_to_remove() 6 | { 7 | cat << 'EOF' 8 | com.google.android.syncadapters.contacts 9 | com.google.android.syncadapters.calendar 10 | com.google.android.backuptransport 11 | EOF 12 | } 13 | 14 | uninstall_list() 15 | { 16 | cat << 'EOF' 17 | GoogleContactsSyncAdapter|com.google.android.syncadapters.contacts 18 | GoogleCalendarSyncAdapter|com.google.android.syncadapters.calendar 19 | GoogleBackupTransport|com.google.android.backuptransport 20 | EOF 21 | } 22 | 23 | framework_uninstall_list() 24 | { 25 | cat << 'EOF' 26 | EOF 27 | } 28 | 29 | if test "${IS_INCLUDED:-false}" = 'false'; then 30 | ui_error() 31 | { 32 | printf 1>&2 '\033[1;31m%s\033[0m\n' "ERROR: ${1?}" 33 | exit 1 34 | } 35 | 36 | ui_debug() 37 | { 38 | printf '%s\n' "${1?}" 39 | } 40 | 41 | delete() 42 | { 43 | for filename in "${@}"; do 44 | if test -e "${filename?}"; then 45 | ui_debug "Deleting '${filename?}'...." 46 | rm -rf -- "${filename:?}" || ui_debug 'Failed to delete files/folders' 47 | fi 48 | done 49 | } 50 | 51 | delete_if_sha256_match() 52 | { 53 | if test -f "${1:?}"; then 54 | _filename="${1:?}" 55 | _filehash="$(sha256sum -- "${_filename:?}" | cut -d ' ' -f '1' -s)" || ui_error 'Failed to calculate SHA256 hash' 56 | shift 57 | for _hash in "${@}"; do 58 | if test "${_hash:?}" = "${_filehash:?}"; then 59 | ui_debug "Deleting '${_filename:?}'..." 60 | rm -f -- "${_filename:?}" || ui_error 'Failed to delete file in delete_if_sha256_match()' 61 | return 62 | fi 63 | done 64 | ui_debug "Deletion of '${_filename:?}' skipped due to hash mismatch!" 65 | fi 66 | } 67 | 68 | ui_debug 'Uninstalling...' 69 | 70 | # shellcheck disable=SC2034 71 | { 72 | SETUP_TYPE='uninstall' 73 | FIRST_INSTALLATION='true' 74 | API=999 75 | SYS_PATH="${SYS_PATH:-/system}" 76 | PRODUCT_PATH="${PRODUCT_PATH:-/product}" 77 | VENDOR_PATH="${VENDOR_PATH:-/vendor}" 78 | SYS_EXT_PATH="${SYS_EXT_PATH:-/system_ext}" 79 | PRIVAPP_DIRNAME='priv-app' 80 | DATA_PATH="${ANDROID_DATA:-/data}" 81 | DEST_PATH="${SYS_PATH:?}" 82 | } 83 | fi 84 | 85 | delete_symlinks() 86 | { 87 | for filename in "${@}"; do 88 | if test -L "${filename?}"; then 89 | ui_debug "Deleting symlink '${filename?}'...." 90 | rm -f -- "${filename:?}" || ui_debug 'Failed to delete symlink' 91 | fi 92 | done 93 | } 94 | 95 | delete_folder_content_silent() 96 | { 97 | if test -e "${1:?}"; then 98 | find "${1:?}" -mindepth 1 -delete 99 | fi 100 | } 101 | 102 | INTERNAL_MEMORY_PATH='/sdcard0' 103 | if test -e '/mnt/sdcard'; then INTERNAL_MEMORY_PATH='/mnt/sdcard'; fi 104 | 105 | delete "${SYS_PATH:?}"/addon.d/*-google-sync.sh 106 | 107 | uninstall_list | while IFS='|' read -r FILENAME INTERNAL_NAME _; do 108 | if test -n "${INTERNAL_NAME}"; then 109 | delete "${SYS_PATH:?}/${PRIVAPP_DIRNAME:?}/${INTERNAL_NAME}" 110 | delete "${SYS_PATH:?}/${PRIVAPP_DIRNAME:?}/${INTERNAL_NAME}.apk" 111 | delete "${SYS_PATH:?}/app/${INTERNAL_NAME}" 112 | delete "${SYS_PATH:?}/app/${INTERNAL_NAME}.apk" 113 | fi 114 | 115 | if test -n "${FILENAME}"; then 116 | delete "${SYS_PATH:?}/${PRIVAPP_DIRNAME:?}/${FILENAME}" 117 | delete "${SYS_PATH:?}/${PRIVAPP_DIRNAME:?}/${FILENAME}.apk" 118 | delete "${SYS_PATH:?}/${PRIVAPP_DIRNAME:?}/${FILENAME}.odex" 119 | delete "${SYS_PATH:?}/app/${FILENAME}" 120 | delete "${SYS_PATH:?}/app/${FILENAME}.apk" 121 | delete "${SYS_PATH:?}/app/${FILENAME}.odex" 122 | 123 | delete "${PRODUCT_PATH:-/product}/priv-app/${FILENAME}" 124 | delete "${PRODUCT_PATH:-/product}/app/${FILENAME}" 125 | delete "${SYS_PATH:?}/product/priv-app/${FILENAME}" 126 | delete "${SYS_PATH:?}/product/app/${FILENAME}" 127 | 128 | delete "${VENDOR_PATH:-/vendor}/priv-app/${FILENAME}" 129 | delete "${VENDOR_PATH:-/vendor}/app/${FILENAME}" 130 | delete "${SYS_PATH:?}/vendor/priv-app/${FILENAME}" 131 | delete "${SYS_PATH:?}/vendor/app/${FILENAME}" 132 | 133 | delete "${SYS_EXT_PATH:-/system_ext}/priv-app/${FILENAME}" 134 | delete "${SYS_EXT_PATH:-/system_ext}/app/${FILENAME}" 135 | delete "${SYS_PATH:?}/system_ext/priv-app/${FILENAME}" 136 | delete "${SYS_PATH:?}/system_ext/app/${FILENAME}" 137 | 138 | # Dalvik cache 139 | delete "${DATA_PATH:?}"/dalvik-cache/system@priv-app@"${FILENAME:?}"[@\.]*@classes* 140 | delete "${DATA_PATH:?}"/dalvik-cache/system@app@"${FILENAME:?}"[@\.]*@classes* 141 | delete "${DATA_PATH:?}"/dalvik-cache/*/system@priv-app@"${FILENAME:?}"[@\.]*@classes* 142 | delete "${DATA_PATH:?}"/dalvik-cache/*/system@app@"${FILENAME:?}"[@\.]*@classes* 143 | 144 | # Package caches 145 | delete "${DATA_PATH:?}"/system/package_cache/*/"${FILENAME:?}"-* 146 | 147 | # Delete legacy libs (very unlikely to be present but possible) 148 | delete "${SYS_PATH:?}/lib64/${FILENAME:?}" 149 | delete "${SYS_PATH:?}/lib/${FILENAME:?}" 150 | delete "${VENDOR_PATH:-/vendor}/lib64/${FILENAME:?}" 151 | delete "${VENDOR_PATH:-/vendor}/lib/${FILENAME:?}" 152 | delete "${SYS_PATH:?}/vendor/lib64/${FILENAME:?}" 153 | delete "${SYS_PATH:?}/vendor/lib/${FILENAME:?}" 154 | 155 | # Current xml paths 156 | delete "${SYS_PATH:?}/etc/permissions/privapp-permissions-${FILENAME:?}.xml" 157 | delete "${SYS_PATH:?}/etc/default-permissions/default-permissions-${FILENAME:?}.xml" 158 | # Legacy xml paths 159 | delete "${SYS_PATH:?}/etc/default-permissions/${FILENAME:?}-permissions.xml" 160 | fi 161 | 162 | if test -n "${INTERNAL_NAME?}"; then 163 | # Only delete app updates during uninstallation or first-time installation 164 | if test "${SETUP_TYPE:?}" = 'uninstall' || test "${FIRST_INSTALLATION:?}" = 'true'; then 165 | delete "${DATA_PATH:?}/app/${INTERNAL_NAME:?}.apk" 166 | delete "${DATA_PATH:?}/app/${INTERNAL_NAME:?}" 167 | delete "${DATA_PATH:?}/app/${INTERNAL_NAME:?}"-* 168 | delete "${DATA_PATH:?}"/app/*/"${INTERNAL_NAME:?}"-* # Recent Android 169 | delete "/mnt/asec/${INTERNAL_NAME:?}.apk" 170 | delete "/mnt/asec/${INTERNAL_NAME:?}" 171 | delete "/mnt/asec/${INTERNAL_NAME:?}"-* 172 | # ToDO => Check also /data/app-private /data/app-asec /data/preload 173 | 174 | # App libs 175 | delete "${DATA_PATH:?}/app-lib/${INTERNAL_NAME:?}" 176 | delete "${DATA_PATH:?}/app-lib/${INTERNAL_NAME:?}"-* 177 | delete_symlinks "${DATA_PATH:?}/data/${INTERNAL_NAME:?}/lib" 178 | fi 179 | 180 | # Dalvik caches 181 | delete "${DATA_PATH:?}"/dalvik-cache/data@app@"${INTERNAL_NAME:?}"-*@classes* 182 | delete "${DATA_PATH:?}"/dalvik-cache/*/data@app@"${INTERNAL_NAME:?}"-*@classes* 183 | delete "${DATA_PATH:?}"/dalvik-cache/profiles/"${INTERNAL_NAME:?}" 184 | 185 | # Package caches 186 | delete "${DATA_PATH:?}"/system/package_cache/*/"${INTERNAL_NAME:?}"-* 187 | delete "${DATA_PATH:?}"/system_ce/*/shortcut_service/packages/"${INTERNAL_NAME:?}"* 188 | 189 | # Caches 190 | delete_folder_content_silent "${DATA_PATH:?}/data/${INTERNAL_NAME:?}/code_cache" 191 | delete_folder_content_silent "${DATA_PATH:?}/data/${INTERNAL_NAME:?}/cache" 192 | delete_folder_content_silent "${DATA_PATH:?}/data/${INTERNAL_NAME:?}/app_webview/Cache" 193 | delete_folder_content_silent "${DATA_PATH:?}/data/${INTERNAL_NAME:?}/app_cache_dg" 194 | 195 | # Legacy xml paths 196 | delete "${SYS_PATH:?}/etc/default-permissions/${INTERNAL_NAME:?}-permissions.xml" 197 | # Other installers 198 | delete "${SYS_PATH:?}/etc/permissions/privapp-permissions-${INTERNAL_NAME:?}.xml" 199 | delete "${SYS_PATH:?}/etc/permissions/permissions_${INTERNAL_NAME:?}.xml" 200 | delete "${SYS_PATH:?}/etc/permissions/${INTERNAL_NAME:?}.xml" 201 | delete "${SYS_PATH:?}/etc/default-permissions/default-permissions-${INTERNAL_NAME:?}.xml" 202 | 203 | delete "${SYS_PATH:?}/etc/sysconfig/sysconfig-${INTERNAL_NAME:?}.xml" 204 | fi 205 | done 206 | STATUS="$?" 207 | if test "${STATUS}" -ne 0; then exit "${STATUS}"; fi 208 | 209 | framework_uninstall_list | while IFS='|' read -r INTERNAL_NAME _; do 210 | if test -n "${INTERNAL_NAME}"; then 211 | delete "${SYS_PATH:?}/framework/${INTERNAL_NAME:?}.jar" 212 | delete "${SYS_PATH:?}/framework/${INTERNAL_NAME:?}.odex" 213 | delete "${SYS_PATH:?}"/framework/oat/*/"${INTERNAL_NAME:?}.odex" 214 | delete "${SYS_PATH:?}/etc/permissions/${INTERNAL_NAME:?}.xml" 215 | 216 | # Dalvik cache 217 | delete "${DATA_PATH:?}"/dalvik-cache/*/system@framework@"${INTERNAL_NAME:?}".jar@classes* 218 | delete "${DATA_PATH:?}"/dalvik-cache/*/system@framework@"${INTERNAL_NAME:?}".odex@classes* 219 | delete "${DATA_PATH:?}"/dalvik-cache/system@framework@"${INTERNAL_NAME:?}".jar@classes* 220 | delete "${DATA_PATH:?}"/dalvik-cache/system@framework@"${INTERNAL_NAME:?}".odex@classes* 221 | fi 222 | done 223 | STATUS="$?" 224 | if test "${STATUS}" -ne 0; then exit "${STATUS}"; fi 225 | 226 | list_app_data_to_remove | while IFS='|' read -r INTERNAL_NAME; do 227 | if test -z "${INTERNAL_NAME?}"; then continue; fi 228 | delete "${DATA_PATH:?}"/misc/profiles/ref/"${INTERNAL_NAME:?}" 229 | delete "${DATA_PATH:?}"/misc/profiles/cur/*/"${INTERNAL_NAME:?}" 230 | delete "${DATA_PATH:?}"/user_de/*/"${INTERNAL_NAME:?}" 231 | delete "${DATA_PATH:?}"/user/*/"${INTERNAL_NAME:?}" 232 | 233 | delete "${DATA_PATH:?}"/data/"${INTERNAL_NAME:?}" 234 | delete "${DATA_PATH:?}"/media/*/Android/data/"${INTERNAL_NAME:?}" 235 | delete "${INTERNAL_MEMORY_PATH}"/Android/data/"${INTERNAL_NAME:?}" 236 | done 237 | 238 | delete "${SYS_PATH:?}"/etc/default-permissions/google-sync-permissions.xml 239 | delete "${SYS_PATH:?}"/etc/default-permissions/contacts-calendar-sync.xml 240 | 241 | # Legacy file 242 | delete "${SYS_PATH:?}/etc/zips/google-sync.prop" 243 | 244 | if test "${IS_INCLUDED:-false}" = 'false'; then 245 | ui_debug 'Done.' 246 | fi 247 | -------------------------------------------------------------------------------- /zip-content/META-INF/com/google/android/update-binary.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | # SPDX-FileCopyrightText: (c) 2016 ale5000 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # shellcheck enable=all 6 | # shellcheck disable=SC3043 # In POSIX sh, local is undefined # 7 | 8 | echo 'PRE-LOADER' || : 9 | 10 | ### INIT OPTIONS ### 11 | 12 | umask 022 || : 13 | set -u 2> /dev/null || : 14 | 15 | # Unsupported set options may cause the shell to exit (even without set -e), so first try them in a subshell to avoid this issue 16 | { 17 | # shellcheck disable=all 18 | (set -o pipefail 1> /dev/null 2>&1) && set -o pipefail || : 19 | } 20 | 21 | ### GLOBAL VARIABLES ### 22 | 23 | export ASH_STANDALONE='1' 24 | export OUTFD="${2:?}" 25 | export ZIPFILE="${3:?}" 26 | unset RANDOM_IS_SEEDED 27 | 28 | ### PREVENTIVE CHECKS ### 29 | 30 | command 1> /dev/null -v 'echo' || { 31 | echo || : 32 | exit 100 33 | } 34 | 35 | command 1> /dev/null -v 'test' || { 36 | echo 1>&2 'ERROR: Missing => test' 37 | exit 100 38 | } 39 | 40 | case "$(:)" in '') ;; *) 41 | echo 1>&2 'ERROR: Command substitution NOT supported by your shell' 42 | exit 100 43 | ;; 44 | esac 45 | 46 | _redirect_command() 47 | { 48 | eval " ${1:?}() { busybox '${1:?}' \"\${@}\"; } " || { 49 | echo 1>&2 "ERROR: Replacing ${1?} failed" 50 | exit 100 51 | } 52 | } 53 | 54 | command 1> /dev/null -v 'printf' || { 55 | if command 1> /dev/null -v busybox; then 56 | _redirect_command 'printf' 57 | else 58 | { 59 | printf() 60 | { 61 | if test "${1:-}" = '%s\n\n'; then _printf_newline='true'; fi 62 | if test "${#}" -gt 1; then shift; fi 63 | echo "${@}" 64 | 65 | test "${_printf_newline:-false}" = 'false' || echo '' 66 | unset _printf_newline 67 | } 68 | } 69 | fi 70 | } 71 | 72 | command 1> /dev/null -v uname || { 73 | if command 1> /dev/null -v busybox; then 74 | _redirect_command 'uname' 75 | elif command 1> /dev/null -v getprop; then 76 | { 77 | uname() 78 | { 79 | if test "${1:-}" != '-m'; then ui_error 'Unsupported parameters for uname'; fi 80 | 81 | _uname_val="$(getprop 'ro.product.cpu.abi')" 82 | case "${_uname_val?}" in 83 | 'armeabi-v7a') _uname_val='armv7l' ;; 84 | 'armeabi') _uname_val='armv6l' ;; 85 | *) ;; 86 | esac 87 | 88 | printf '%s\n' "${_uname_val?}" 89 | unset _uname_val 90 | } 91 | } 92 | fi 93 | } 94 | 95 | command 1> /dev/null -v 'dirname' || { 96 | dirname() 97 | { 98 | printf '%s\n' "${1%/*}" 99 | } 100 | } 101 | 102 | command 1> /dev/null -v 'unzip' || { 103 | if command 1> /dev/null -v busybox; then 104 | _redirect_command 'unzip' 105 | else 106 | printf 1>&2 '\033[1;31m%s\033[0m\n' 'ERROR: Missing => unzip' 107 | exit 100 108 | fi 109 | } 110 | 111 | command 1> /dev/null -v 'grep' || { 112 | if command 1> /dev/null -v busybox; then _redirect_command 'grep'; fi 113 | } 114 | 115 | ### FUNCTIONS AND CODE ### 116 | 117 | # Detect whether we are in boot mode 118 | _ub_detect_bootmode() 119 | { 120 | if test -n "${BOOTMODE:-}"; then return; fi 121 | BOOTMODE=false 122 | # shellcheck disable=SC2009 123 | if pgrep -f -x 'zygote' 1> /dev/null 2>&1 || pgrep -f -x 'zygote64' 1> /dev/null 2>&1 || ps | grep 'zygote' | grep -v 'grep' 1> /dev/null || ps -A 2> /dev/null | grep 'zygote' | grep -v 'grep' 1> /dev/null; then 124 | BOOTMODE=true 125 | fi 126 | readonly BOOTMODE 127 | export BOOTMODE 128 | } 129 | 130 | _send_text_to_recovery() 131 | { 132 | if test "${BOOTMODE:?}" = 'true'; then 133 | printf '%s\n' "${1?}" 134 | return 135 | elif test -e "/proc/self/fd/${OUTFD:?}"; then 136 | printf 'ui_print %s\nui_print\n' "${1?}" >> "/proc/self/fd/${OUTFD:?}" 137 | else 138 | printf 'ui_print %s\nui_print\n' "${1?}" 1>&"${OUTFD:?}" 139 | fi 140 | } 141 | 142 | ui_error() 143 | { 144 | ERROR_CODE=79 145 | if test -n "${2:-}"; then ERROR_CODE="${2:?}"; fi 146 | _send_text_to_recovery "ERROR ${ERROR_CODE:?}: ${1:?}" 147 | printf 1>&2 '\033[1;31m%s\033[0m\n' "ERROR ${ERROR_CODE:?}: ${1:?}" 148 | abort '' 2> /dev/null || exit "${ERROR_CODE:?}" 149 | } 150 | 151 | set_perm() 152 | { 153 | local uid="${1:?}" 154 | local gid="${2:?}" 155 | local mod="${3:?}" 156 | shift 3 157 | test -n "${*}" || ui_error "Missing parameter on set_perm: $*" 158 | chown "${uid:?}:${gid:?}" "${@}" || chown "${uid:?}.${gid:?}" "${@}" || ui_error "chown failed on: $*" 159 | chmod "${mod:?}" "${@}" || ui_error "chmod failed on: $*" 160 | } 161 | 162 | package_extract_file() 163 | { 164 | unzip -opq "${ZIPFILE:?}" "${1:?}" 1> "${2:?}" || ui_error "Failed to extract the file '${1}' from this archive" 165 | if ! test -e "${2:?}"; then ui_error "Failed to extract the file '${1}' from this archive"; fi 166 | } 167 | 168 | generate_awk_random_seed() 169 | { 170 | local _seed _pid 171 | 172 | # IMPORTANT: On old versions of awk the maximum value of seed is 4294967295 (2^32 − 1); if you exceed the maximum then awk always returns the same random number (which is no longer random) 173 | 174 | if _seed="$(LC_ALL=C date 2> /dev/null -u -- '+%N')" && test -n "${_seed?}" && test "${_seed:?}" != 'N'; then 175 | echo "${_seed:?}" 176 | elif command 1> /dev/null -v tail && _pid="$(echo "${$:?}" | tail -c 5)" && LC_ALL=C date 2> /dev/null -u -- "+%-I%M%S${_pid:?}"; then # tail -c 5 => Last 4 bytes + '\n' 177 | echo 1>&2 'Seed: using unsafe seed' 178 | else 179 | return 1 180 | fi 181 | } 182 | 183 | generate_random() 184 | { 185 | local _seed 186 | 187 | if test "${RANDOM_IS_SEEDED:-false}" = 'false'; then 188 | # Seed the RANDOM variable 189 | RANDOM="${$:?}" 190 | readonly RANDOM_IS_SEEDED='true' 191 | fi 192 | 193 | # shellcheck disable=SC3028 194 | LAST_RANDOM="${RANDOM-}" 195 | 196 | if test -n "${LAST_RANDOM?}" && test "${LAST_RANDOM:?}" != "${$:?}"; then 197 | : # OK 198 | elif command 1> /dev/null -v shuf && LAST_RANDOM="$(shuf -n '1' -i '0-99999')"; then 199 | : # OK 200 | elif command 1> /dev/null -v hexdump && test -e '/dev/urandom' && LAST_RANDOM="$(hexdump -v -n '2' -e '1/2 "%u"' -- '/dev/urandom')"; then 201 | echo 'Random: using hexdump' # OK 202 | elif command 1> /dev/null -v awk && command 1> /dev/null -v date && _seed="$(generate_awk_random_seed)" && test -n "${_seed?}" && LAST_RANDOM="$(awk -v seed="${_seed:?}" -- 'BEGIN { srand(seed); print int( rand()*(99999+1) ) }')"; then 203 | echo 'Random: using awk' # OK 204 | elif test -e '/dev/urandom' && command 1> /dev/null -v tr && command 1> /dev/null -v head && LAST_RANDOM="$(tr 0< '/dev/urandom' -d -c '[:digit:]' | head -c 5 || true)" 2> /dev/null && test -n "${LAST_RANDOM?}"; then 205 | echo 'Random: using tr/head' # OK 206 | else 207 | LAST_RANDOM='' 208 | ui_error 'Unable to generate a random number' 209 | fi 210 | } 211 | 212 | _ub_detect_bootmode 213 | DELETE_TMP=0 214 | UNMOUNT_TMP=0 215 | 216 | __is_mounted() 217 | { 218 | local _mount_result 219 | 220 | if test "${TEST_INSTALL:-false}" = 'false' && command 1> /dev/null -v 'mountpoint'; then 221 | mountpoint 1> /dev/null 2>&1 "${1:?}" || return 1 222 | return 0 223 | fi 224 | 225 | { 226 | test -f '/proc/mounts' && _mount_result="$(cat /proc/mounts)" 227 | } || _mount_result="$(mount 2> /dev/null)" || ui_error '__is_mounted has failed' 228 | 229 | # IMPORTANT: Some limited shells does NOT support character classes like [[:blank:]], so avoid using them in "case" 230 | case "${_mount_result:?}" in 231 | *\ "${1:?}"\ *) return 0 ;; # Mounted 232 | *) ;; # NOT mounted 233 | esac 234 | return 1 # NOT mounted 235 | } 236 | 237 | # Workaround: Manually set a temp folder if there isn't one ready already 238 | 239 | if test -n "${TMPDIR-}" && test "${TMPDIR:?}" != '/data/local' && test -d "${TMPDIR:?}" && test -w "${TMPDIR:?}"; then 240 | : # Already ready 241 | elif test -d '/tmp'; then 242 | TMPDIR='/tmp' 243 | elif test -d '/dev' && __is_mounted '/dev'; then 244 | mkdir -p '/dev/tmp' || ui_error 'Failed to create the temp folder => /dev/tmp' 245 | set_perm 0 2000 01775 '/dev/tmp' 246 | 247 | TMPDIR='/dev/tmp' 248 | else 249 | _send_text_to_recovery 'WARNING: Creating the temp folder...' 250 | printf 1>&2 '\033[0;33m%s\033[0m\n' 'WARNING: Creating the temp folder...' 251 | mkdir -p '/tmp' || ui_error 'Failed to create the temp folder => /tmp' 252 | DELETE_TMP=1 253 | set_perm 0 0 0755 '/tmp' 254 | 255 | TMPDIR='/tmp' 256 | fi 257 | 258 | if test "${TMPDIR:?}" = '/tmp'; then 259 | __is_mounted '/tmp' || { 260 | _send_text_to_recovery 'WARNING: Mounting the temp folder...' 261 | printf 1>&2 '\033[0;33m%s\033[0m\n' 'WARNING: Mounting the temp folder...' 262 | 263 | mount -t 'tmpfs' -o 'rw' tmpfs '/tmp' || ui_error 'Failed to mount the temp folder => /tmp' 264 | UNMOUNT_TMP=1 265 | __is_mounted '/tmp' || ui_error 'The temp folder CANNOT be mounted => /tmp' 266 | set_perm 0 2000 01775 '/tmp' 267 | } 268 | fi 269 | 270 | test -w "${TMPDIR:?}" || ui_error "The temp folder is NOT writable => ${TMPDIR?}" 271 | export TMPDIR 272 | 273 | generate_random 274 | _ub_our_main_script="${TMPDIR:?}/${LAST_RANDOM:?}-customize.sh" 275 | 276 | STATUS=1 277 | 278 | package_extract_file 'customize.sh' "${_ub_our_main_script:?}" 279 | 280 | echo "Loading ${LAST_RANDOM:?}-customize.sh..." 281 | # shellcheck source=SCRIPTDIR/../../../../customize.sh 282 | command . "${_ub_our_main_script:?}" || ui_error "Failed to source '${_ub_our_main_script?}'" 283 | if test "${UNKNOWN_ERROR:-1}" != '0' && test "${STATUS?}" = '0'; then STATUS=253; fi 284 | 285 | if test -f "${_ub_our_main_script:?}"; then 286 | rm "${_ub_our_main_script:?}" || ui_error "Failed to delete '${_ub_our_main_script?}'" 287 | fi 288 | unset _ub_our_main_script 289 | 290 | if test -d '/tmp'; then 291 | if test "${UNMOUNT_TMP:?}" = '1'; then umount '/tmp' || ui_error 'Failed to unmount the temp folder => /tmp'; fi 292 | # IMPORTANT: Legacy versions of rmdir don't accept any parameter (not even --) 293 | if test "${DELETE_TMP:?}" = '1'; then rmdir '/tmp' || ui_error 'Failed to delete the temp folder => /tmp'; fi 294 | fi 295 | 296 | case "${STATUS?}" in 297 | '0') ;; # Success 298 | '250') ui_msg 'TEST mode completed' ;; 299 | '251') ui_error 'Restart the device and flash this again!' "${STATUS:?}" ;; 300 | '252') ui_error 'Restart the emulator and flash this again!' "${STATUS:?}" ;; 301 | *) ui_error "Installation script failed" "${STATUS?}" ;; # Failure 302 | esac 303 | -------------------------------------------------------------------------------- /tools/win/man/cat1/pdpmake.1: -------------------------------------------------------------------------------- 1 | PDPMAKE(1) Usage Manual PDPMAKE(1) 2 | 3 | NAME 4 | pdpmake - Public domain POSIX make 5 | 6 | SYNOPSIS 7 | pdpmake [--posix] [-ehiknpqrSst] [-C dir] [-f mkfile] [-j num_jobs] 8 | [-x pragma] [macro[:[:[:]]]=value ...] [target ...] 9 | 10 | DESCRIPTION 11 | The pdpmake utility creates or updates files following a set of rules. 12 | The created or updated files, called targets, are typically derived 13 | from other files, called prerequisites. Targets are derived according 14 | to rules describing file dependencies and listing commands to be exe- 15 | cuted. Rules may be inferred by the utility or explicitly defined in 16 | one or more makefiles. 17 | 18 | OPTIONS 19 | -C dir Change to dir before reading the makefiles or doing anything 20 | else. If multiple -C options are specified, each is interpreted 21 | relative to the previous one: '-C / -C etc' is equivalent to '-C 22 | /etc'. 23 | 24 | -e Let environment variables override macro assignments within 25 | makefiles. 26 | 27 | -f mkfile 28 | Specify a different makefile. The argument mkfile may be a path 29 | to a file, or a minus sign '-' for standard input. Multiple 30 | files may be specified and are read in that order. 31 | 32 | -h Display help information. 33 | 34 | -i Ignore non-zero exit codes returned by commands executed to re- 35 | build files. This is equivalent to using the special target .IG- 36 | NORE without prerequisites. 37 | 38 | -j num_jobs 39 | Unused, provided only for compatibility. 40 | 41 | -k Continue processing after errors are encountered, but only for 42 | targets that don't depend on the target whose creation caused 43 | the error. 44 | 45 | -n Print commands that would have been executed, but don't actually 46 | execute them unless the command is prefixed with '+'. 47 | 48 | -p Print the macro definitions and rules that result from reading 49 | the makefiles, then continue with any processing required. 50 | 51 | --posix 52 | Enable strict POSIX-compliant mode. This option must be the 53 | first given on the command line. 54 | 55 | -q Do not execute any commands, instead exit 0 if the specified 56 | targets are up to date, and 1 otherwise. 57 | 58 | -r Do not use the built-in rules. Clear the suffix list. 59 | 60 | -S Stop processing if an error is encountered. This is the default 61 | behaviour and the opposite of -k. 62 | 63 | -s Do not print the commands as they are executed. This is equiva- 64 | lent to using the special target .SILENT without prerequisites. 65 | 66 | -t Touch files instead of running the commands required to build 67 | them, but not for targets that have no commands or that are al- 68 | ready up-to-date. 69 | 70 | -x pragma 71 | Allow certain pdpmake extensions to apply in strict POSIX-com- 72 | pliant mode. For a list of supported pragmas see PRAGMAS below. 73 | Multiple -x options can be given. 74 | 75 | macro[:[:[:]]]=value 76 | Assign value to macro, overriding the value of macro in the 77 | makefile, if it exists. Macro assignments and targets may be 78 | mixed on the command line. All assignments will be processed 79 | first, then the targets. 80 | 81 | PRAGMAS 82 | macro_name 83 | Allow '-' as a valid character in macro names. 84 | 85 | target_name 86 | Allow '-' and '/' as valid characters in target names. 87 | 88 | command_comment 89 | Don't treat the '#' character as introducing a comment in com- 90 | mands or in target and inference rules. 91 | 92 | empty_suffix 93 | Permit an empty suffix in macro expansions of the form 94 | $(VAR:=.c). 95 | 96 | posix_2017 97 | Enforce the current POSIX 2017 standard rather than the future 98 | POSIX 202X. 99 | 100 | posix_202x 101 | Enforce the future POSIX 202X standard rather than the current 102 | POSIX 2017. In this case the macro_name and target_name pragmas 103 | aren't required as the future standard allows the additional 104 | characters. 105 | 106 | windows 107 | Allow target names of the form C:/path in builds for Microsoft 108 | Windows. This may also require setting target_name. 109 | 110 | EXTENDED DESCRIPTION 111 | pdpmake is a make utility following the POSIX standard: 112 | https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html 113 | 114 | The behavior of the utility should match the behavior described in the 115 | POSIX standard specification, while allowing a set of extensions for 116 | convenience. The behavior may be fine-tuned using command line options, 117 | environment variables, or special targets defined inside makefiles. 118 | 119 | By default pdpmake allows all extensions. To disable all extensions and 120 | enable strict POSIX-compliant mode, do any of the following: 121 | 122 | * Add the special target .POSIX as the first non-comment line 123 | in the first makefile to be processed. This is the standard 124 | approach for declaring a makefile to be POSIX-compliant. 125 | 126 | * Add the --posix flag as the first command line option given 127 | to pdpmake. This flag is unique to pdpmake and may not be 128 | available in other make utilities. 129 | 130 | * Set the PDPMAKE_POSIXLY_CORRECT environment variable to any 131 | value. This environment variable is unique to pdpmake and may 132 | not be available in other make utilities. 133 | 134 | While in strict POSIX-compliant mode, you may selectively enable cer- 135 | tain extensions through the use of pragmas (see PRAGMAS). To use one 136 | or more pragmas, do any of the following: 137 | 138 | * Add -x pragma as a command line option given to pdpmake. 139 | Multiple -x options can be given. This flag is unique to pdp- 140 | make and may not be available in other make utilities. 141 | 142 | * Add the special target .PRAGMA: pragma to the first makefile 143 | to be processed. Multiple pragmas can be specified. This 144 | special target is unique to pdpmake and may not be available 145 | in other make utilities. 146 | 147 | pdpmake implements a set of extensions from the future POSIX standard 148 | as well as other make utilities. The set of available extensions are: 149 | 150 | * Nested macro expansion. e.g. $(FOO$(BAR)) 151 | 152 | * Prerequisites of the .PHONY special target are always treated 153 | as being out-of-date. 154 | 155 | * More than one file can be specified on each include line. 156 | 157 | * Missing include files can be ignored by using -include file 158 | instead of include file. 159 | 160 | * Missing or out-of-date include files are rebuilt if an appro- 161 | priate rule can be found. 162 | 163 | * The $^ and $+ internal macros evaluate to all prerequisites 164 | of the current target (not just out-of-date ones, as with 165 | $?). $^ removes duplicated prerequisites from the list, $+ 166 | doesn't. 167 | 168 | * If no MAKE environment variable is provided the MAKE macro is 169 | initialised from argv[0], with a relative path converted to 170 | absolute. 171 | 172 | * The macro assignments ::=, :::=, +=, ?= and != are permitted. 173 | 174 | * Pattern macros extend the standard suffix substitution in 175 | macro expansion to allow changes to prefixes as well. 176 | 177 | * An escaped newline within a macro expansion on a command line 178 | is replaced by a space. 179 | 180 | * The CURDIR macro is set to the current directory during pro- 181 | gram start up. 182 | 183 | * The -C directory command line option changes the current 184 | working directory. 185 | 186 | * Double colon rules are allowed. 187 | 188 | * The following conditional keywords are allowed: ifdef, ifn- 189 | def, ifeq, ifneq, else, endif 190 | 191 | * Archive members can be specified using the form lib.a(mem1.o 192 | mem2.o...). 193 | 194 | * The macro assignment := is permitted. It is equivalent to ::= 195 | in POSIX. 196 | 197 | * Chained inference rules can be used when searching for the 198 | prerequisites of a target. Thus, if there are inference rules 199 | .p.q and .q.r and the file thing.p exists, make is able to 200 | deduce how to create thing.r. 201 | 202 | * The wildcards '*', '?' and '[]' can be used in the targets 203 | and prerequisites of target rules. 204 | 205 | * The '#' character on a command line or in a macro expansion 206 | doesn't indicate the start of a comment. In other locations 207 | '#' can be escaped by preceding it with a backslash. 208 | 209 | * Duplicated prerequisites are removed when the internal macro 210 | $? is expanded. 211 | 212 | * An include line with no files specified is silently ignored. 213 | At least one blank must follow the include for the line to be 214 | valid. 215 | 216 | * The shell used to process build commands isn't started with 217 | the -e option when errors aren't being ignored. 218 | 219 | * Macro definitions and targets may be mixed on the command 220 | line. The macro definitions are processed first, then the 221 | targets. 222 | 223 | * The $< and $* internal macros are given values in target 224 | rules. 225 | 226 | * When a build command receives a signal the target is removed. 227 | 228 | COPYRIGHT 229 | pdpmake is in the public domain. See https://unlicense.org 230 | 231 | Ron Yorston 08 June 2024 PDPMAKE(1) 232 | -------------------------------------------------------------------------------- /zip-content/zip-install.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # @name ZIP install 3 | # @brief It can execute a flashable ZIP directly without the need of a recovery. 4 | # @author ale5000 5 | # Get the latest version from here: https://github.com/micro5k/microg-unofficial-installer/blob/HEAD/zip-content/zip-install.sh 6 | 7 | # SPDX-FileCopyrightText: (c) 2022 ale5000 8 | # SPDX-License-Identifier: GPL-3.0-or-later 9 | # shellcheck enable=all 10 | 11 | readonly ZIPINSTALL_VERSION='1.4.1' 12 | 13 | PATH="${PATH:-/system/bin}:." 14 | umask 022 || : 15 | 16 | ### PREVENTIVE CHECKS ### 17 | 18 | command 1> /dev/null -v 'echo' || { 19 | echo || : 20 | exit 100 21 | } 22 | 23 | command 1> /dev/null -v 'test' || { 24 | echo 1>&2 'ERROR: Missing => test' 25 | exit 100 26 | } 27 | 28 | case "$(:)" in '') ;; *) 29 | echo 1>&2 'ERROR: Command substitution NOT supported by your shell' 30 | exit 100 31 | ;; 32 | esac 33 | 34 | _is_busybox_available() 35 | { 36 | if test -f './busybox'; then test -x './busybox' || chmod 0755 './busybox' || echo 1>&2 'WARNING: Chmod failed on busybox'; fi 37 | 38 | command 1> /dev/null -v 'busybox' || { 39 | echo 'false' 40 | return 41 | } 42 | 43 | PROPAGATE_BUSYBOX='true' 44 | echo 'true' 45 | } 46 | 47 | _is_head_functional() 48 | { 49 | command 1> /dev/null -v 'head' || return 1 50 | case "$(echo 2> /dev/null 'ABCD' | head 2> /dev/null -c 2 || :)" in 'AB') return 0 ;; *) ;; esac # Some versions of head are broken or incomplete 51 | return 2 52 | } 53 | 54 | _redirect_command() 55 | { 56 | eval " ${1:?}() { busybox '${1:?}' \"\${@}\"; } " || { 57 | echo 1>&2 "ERROR: Replacing ${1?} failed" 58 | exit 100 59 | } 60 | } 61 | 62 | _is_head_functional || { 63 | if "${IS_BUSYBOX_AVAILABLE:=$(_is_busybox_available || :)}"; then _redirect_command 'head'; fi 64 | } 65 | 66 | command 1> /dev/null -v 'printf' || { 67 | if "${IS_BUSYBOX_AVAILABLE:=$(_is_busybox_available || :)}"; then 68 | _redirect_command 'printf' 69 | else 70 | NO_COLOR=1 71 | 72 | # shellcheck disable=SC2329 # IGNORE: Detection bug 73 | printf() 74 | { 75 | case "${1-unset}" in 76 | '%s') 77 | _printf_backup_ifs="${IFS-unset}" 78 | if _is_head_functional; then 79 | shift && IFS='' && echo "${*}" | head -c '-1' 80 | else 81 | shift && IFS='' && echo "${*}" 82 | fi 83 | if test "${_printf_backup_ifs}" = 'unset'; then unset IFS; else IFS="${_printf_backup_ifs}"; fi 84 | unset _printf_backup_ifs 85 | ;; 86 | '%s\n') 87 | shift && for _printf_val in "${@}"; do echo "${_printf_val}"; done 88 | ;; 89 | '%s\n\n') 90 | shift && for _printf_val in "${@}"; do echo "${_printf_val}" && echo ''; done 91 | ;; 92 | '\n') echo '' ;; 93 | '\n\n') echo '' && echo '' ;; 94 | '') ;; 95 | 96 | *) 97 | echo 1>&2 'ERROR: Unsupported printf parameter' 98 | return 2 99 | ;; 100 | esac 101 | 102 | unset _printf_val || : 103 | return 0 104 | } 105 | fi 106 | } 107 | 108 | command 1> /dev/null -v 'unzip' || { 109 | if "${IS_BUSYBOX_AVAILABLE:=$(_is_busybox_available || :)}"; then 110 | _redirect_command 'unzip' 111 | else 112 | echo 1>&2 'ERROR: "unzip" is missing' 113 | exit 100 114 | fi 115 | } 116 | 117 | ### FUNCTIONS AND CODE ### 118 | 119 | ui_info_msg() 120 | { 121 | if test -n "${NO_COLOR-}"; then 122 | printf '%s\n' "${1}" 123 | elif test "${CI:-false}" = 'false'; then 124 | printf '\033[1;32m\r%s\n\033[0m\r \r' "${1}" 125 | else 126 | printf '\033[1;32m%s\033[0m\n' "${1}" 127 | fi 128 | } 129 | 130 | ui_error_msg() 131 | { 132 | if test -n "${NO_COLOR-}"; then 133 | printf 1>&2 '%s\n' "ERROR: ${1}" 134 | elif test "${CI:-false}" = 'false'; then 135 | printf 1>&2 '\033[1;31m\r%s\n\033[0m\r \r' "ERROR: ${1}" 136 | else 137 | printf 1>&2 '\033[1;31m%s\033[0m\n' "ERROR: ${1}" 138 | fi 139 | } 140 | 141 | is_root() 142 | { 143 | if command 1> /dev/null -v 'whoami'; then 144 | case "$(whoami || :)" in 'root') return 0 ;; *) ;; esac 145 | else 146 | command 1> /dev/null -v 'grep' || { 147 | if "${IS_BUSYBOX_AVAILABLE:=$(_is_busybox_available || :)}"; then 148 | _redirect_command 'grep' 149 | else 150 | echo 1>&2 'ERROR: "grep" is missing' 151 | exit 100 152 | fi 153 | } 154 | 155 | if id | grep -m '1' -q -e "uid=0[ (]"; then 156 | return 0 157 | fi 158 | fi 159 | 160 | return 1 161 | } 162 | 163 | if test "${#}" -gt 0; then 164 | for _param in "${@}"; do 165 | shift || { 166 | ui_error_msg 'shift failed' 167 | exit 6 168 | } 169 | # Skip empty parameters or parameters that may get passed due to buggy su implementation 170 | if test -z "${_param?}" || test "${_param:?}" = '--' || test "${_param:?}" = '[su]zip-install.sh'; then continue; fi 171 | 172 | test -e "${_param:?}" || { 173 | ui_error_msg "ZIP file doesn't exist => '${_param:-}'" 174 | exit 7 175 | } 176 | 177 | _param_copy="${_param:?}" 178 | _param="$(readlink 2> /dev/null -f "${_param_copy:?}")" || _param="$(realpath "${_param_copy:?}")" || { 179 | ui_error_msg "Canonicalization failed => '${_param_copy:-}'" 180 | exit 8 181 | } 182 | 183 | set -- "${@}" "${_param:?}" || { 184 | ui_error_msg 'set failed' 185 | exit 6 186 | } 187 | done 188 | unset _param _param_copy 189 | fi 190 | 191 | if test "${#}" -eq 0; then 192 | ui_error_msg 'You must specify the ZIP file to install' 193 | exit 5 194 | fi 195 | 196 | if ! is_root; then 197 | if test "${AUTO_ELEVATED:-false}" = 'false'; then 198 | printf '%s\n' 'Auto-rooting attempt...' 199 | 200 | # First verify that "su" is working (user 0 is root) 201 | su 0 sh -c 'command' '[su]verification' || { 202 | _status="${?}" # Usually it return 1 or 255 when root is present but disabled 203 | ui_error_msg 'Auto-rooting failed, you must execute this as root!!!' 204 | exit "${_status:-2}" 205 | } 206 | 207 | ZIP_INSTALL_SCRIPT="$(readlink 2> /dev/null -f "${0:?}")" || ZIP_INSTALL_SCRIPT="$(realpath "${0:?}")" || { 208 | ui_error_msg 'Unable to find myself' 209 | exit 3 210 | } 211 | exec su 0 sh -c "AUTO_ELEVATED=true DEBUG_LOG='${DEBUG_LOG-}' TMPDIR='${TMPDIR-}' LD_LIBRARY_PATH='${LD_LIBRARY_PATH-}' DRY_RUN='${DRY_RUN-}' KEY_TEST_ONLY='${KEY_TEST_ONLY-}' BYPASS_LOCK_CHECK='${BYPASS_LOCK_CHECK-}' INPUT_TYPE='${INPUT_TYPE-}' FORCE_HW_KEYS='${FORCE_HW_KEYS-}' CI='${CI:-false}' sh -- '${ZIP_INSTALL_SCRIPT:?}' \"\${@}\"" '[su]zip-install.sh' "${@}" || ui_error_msg 'failed: exec' 212 | exit "${?}" 213 | fi 214 | 215 | ui_error_msg 'You must execute this as root!!!' 216 | exit 4 217 | fi 218 | export LD_LIBRARY_PATH 219 | 220 | test -n "${DEBUG_LOG-unset}" || unset DEBUG_LOG 221 | test -n "${TMPDIR-unset}" || unset TMPDIR 222 | test -n "${LD_LIBRARY_PATH-unset}" || unset LD_LIBRARY_PATH 223 | 224 | test -n "${DRY_RUN-unset}" || unset DRY_RUN 225 | test -n "${KEY_TEST_ONLY-unset}" || unset KEY_TEST_ONLY 226 | test -n "${BYPASS_LOCK_CHECK-unset}" || unset BYPASS_LOCK_CHECK 227 | 228 | test -n "${INPUT_TYPE-unset}" || unset INPUT_TYPE 229 | test -n "${FORCE_HW_KEYS-unset}" || unset FORCE_HW_KEYS 230 | 231 | propagate_busybox() 232 | { 233 | mkdir -p "${TMPDIR:?}/bb-applets" || { 234 | ui_error_msg 'Failed to create a temp folder for busybox applets' 235 | return 236 | } 237 | busybox 2> /dev/null --install -s "${TMPDIR:?}/bb-applets" || { 238 | ui_error_msg 'Failed to propagate busybox' 239 | return 240 | } 241 | PATH="${PATH?}:${TMPDIR:?}/bb-applets" 242 | export PATH 243 | } 244 | 245 | unset SCRIPT_NAME 246 | _clean_at_exit() 247 | { 248 | if test -n "${SCRIPT_NAME-}" && test -f "${SCRIPT_NAME:?}"; then 249 | # Legacy versions of rm don't accept any parameter (except -r and -R) 250 | rm "${SCRIPT_NAME:?}" || : 251 | fi 252 | if test -n "${UPD_SCRIPT_NAME-}" && test -f "${UPD_SCRIPT_NAME:?}"; then 253 | rm "${UPD_SCRIPT_NAME:?}" || : 254 | fi 255 | if test -n "${TMPDIR-}" && test -d "${TMPDIR:?}/bb-applets"; then 256 | rm -r "${TMPDIR:?}/bb-applets" || : 257 | fi 258 | 259 | unset SCRIPT_NAME 260 | if test "${TMPDIR:-}" = '/dev/tmp'; then 261 | if test -d "${TMPDIR:?}"; then 262 | # Legacy versions of rmdir don't accept any parameter (not even --) 263 | rmdir "${TMPDIR:?}" 2> /dev/null || : 264 | fi 265 | unset TMPDIR 266 | fi 267 | } 268 | trap ' _clean_at_exit' 0 2 3 6 15 269 | 270 | if test -n "${TMPDIR-}" && test "${TMPDIR:?}" != '/data/local/tmp' && test -w "${TMPDIR:?}"; then 271 | : # Already ready 272 | elif test -w '/tmp'; then 273 | TMPDIR='/tmp' 274 | elif test -w '/postinstall/tmp'; then 275 | TMPDIR='/postinstall/tmp' 276 | elif test -d '/dev'; then 277 | mkdir -p '/dev/tmp' || { 278 | ui_error_msg 'Failed to create a temp folder' 279 | exit 9 280 | } 281 | chmod 01775 '/dev/tmp' || { 282 | ui_error_msg "chmod failed on '/dev/tmp'" 283 | rmdir 2> /dev/null '/dev/tmp' || : 284 | exit 10 285 | } 286 | TMPDIR='/dev/tmp' 287 | else 288 | unset TMPDIR 289 | fi 290 | 291 | if test -z "${TMPDIR-}" || test ! -w "${TMPDIR:?}"; then 292 | ui_error_msg 'Unable to find a temp folder' 293 | exit 11 294 | fi 295 | export TMPDIR 296 | 297 | test "${PROPAGATE_BUSYBOX:-false}" = 'false' || propagate_busybox 298 | 299 | SCRIPT_NAME="${TMPDIR:?}/update-binary" || exit 12 300 | UPD_SCRIPT_NAME="${TMPDIR:?}/updater-script" || exit 12 301 | ZIPFILE="${1:?}" 302 | 303 | unzip -p -qq "${ZIPFILE:?}" 'META-INF/com/google/android/update-binary' 1> "${SCRIPT_NAME:?}" || { 304 | ui_error_msg "Failed to extract update-binary from => '${ZIPFILE:-}'" 305 | exit 13 306 | } 307 | test -s "${SCRIPT_NAME:?}" || { 308 | ui_error_msg "Failed to extract update-binary (2) from => '${ZIPFILE:-}'" 309 | exit 14 310 | } 311 | 312 | unzip -p -qq "${ZIPFILE:?}" 'META-INF/com/google/android/updater-script' 1> "${UPD_SCRIPT_NAME:?}" || : # Not strictly needed 313 | 314 | STATUS=0 315 | if ! _is_head_functional || test '#!' = "$(head -c 2 -- "${SCRIPT_NAME:?}" || :)"; then 316 | printf '%s\n' 'Executing script...' 317 | 318 | # Use STDERR (2) for recovery messages to avoid possible problems with subshells intercepting output 319 | sh -- "${SCRIPT_NAME:?}" 3 2 "${ZIPFILE:?}" 'zip-install' "${ZIPINSTALL_VERSION:?}" || STATUS="${?}" 320 | else 321 | printf '%s\n' 'Executing binary...' 322 | 323 | # Legacy versions of chmod don't support +x and -- 324 | chmod 0755 "${SCRIPT_NAME:?}" || { 325 | ui_error_msg "chmod failed on '${SCRIPT_NAME:?}'" 326 | exit 15 327 | } 328 | "${SCRIPT_NAME:?}" 3 2 "${ZIPFILE:?}" 'zip-install' "${ZIPINSTALL_VERSION:?}" || STATUS="${?}" 329 | fi 330 | 331 | _clean_at_exit 332 | trap - 0 2 3 6 15 || : # Already cleaned, so unset traps 333 | 334 | case "${STATUS?}" in 335 | '0') 336 | ui_info_msg 'The ZIP installation has been successfully completed. Please restart your device now!!!' 337 | exit 0 338 | ;; 339 | '251') ui_info_msg 'To continue, restart the device and flash this again!!!' ;; 340 | '252') ui_info_msg 'To continue, restart the emulator and flash this again!!!' ;; 341 | *) ui_error_msg "ZIP installation failed with error ${STATUS?}" ;; 342 | esac 343 | 344 | exit "${STATUS:-254}" 345 | -------------------------------------------------------------------------------- /.github/workflows/scripts-testing.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # SPDX-FileCopyrightText: NONE 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: "Scripts testing" 6 | permissions: {} 7 | on: 8 | push: 9 | paths: 10 | - "includes/**" 11 | - "tools/*.sh" 12 | - "cmdline.sh" 13 | pull_request: 14 | paths: 15 | - "includes/**" 16 | - "tools/*.sh" 17 | - "cmdline.sh" 18 | schedule: 19 | # At 04:00 AM, every 6 days (UTC) 20 | - cron: "0 4 */6 * *" 21 | workflow_dispatch: 22 | 23 | jobs: 24 | base-job: 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | os: [ubuntu-latest, windows-latest, macos-latest] 29 | name: "${{ matrix.os }}" 30 | runs-on: "${{ matrix.os }}" 31 | timeout-minutes: 20 32 | env: 33 | cache-key: "shells" 34 | 35 | permissions: 36 | actions: write # Needed to delete a cache 37 | 38 | steps: 39 | - name: "Checkout sources" 40 | uses: actions/checkout@v6 41 | - name: "Prepare cache" 42 | id: cache-action 43 | if: "${{ runner.os == 'Linux' }}" 44 | uses: actions/cache@v5 45 | with: 46 | path: "cache/shells" 47 | key: "${{ env.cache-key }}-${{ runner.os }}" 48 | - name: "Prepare shells" 49 | id: prepare-shells 50 | if: "${{ steps.cache-action.outcome != 'skipped' }}" 51 | shell: bash 52 | run: | 53 | # Preparing shells... 54 | CACHE_IS_OUTDATED='false' 55 | # shellcheck disable=SC2016 # Intended: Expressions don't expand in single quotes 56 | { 57 | readonly current_os='${{ runner.os }}' 58 | readonly shells_dir='${{ github.workspace }}/cache/shells' 59 | } 60 | prepare_shell() 61 | { 62 | if test ! -s "${shells_dir:?}/${1:?}.${2:?}"; then 63 | printf '%s\n' "Downloading '${1?}'..." 64 | if wget -q -O "${shells_dir:?}/${1:?}.${2:?}" -- "${3:?}" && test -s "${shells_dir:?}/${1:?}.${2:?}"; then 65 | : # OK 66 | else 67 | rm -f -- "${shells_dir:?}/${1:?}.${2:?}" || : 68 | return 1 69 | fi 70 | CACHE_IS_OUTDATED='true' 71 | fi 72 | mkdir -p -- "${shells_dir:?}/extracted/${1:?}" || return "${?}" 73 | if test "${2:?}" = 'bin'; then 74 | cp -f -p -- "${shells_dir:?}/${1:?}.${2:?}" "${shells_dir:?}/extracted/${1:?}/${1:?}" || return "${?}" 75 | chmod +x -- "${shells_dir:?}/extracted/${1:?}/${1:?}" || return "${?}" 76 | else 77 | tar -x -f "${shells_dir:?}/${1:?}.${2:?}" -C "${shells_dir:?}/extracted/${1:?}" || return "${?}" 78 | fi 79 | printf '%s\n' "${shells_dir:?}/extracted/${1:?}" 1>> "${shells_dir:?}/extracted/list.dat" || return "${?}" 80 | } 81 | if command 1> /dev/null -v 'sudo' && legacy_bb="$(command -v 'busybox')" && legacy_bb_dir="$(dirname "${legacy_bb:?}")"; then 82 | sudo mv -f -- "${legacy_bb:?}" "${legacy_bb_dir:?}/busybox-preinstalled" || exit "${?}" 83 | fi 84 | mkdir -p -- "${shells_dir:?}/extracted" || exit "${?}" 85 | rm -f -- "${shells_dir:?}/extracted/list.dat" || exit "${?}" 86 | touch -- "${shells_dir:?}/extracted/list.dat" || exit "${?}" 87 | if test "${current_os:?}" = 'Linux'; then 88 | prepare_shell 'busybox' 'bin' 'https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox' 89 | prepare_shell 'busybox-x86' 'bin' 'https://busybox.net/downloads/binaries/1.35.0-i686-linux-musl/busybox' 90 | prepare_shell 'busybox-x86-legacy' 'bin' 'https://busybox.net/downloads/binaries/1.30.0-i686/busybox' 91 | prepare_shell 'bosh' 'tar.xz' 'http://fuz.su/pub/schilytools/bin/schily-2024-03-21-x86_64-linux-gcc.tar.xz' 92 | fi 93 | printf 'cache_is_outdated=%s\n' "${CACHE_IS_OUTDATED:?}" >> "${GITHUB_OUTPUT?}" 94 | - name: "Delete outdated cache" 95 | if: "${{ steps.cache-action.outputs.cache-hit && steps.prepare-shells.outputs.cache_is_outdated == 'true' }}" 96 | shell: bash 97 | run: | 98 | # Deleting outdated cache... 99 | gh extension install 'actions/gh-actions-cache' || exit "${?}" 100 | gh actions-cache delete '${{ env.cache-key }}-${{ runner.os }}' --confirm || exit "${?}" 101 | printf '%s\n' 'Cache deleted.' 102 | env: 103 | GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 104 | - name: "Test scripts" 105 | shell: bash 106 | timeout-minutes: 10 107 | run: | 108 | # Testing scripts... 109 | EXIT_CODE='0' 110 | SH_IS_BASH='false' 111 | ORIGINAL_KSH="$(command -v 'ksh' || :)" 112 | # shellcheck disable=SC2016 # Intended: Expressions don't expand in single quotes 113 | { 114 | readonly current_os='${{ runner.os }}' 115 | readonly workspace_dir='${{ github.workspace }}' 116 | readonly shells_dir='${{ github.workspace }}/cache/shells' 117 | } 118 | if test -f "${shells_dir:?}/extracted/list.dat" && dl_shells="$(tr -- '\n' ':' 0< "${shells_dir:?}/extracted/list.dat")" && dl_shells="${dl_shells%':'}" && test -n "${dl_shells?}"; then 119 | PATH="${PATH:-/usr/bin}:${dl_shells:?}" || exit "${?}" 120 | fi 121 | if test "${current_os:?}" = 'Linux'; then PATH="${PATH:-/usr/bin}:${workspace_dir:?}/cache/shells/extracted/bosh/opt/schily/bin" || exit "${?}"; fi 122 | if diff 1> /dev/null 2>&1 -- "$(command -v 'sh' || :)" "$(command -v 'bash' || :)"; then SH_IS_BASH='true'; fi 123 | if test "${current_os:?}" = 'Linux'; then 124 | sudo DEBIAN_FRONTEND='noninteractive' apt-get -y -qq --no-install-recommends --no-upgrade install 'mksh' 'yash' 'posh' 1> /dev/null 2>&1 || exit "${?}" 125 | elif test "${current_os:?}" = 'macOS'; then 126 | brew 2> /dev/null update --quiet || exit "${?}" 127 | brew 1> /dev/null install --quiet 'mksh' 'oksh' 'ksh93' 'yash' || exit "${?}" 128 | brew 1> /dev/null install --quiet 'oils-for-unix' || exit "${?}" 129 | else 130 | choco 1> /dev/null install 'busybox' -y --no-progress 131 | #choco install 'schily-cdrtools' --pre -y --no-progress 132 | fi 133 | # 134 | resolve_base() 135 | { 136 | local _rb_shell 137 | _rb_shell="$(command -v "${1:?}")" || return "${?}" 138 | _rb_shell="$(realpath "${_rb_shell:?}")" || return "${?}" 139 | basename "${_rb_shell:?}" || return "${?}" 140 | } 141 | not_already_excuted() 142 | { 143 | local _shell 144 | _shell="$(realpath "${1:?}")" || return 2 145 | case "${EXECUTED_LIST?}|" in 146 | *"|${_shell:?} ${2?}|"*) return 1 ;; # Already executed 147 | *) ;; 148 | esac 149 | EXECUTED_LIST="${EXECUTED_LIST?}|${_shell:?} ${2?}" 150 | return 0 # NOT already executed 151 | } 152 | skip() 153 | { 154 | local _s_shell 155 | _s_shell='' 156 | if test "${SH_IS_BASH:?}" = 'true'; then 157 | case "${2:?}" in 158 | bash) return 0 ;; # Skip 159 | sh) _s_shell='bash' ;; # Evaluate as bash 160 | *) ;; 161 | esac 162 | fi 163 | if test -n "${_s_shell?}"; then 164 | : 165 | elif test "${2:?}" = 'osh' || test "${2:?}" = 'bosh'; then 166 | _s_shell="${2:?}" 167 | else 168 | _s_shell="$(resolve_base "${2:?}")" || _s_shell="${2:?}" 169 | fi 170 | if test "${1:?}" = 'cmdline.sh'; then 171 | case "${_s_shell?}" in 172 | 'obosh') return 0 ;; # Skip 173 | 'busybox'*) if test "${3?}" = 'hush'; then return 0; fi ;; # Skip if hush 174 | *) ;; 175 | esac 176 | else 177 | case "${_s_shell?}" in 178 | 'obosh') return 0 ;; # Skip 179 | *) ;; 180 | esac 181 | fi 182 | return 1 # Execute 183 | } 184 | set_applet() 185 | { 186 | case "${1:?}" in 187 | 'busybox'*) 188 | if test "${CURRENT_SHELL:-none}" != "${2:?}"; then 189 | CURRENT_APPLET='' 190 | CURRENT_SHELL="${2:?}" 191 | fi 192 | case "${CURRENT_APPLET?}" in 193 | ash) CURRENT_APPLET='hush' ;; 194 | *) CURRENT_APPLET='ash' ;; 195 | esac 196 | ;; 197 | 'osh' | 'ysh') 198 | CURRENT_APPLET="${1:?}" 199 | CURRENT_SHELL="${2:?}" 200 | ;; 201 | *) 202 | CURRENT_APPLET='' 203 | CURRENT_SHELL='' 204 | ;; 205 | esac 206 | } 207 | test_on_all_shells() 208 | { 209 | local _shell _shell_cmd _status 210 | EXECUTED_LIST='' 211 | for _shell in sh dash bash busybox busybox-x86 busybox-x86 busybox-x86-legacy busybox-x86-legacy ash hush mksh pdksh oksh ksh88 ksh93 ksh zsh yash posh osh bosh pbosh obosh; do 212 | if test "${_shell:?}" = 'ksh' && test -n "${ORIGINAL_KSH?}"; then _shell="${ORIGINAL_KSH:?}"; fi 213 | if ! _shell_cmd="$(command -v "${_shell:?}")"; then continue; fi 214 | set_applet "${_shell:?}" "${_shell_cmd:?}" 215 | if skip "${1:?}" "${_shell:?}" "${CURRENT_APPLET?}" || ! not_already_excuted "${_shell_cmd:?}" "${CURRENT_APPLET?}"; then continue; fi 216 | printf 'SHELL: %s - SCRIPT: %s\n\n' "${_shell_cmd:?}" "${1:?}" 217 | _status='0' 218 | case "${_shell:?}" in 219 | 'busybox'*) "${_shell_cmd:?}" "${CURRENT_APPLET:?}" "${workspace_dir:?}/${1:?}" ${2-} || _status="${?}" ;; 220 | *) "${_shell_cmd:?}" "${workspace_dir:?}/${1:?}" ${2-} || _status="${?}" ;; 221 | esac 222 | test "${_status:?}" = 0 || EXIT_CODE="${_status:?}" 223 | printf '\nRETURN CODE: %s\n\n' "${_status:?}" 224 | done 225 | unset EXECUTED_LIST CURRENT_SHELL CURRENT_APPLET 226 | } 227 | list_scripts() 228 | { 229 | printf '%s|%s\n' 'tools/bits-info.sh' '-i' 230 | printf '%s\n' 'cmdline.sh' 231 | } 232 | main() 233 | { 234 | local backup_ifs _script 235 | export ONLY_FOR_TESTING='true' 236 | backup_ifs="${IFS-}" 237 | IFS=$'\n' 238 | set -- $(list_scripts) || exit "${?}" 239 | IFS="${backup_ifs}" 240 | for _script in "${@}"; do 241 | test_on_all_shells "$(printf '%s\n' "${_script:?}" | cut -d '|' -f '1' || :)" "$(printf '%s\n' "${_script:?}" | cut -d '|' -f '2-' -s || :)" 242 | printf '%s\n' "---" 243 | done 244 | } 245 | main 246 | exit "${EXIT_CODE:?}" 247 | - name: "Clean extracted files" 248 | if: "${{ always() && steps.cache-action.outcome != 'skipped' }}" 249 | shell: bash 250 | run: | 251 | # Cleaning extracted files... 252 | readonly shells_dir='${{ github.workspace }}/cache/shells' 253 | rm -f -r -- "${shells_dir:?}/extracted" || exit $? 254 | --------------------------------------------------------------------------------