mirror of https://github.com/topjohnwu/Magisk
Compare commits
221 Commits
Author | SHA1 | Date |
---|---|---|
topjohnwu | 6cf00130f4 | |
topjohnwu | 6c27ba6b88 | |
vvb2060 | dd3b9980e7 | |
vvb2060 | 02e189a029 | |
topjohnwu | 72b8d12ee4 | |
topjohnwu | eed03080c1 | |
LoveSy | 090cb4b0f9 | |
topjohnwu | 6f2c76b898 | |
topjohnwu | f61827cbec | |
topjohnwu | 3f2264f2c7 | |
topjohnwu | c1cadf4bdc | |
Rodrigo Martínez | 0e56991369 | |
LoveSy | 4dc1c59040 | |
topjohnwu | 33b7b8b297 | |
topjohnwu | e6af5ed460 | |
topjohnwu | b678afa4b6 | |
WINZORT | 4bac2df4e7 | |
igor | 50416eee09 | |
igor | 73cf501d33 | |
Hen_Ry | d2b7907bed | |
topjohnwu | 99d5dd5ea8 | |
cloudchamb3r | 5fdb841fa8 | |
topjohnwu | 7c88484d64 | |
topjohnwu | b22b6a4204 | |
topjohnwu | 2a3d34c812 | |
topjohnwu | c50ee722a1 | |
topjohnwu | ffc1e38e48 | |
topjohnwu | 6219d5fcbf | |
topjohnwu | 2e4440b702 | |
topjohnwu | 0d9ec0931b | |
vvb2060 | 60e8415369 | |
LoveSy | 652a26d5d9 | |
topjohnwu | f57839379a | |
LoveSy | 36bd00a046 | |
topjohnwu | fb5ee86615 | |
topjohnwu | 30bf5c8448 | |
topjohnwu | 2051836a73 | |
topjohnwu | 2cb0af1ff3 | |
topjohnwu | a1b6568226 | |
topjohnwu | 1eddbfd72c | |
topjohnwu | 21ed095601 | |
Js0n | 000a2e4d59 | |
Js0n | 7abe635de9 | |
topjohnwu | 9a008c17ba | |
topjohnwu | 08dbf728a4 | |
topjohnwu | 4670f762d3 | |
topjohnwu | efa49567fa | |
topjohnwu | 0ffc4527a7 | |
topjohnwu | dd9d43be96 | |
topjohnwu | 865fca71a5 | |
topjohnwu | 6b4baa3bcd | |
topjohnwu | a9ee2d7d18 | |
topjohnwu | d654b9cb97 | |
LoveSy | 4d2921e742 | |
vvb2060 | ecc74d45d1 | |
vvb2060 | 5de597f079 | |
LoveSy | 156b0e67ca | |
vvb2060 | 10069215f4 | |
LoveSy | 92b305a389 | |
topjohnwu | d20b30c771 | |
topjohnwu | 83209b21ff | |
topjohnwu | 81658d45f7 | |
topjohnwu | c951b208a1 | |
topjohnwu | 050a073771 | |
topjohnwu | 21d374214f | |
LoveSy | 19ea25a9d0 | |
topjohnwu | dbf6e40dfe | |
topjohnwu | d56f4fbc90 | |
topjohnwu | 73c3d741a7 | |
pndwal | 2b5fc75127 | |
osm0sis | 991802ab82 | |
WindowsFan9600 | 7f6b5305ba | |
canyie | 825c6c4316 | |
canyie | f00408c793 | |
topjohnwu | a6ff3672af | |
LoveSy | 2290ddeb89 | |
topjohnwu | 74af79ad03 | |
LoveSy | b6c24a3a8a | |
LoveSy | a8c2ae223a | |
topjohnwu | 953d44302c | |
topjohnwu | 24e46a5971 | |
topjohnwu | b1297c4192 | |
topjohnwu | 9ae328fd84 | |
topjohnwu | 625a1d6f44 | |
topjohnwu | 987e5f5413 | |
topjohnwu | 715284b70d | |
LoveSy | 62fc7868ac | |
topjohnwu | 1a70796339 | |
topjohnwu | af6965eefa | |
topjohnwu | 8f7d2e38f7 | |
topjohnwu | be433fa667 | |
topjohnwu | 0ccd6e7381 | |
topjohnwu | 907bbbda41 | |
topjohnwu | 4393bc077d | |
topjohnwu | 365b373480 | |
topjohnwu | 47e6dd286d | |
topjohnwu | 0dbaf52566 | |
topjohnwu | 66f49dfab5 | |
topjohnwu | f8967e9274 | |
topjohnwu | a4f008fde5 | |
topjohnwu | e9980c778b | |
topjohnwu | 06b6fb0c33 | |
topjohnwu | 38cb3d4105 | |
topjohnwu | db99caf258 | |
topjohnwu | 39dbffadfe | |
topjohnwu | b7505c3c9c | |
topjohnwu | 3185e5a7ca | |
topjohnwu | e0cbe28711 | |
topjohnwu | 66cee19cea | |
topjohnwu | 2ec29ade79 | |
topjohnwu | c865d4e187 | |
topjohnwu | a42a0a53ce | |
topjohnwu | 6d79de7d71 | |
topjohnwu | 7e9abe6e90 | |
残页 | 4d5510be4f | |
topjohnwu | b04e1394c0 | |
topjohnwu | 2aa923191e | |
topjohnwu | 4bf1c74164 | |
topjohnwu | 472c7878b2 | |
topjohnwu | 38ad871e33 | |
topjohnwu | c5d34670c4 | |
topjohnwu | 154121f3dd | |
topjohnwu | 3d91a561fe | |
topjohnwu | 2c6adbc69b | |
topjohnwu | 5280982363 | |
topjohnwu | 18c45ae289 | |
LoveSy | 41fbd2a7be | |
LoveSy | 5e45884af4 | |
topjohnwu | d78ee171bc | |
LoveSy | 356ee1febd | |
LoveSy | cc044ccc4c | |
LoveSy | 9c638cc463 | |
topjohnwu | df786eb2b6 | |
topjohnwu | 8e7186eebb | |
topjohnwu | 74b7b84561 | |
topjohnwu | 308c9999fa | |
topjohnwu | 930bb8687f | |
topjohnwu | f2c4288d2d | |
topjohnwu | b44141ae39 | |
kam821 | 86e0020964 | |
残页 | 94d3daeadf | |
LoveSy | 79334b7702 | |
LoveSy | df66458db6 | |
LoveSy | 97705704e2 | |
topjohnwu | 1206179580 | |
topjohnwu | a0b8aa4da6 | |
topjohnwu | 65207f96c8 | |
Abhishek Girish | 062e498bdd | |
topjohnwu | 1057cb3e3c | |
topjohnwu | 2dd23b2518 | |
RafaeloxMC | 8cab12998c | |
topjohnwu | 48b1c26dc8 | |
topjohnwu | f1e0bc3e4a | |
topjohnwu | 38527cd58f | |
LoveSy | e94d65b4b2 | |
LoveSy | 27ece3c7df | |
LoveSy | 06687abffc | |
vvb2060 | deedb462a0 | |
igor | c48962bdf7 | |
Wang Han | 1ef3f6e13b | |
topjohnwu | 83a34a9004 | |
topjohnwu | e30bda6c8d | |
vvb2060 | 00e9d76a5a | |
LoveSy | 6cda6c2fae | |
VD $ VD171 @ Priv8 | 6dfda6dc39 | |
LoveSy | f41994cb52 | |
topjohnwu | a003336497 | |
LoveSy | 401090d6fe | |
LoveSy | 90dcc1cd30 | |
LoveSy | 2ac464b186 | |
LoveSy | 8b7fae278b | |
topjohnwu | d73c2daf6d | |
topjohnwu | ca25935de3 | |
LoveSy | d7750b7220 | |
LoveSy | 98861f0b5a | |
topjohnwu | e35925d520 | |
Kieron Quinn | 685a2d2101 | |
LoveSy | f7e471616d | |
残页 | c013a349af | |
topjohnwu | 61ea59a27b | |
VD $ VD171 @ Priv8 | e55f338367 | |
VD $ VD171 @ Priv8 | 1425cf4105 | |
topjohnwu | b493a985b0 | |
canyie | 1fe9ede940 | |
LoveSy | 1fd49e4987 | |
LoveSy | d49b02b274 | |
LoveSy | d47e70cfaa | |
topjohnwu | 40cb031af5 | |
topjohnwu | 1dcf325547 | |
LoveSy | 4e99997013 | |
LoveSy | 334554697d | |
LoveSy | e77cbd0c15 | |
topjohnwu | 46ba008b9d | |
LoveSy | 58aded31c2 | |
LoveSy | 6f6b0ade06 | |
topjohnwu | d9b67a207b | |
topjohnwu | c7083659aa | |
topjohnwu | a6d1803105 | |
Re*Index. (ot_inc) | 66eef75673 | |
Alessandro Sangiorgi | 367f5f7b44 | |
topjohnwu | 0edcb03c45 | |
canyie | 63eef153de | |
canyie | 68442f38ac | |
topjohnwu | 8d5b9e5329 | |
topjohnwu | 6c0966b795 | |
topjohnwu | 7c2e93d266 | |
topjohnwu | 1ff7b9055f | |
topjohnwu | 49f241b77c | |
topjohnwu | cfb20b0f86 | |
topjohnwu | 6d6f14fcb3 | |
topjohnwu | 977c981265 | |
topjohnwu | ef48abf19d | |
topjohnwu | 65c18f9c09 | |
残页 | ecb31eed40 | |
topjohnwu | a80cadf587 | |
LoveSy | fce1bf2365 | |
LoveSy | cbc6d40b2c | |
LoveSy | 9fbd079560 | |
LoveSy | 42eb928054 | |
topjohnwu | 577483fde1 | |
topjohnwu | aa6c7c15cc |
|
@ -0,0 +1,44 @@
|
|||
name: Magisk Setup
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Set up sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ runner.os }}-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
max-size: 10000M
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
- name: Cache build cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-build-cache-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-build-cache-
|
||||
|
||||
- name: Set up NDK
|
||||
run: python build.py -v ndk
|
||||
shell: bash
|
|
@ -17,12 +17,12 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
name: Build on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build Magisk artifacts
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SCCACHE_DIRECT: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-13]
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
|
@ -30,99 +30,125 @@ jobs:
|
|||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Set up sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ runner.os }}-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
max-size: 10000M
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
- name: Cache build cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-build-cache-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-build-cache-
|
||||
|
||||
- name: Set up NDK
|
||||
run: python build.py -v ndk
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build release
|
||||
run: |
|
||||
python build.py -vr all
|
||||
run: ./build.py -vr all
|
||||
|
||||
- name: Build debug
|
||||
run: |
|
||||
python build.py -v all
|
||||
run: ./build.py -v all
|
||||
|
||||
- name: Stop gradle daemon
|
||||
run: ./gradlew --stop
|
||||
|
||||
# Only upload artifacts built on Linux
|
||||
- name: Upload build artifact
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
compression-level: 9
|
||||
|
||||
- name: Upload mapping and native debug symbols
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}-symbols
|
||||
path: app/build/outputs
|
||||
compression-level: 9
|
||||
|
||||
test-build:
|
||||
name: Test building on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
SCCACHE_DIRECT: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-14]
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build debug
|
||||
run: python build.py -v all
|
||||
|
||||
- name: Stop gradle daemon
|
||||
run: ./gradlew --stop
|
||||
|
||||
test:
|
||||
name: Test on ${{ matrix.api }}
|
||||
runs-on: macos-13
|
||||
name: Test x86_64 on API ${{ matrix.api }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
api: [23, 26, 28, 29, 34]
|
||||
api: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
|
||||
- name: AVD test
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
brew install coreutils bash
|
||||
scripts/avd_test.sh ${{ matrix.api }}
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: AVD test
|
||||
run: scripts/avd_test.sh ${{ matrix.api }}
|
||||
|
||||
test-32:
|
||||
name: Test x86 on API ${{ matrix.api }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
api: [23, 24, 25, 26, 27, 28, 29, 30]
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: AVD test
|
||||
env:
|
||||
FORCE_32_BIT: 1
|
||||
run: scripts/avd_test.sh ${{ matrix.api }}
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
[submodule "zlib"]
|
||||
path = native/src/external/zlib
|
||||
url = https://android.googlesource.com/platform/external/zlib
|
||||
[submodule "parallel-hashmap"]
|
||||
path = native/src/external/parallel-hashmap
|
||||
url = https://github.com/greg7mdp/parallel-hashmap.git
|
||||
[submodule "zopfli"]
|
||||
path = native/src/external/zopfli
|
||||
url = https://github.com/google/zopfli.git
|
||||
|
@ -37,6 +34,9 @@
|
|||
[submodule "system_properties"]
|
||||
path = native/src/external/system_properties
|
||||
url = https://github.com/topjohnwu/system_properties.git
|
||||
[submodule "crt0"]
|
||||
path = native/src/external/crt0
|
||||
url = https://github.com/topjohnwu/crt0.git
|
||||
[submodule "termux-elf-cleaner"]
|
||||
path = tools/termux-elf-cleaner
|
||||
url = https://github.com/termux/termux-elf-cleaner.git
|
||||
|
|
|
@ -18,8 +18,8 @@ Some highlight features:
|
|||
|
||||
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
||||
|
||||
[![](https://img.shields.io/badge/Magisk-v26.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.3)
|
||||
[![](https://img.shields.io/badge/Magisk%20Beta-v26.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.3)
|
||||
[![](https://img.shields.io/badge/Magisk-v27.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[![](https://img.shields.io/badge/Magisk%20Beta-v27.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
||||
[![](https://img.shields.io/badge/Magisk-Debug-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
||||
|
||||
|
|
|
@ -70,17 +70,17 @@ configurations.all {
|
|||
dependencies {
|
||||
implementation(project(":app:shared"))
|
||||
|
||||
implementation("com.github.topjohnwu:jtar:1.0.0")
|
||||
implementation("com.github.topjohnwu:jtar:1.1.0")
|
||||
implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7")
|
||||
implementation("com.github.topjohnwu:lz4-java:1.7.1")
|
||||
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||
implementation("org.bouncycastle:bcpkix-jdk18on:1.76")
|
||||
implementation("org.bouncycastle:bcpkix-jdk18on:1.77")
|
||||
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0")
|
||||
implementation("dev.rikka.rikkax.insets:insets:1.3.0")
|
||||
implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.2")
|
||||
implementation("io.noties.markwon:core:4.6.2")
|
||||
|
||||
val vLibsu = "5.2.1"
|
||||
val vLibsu = "5.2.2"
|
||||
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
|
||||
implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
|
||||
implementation("com.github.topjohnwu.libsu:nio:${vLibsu}")
|
||||
|
@ -99,12 +99,12 @@ dependencies {
|
|||
implementation("com.squareup.moshi:moshi:${vMoshi}")
|
||||
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
|
||||
|
||||
val vRoom = "2.6.0"
|
||||
val vRoom = "2.6.1"
|
||||
implementation("androidx.room:room-runtime:${vRoom}")
|
||||
implementation("androidx.room:room-ktx:${vRoom}")
|
||||
kapt("androidx.room:room-compiler:${vRoom}")
|
||||
|
||||
val vNav = "2.7.4"
|
||||
val vNav = "2.7.7"
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
|
||||
|
||||
|
@ -112,10 +112,10 @@ dependencies {
|
|||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.2")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.1")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.2")
|
||||
implementation("androidx.transition:transition:1.4.1")
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
|
||||
implementation("com.google.android.material:material:1.10.0")
|
||||
implementation("com.google.android.material:material:1.11.0")
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS" />
|
||||
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE"
|
||||
android:maxSdkVersion="33" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
|
|
|
@ -67,8 +67,6 @@ public final class APKInstall {
|
|||
public interface Session {
|
||||
// @WorkerThread
|
||||
OutputStream openStream(Context context) throws IOException;
|
||||
// @WorkerThread
|
||||
void install(Context context, File apk) throws IOException;
|
||||
// @WorkerThread @Nullable
|
||||
Intent waitIntent();
|
||||
}
|
||||
|
@ -167,13 +165,5 @@ public final class APKInstall {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install(Context context, File apk) throws IOException {
|
||||
try (var src = new FileInputStream(apk);
|
||||
var out = openStream(context)) {
|
||||
transfer(src, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,8 +61,9 @@
|
|||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".core.download.DownloadService"
|
||||
android:name=".core.Service"
|
||||
android:exported="false"
|
||||
android:enabled="@bool/enable_fg_service"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.Manifest.permission.*
|
||||
import android.Manifest.permission.POST_NOTIFICATIONS
|
||||
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.PropertyChangeRegistry
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.Application
|
|||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.system.Os
|
||||
import androidx.profileinstaller.ProfileInstaller
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
|
@ -46,6 +47,8 @@ open class App() : Application() {
|
|||
Timber.e(e)
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
Os.setenv("PATH", "${Os.getenv("PATH")}:/debug_ramdisk:/sbin", true)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(context: Context) {
|
||||
|
|
|
@ -12,8 +12,11 @@ import com.topjohnwu.magisk.core.repository.DBConfig
|
|||
import com.topjohnwu.magisk.core.repository.PreferenceConfig
|
||||
import com.topjohnwu.magisk.core.utils.refreshLocale
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
object Config : PreferenceConfig, DBConfig {
|
||||
|
||||
|
@ -37,6 +40,7 @@ object Config : PreferenceConfig, DBConfig {
|
|||
const val SU_MNT_NS = "mnt_ns"
|
||||
const val SU_BIOMETRIC = "su_biometric"
|
||||
const val ZYGISK = "zygisk"
|
||||
const val BOOTLOOP = "bootloop"
|
||||
const val DENYLIST = "denylist"
|
||||
const val SU_MANAGER = "requester"
|
||||
const val KEYSTORE = "keystore"
|
||||
|
@ -163,6 +167,7 @@ object Config : PreferenceConfig, DBConfig {
|
|||
suBiometric = value
|
||||
}
|
||||
var zygisk by dbSettings(Key.ZYGISK, false)
|
||||
var bootloop by dbSettings(Key.BOOTLOOP, 0)
|
||||
var denyList by BoolDBPropertyNoWrite(Key.DENYLIST, false)
|
||||
var suManager by dbStrings(Key.SU_MANAGER, "", true)
|
||||
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
|
||||
|
@ -171,8 +176,14 @@ object Config : PreferenceConfig, DBConfig {
|
|||
|
||||
fun load(pkg: String?) {
|
||||
// Only try to load prefs when fresh install and a previous package name is set
|
||||
if (pkg != null && prefs.all.isEmpty()) runCatching {
|
||||
context.contentResolver.openInputStream(Provider.preferencesUri(pkg))?.writeTo(prefsFile)
|
||||
if (pkg != null && prefs.all.isEmpty()) {
|
||||
runBlocking {
|
||||
try {
|
||||
context.contentResolver
|
||||
.openInputStream(Provider.preferencesUri(pkg))
|
||||
?.writeTo(prefsFile, dispatcher = Dispatchers.Unconfined)
|
||||
} catch (ignored: IOException) {}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ object Const {
|
|||
}
|
||||
|
||||
object ID {
|
||||
const val JOB_SERVICE_ID = 7
|
||||
const val DOWNLOAD_JOB_ID = 6
|
||||
const val CHECK_UPDATE_JOB_ID = 7
|
||||
}
|
||||
|
||||
object Url {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.job.JobInfo
|
||||
import android.app.job.JobParameters
|
||||
import android.app.job.JobScheduler
|
||||
|
@ -8,38 +11,78 @@ import androidx.core.content.getSystemService
|
|||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.core.base.BaseJobService
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class JobService : BaseJobService() {
|
||||
|
||||
private val job = Job()
|
||||
private val svc get() = ServiceLocator.networkService
|
||||
private var mSession: Session? = null
|
||||
|
||||
override fun onStartJob(params: JobParameters): Boolean {
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO + job)
|
||||
coroutineScope.launch {
|
||||
doWork()
|
||||
@TargetApi(value = 34)
|
||||
inner class Session(
|
||||
private var params: JobParameters
|
||||
) : DownloadEngine.Session {
|
||||
|
||||
override val context get() = this@JobService
|
||||
val engine = DownloadEngine(this)
|
||||
|
||||
fun updateParams(params: JobParameters) {
|
||||
this.params = params
|
||||
engine.reattach()
|
||||
}
|
||||
|
||||
override fun attachNotification(id: Int, builder: Notification.Builder) {
|
||||
setNotification(params, id, builder.build(), JOB_END_NOTIFICATION_POLICY_REMOVE)
|
||||
}
|
||||
|
||||
override fun onDownloadComplete() {
|
||||
jobFinished(params, false)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private suspend fun doWork() {
|
||||
svc.fetchUpdate()?.let {
|
||||
Info.remote = it
|
||||
if (Info.env.isActive && BuildConfig.VERSION_CODE < it.magisk.versionCode)
|
||||
Notifications.updateAvailable()
|
||||
@SuppressLint("NewApi")
|
||||
override fun onStartJob(params: JobParameters): Boolean {
|
||||
return when (params.jobId) {
|
||||
Const.ID.CHECK_UPDATE_JOB_ID -> checkUpdate(params)
|
||||
Const.ID.DOWNLOAD_JOB_ID -> downloadFile(params)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStopJob(params: JobParameters): Boolean {
|
||||
job.cancel()
|
||||
return false
|
||||
override fun onStopJob(params: JobParameters?) = false
|
||||
|
||||
@TargetApi(value = 34)
|
||||
private fun downloadFile(params: JobParameters): Boolean {
|
||||
params.transientExtras.classLoader = Subject::class.java.classLoader
|
||||
val subject = params.transientExtras
|
||||
.getParcelable(DownloadEngine.SUBJECT_KEY, Subject::class.java) ?:
|
||||
return false
|
||||
|
||||
val session = mSession?.also {
|
||||
it.updateParams(params)
|
||||
} ?: run {
|
||||
Session(params).also { mSession = it }
|
||||
}
|
||||
|
||||
session.engine.download(subject)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkUpdate(params: JobParameters): Boolean {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
ServiceLocator.networkService.fetchUpdate()?.let {
|
||||
Info.remote = it
|
||||
if (Info.env.isActive && BuildConfig.VERSION_CODE < it.magisk.versionCode)
|
||||
Notifications.updateAvailable()
|
||||
jobFinished(params, false)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -47,14 +90,14 @@ class JobService : BaseJobService() {
|
|||
val scheduler = context.getSystemService<JobScheduler>() ?: return
|
||||
if (Config.checkUpdate) {
|
||||
val cmp = JobService::class.java.cmp(context.packageName)
|
||||
val info = JobInfo.Builder(Const.ID.JOB_SERVICE_ID, cmp)
|
||||
val info = JobInfo.Builder(Const.ID.CHECK_UPDATE_JOB_ID, cmp)
|
||||
.setPeriodic(TimeUnit.HOURS.toMillis(12))
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setRequiresDeviceIdle(true)
|
||||
.build()
|
||||
scheduler.schedule(info)
|
||||
} else {
|
||||
scheduler.cancel(Const.ID.JOB_SERVICE_ID)
|
||||
scheduler.cancel(Const.ID.CHECK_UPDATE_JOB_ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@ package com.topjohnwu.magisk.core
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.IntentCompat
|
||||
import com.topjohnwu.magisk.core.base.BaseReceiver
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
@ -35,6 +38,12 @@ open class Receiver : BaseReceiver() {
|
|||
}
|
||||
|
||||
when (intent.action ?: return) {
|
||||
DownloadEngine.ACTION -> {
|
||||
IntentCompat.getParcelableExtra(
|
||||
intent, DownloadEngine.SUBJECT_KEY, Subject::class.java)?.let {
|
||||
DownloadEngine.start(context, it)
|
||||
}
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REPLACED -> {
|
||||
// This will only work pre-O
|
||||
if (Config.suReAuth)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.ServiceCompat
|
||||
import androidx.core.content.IntentCompat
|
||||
import com.topjohnwu.magisk.core.base.BaseService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
|
||||
class Service : BaseService(), DownloadEngine.Session {
|
||||
|
||||
private var mEngine: DownloadEngine? = null
|
||||
override val context get() = this
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
if (intent.action == DownloadEngine.ACTION) {
|
||||
IntentCompat
|
||||
.getParcelableExtra(intent, DownloadEngine.SUBJECT_KEY, Subject::class.java)
|
||||
?.let { subject ->
|
||||
val engine = mEngine ?: DownloadEngine(this).also { mEngine = it }
|
||||
engine.download(subject)
|
||||
}
|
||||
}
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun attachNotification(id: Int, builder: Notification.Builder) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
builder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
startForeground(id, builder.build())
|
||||
}
|
||||
|
||||
override fun onDownloadComplete() {
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,11 @@ import com.topjohnwu.magisk.core.model.BranchInfo
|
|||
import com.topjohnwu.magisk.core.model.ModuleJson
|
||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.http.*
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Streaming
|
||||
import retrofit2.http.Url
|
||||
|
||||
private const val BRANCH = "branch"
|
||||
private const val REPO = "repo"
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package com.topjohnwu.magisk.core.data
|
||||
|
||||
import androidx.room.*
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Database
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.topjohnwu.magisk.core.model.su.SuLog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
|
||||
@Database(version = 2, entities = [SuLog::class], exportSchema = false)
|
||||
abstract class SuLogDatabase : RoomDatabase() {
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.app.job.JobInfo
|
||||
import android.app.job.JobScheduler
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.collection.isNotEmpty
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
import com.topjohnwu.magisk.core.ActivityTracker
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.JobService
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.cmp
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.cachedFile
|
||||
import com.topjohnwu.magisk.core.ktx.copyAll
|
||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||
import com.topjohnwu.magisk.core.ktx.forEach
|
||||
import com.topjohnwu.magisk.core.ktx.set
|
||||
import com.topjohnwu.magisk.core.ktx.withStreams
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
||||
import com.topjohnwu.magisk.utils.APKInstall
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.ResponseBody
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
/**
|
||||
* This class drives the execution of file downloads and notification management.
|
||||
*
|
||||
* Each download engine instance has to be paired with a "session" that is managed by the operating
|
||||
* system. A session is an Android component that allows executing long lasting operations and
|
||||
* have its state tied to a notification to show progress.
|
||||
*
|
||||
* A session can only have one single notification representing its state, and the operating system
|
||||
* also uses the notification to manage the lifecycle of a session. One goal of this class is
|
||||
* to support concurrent download tasks using only one single session, so internally it manages
|
||||
* all active tasks and notifications and properly re-assign notifications to be attached to
|
||||
* the session to make sure all download operations can be completed without the operating system
|
||||
* killing the session.
|
||||
*
|
||||
* For API 23 - 33, we use a foreground service as a session.
|
||||
* For API 34 and higher, we use user-initiated job services as a session.
|
||||
*/
|
||||
class DownloadEngine(
|
||||
private val session: Session
|
||||
) {
|
||||
|
||||
interface Session {
|
||||
val context: Context
|
||||
|
||||
fun attachNotification(id: Int, builder: Notification.Builder)
|
||||
fun onDownloadComplete()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION = "com.topjohnwu.magisk.DOWNLOAD"
|
||||
const val SUBJECT_KEY = "subject"
|
||||
private const val REQUEST_CODE = 1
|
||||
|
||||
private val progressBroadcast = MutableLiveData<Pair<Float, Subject>?>()
|
||||
|
||||
private fun broadcast(progress: Float, subject: Subject) {
|
||||
progressBroadcast.postValue(progress to subject)
|
||||
}
|
||||
|
||||
fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
|
||||
progressBroadcast.value = null
|
||||
progressBroadcast.observe(owner) {
|
||||
val (progress, subject) = it ?: return@observe
|
||||
callback(progress, subject)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIntent(context: Context, subject: Subject) =
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
context.intent<com.topjohnwu.magisk.core.Receiver>()
|
||||
.setAction(ACTION)
|
||||
.putExtra(SUBJECT_KEY, subject)
|
||||
} else {
|
||||
context.intent<com.topjohnwu.magisk.core.Service>()
|
||||
.setAction(ACTION)
|
||||
.putExtra(SUBJECT_KEY, subject)
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
fun getPendingIntent(context: Context, subject: Subject): PendingIntent {
|
||||
val flag = PendingIntent.FLAG_IMMUTABLE or
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or
|
||||
PendingIntent.FLAG_ONE_SHOT
|
||||
val intent = createIntent(context, subject)
|
||||
return if (Build.VERSION.SDK_INT >= 34) {
|
||||
// On API 34+, download tasks are handled with a user-initiated job.
|
||||
// However, there is no way to schedule a new job directly with a pending intent.
|
||||
// As a workaround, we send the subject to a broadcast receiver and have it
|
||||
// schedule the job for us.
|
||||
PendingIntent.getBroadcast(context, REQUEST_CODE, intent, flag)
|
||||
} else if (Build.VERSION.SDK_INT >= 26) {
|
||||
PendingIntent.getForegroundService(context, REQUEST_CODE, intent, flag)
|
||||
} else {
|
||||
PendingIntent.getService(context, REQUEST_CODE, intent, flag)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
fun startWithActivity(activity: BaseActivity, subject: Subject) {
|
||||
activity.withPermission(Manifest.permission.POST_NOTIFICATIONS) {
|
||||
// Always download regardless of notification permission status
|
||||
start(activity.applicationContext, subject)
|
||||
}
|
||||
}
|
||||
|
||||
fun start(context: Context, subject: Subject) {
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val scheduler = context.getSystemService<JobScheduler>()!!
|
||||
val cmp = JobService::class.java.cmp(context.packageName)
|
||||
val extras = Bundle()
|
||||
extras.putParcelable(SUBJECT_KEY, subject)
|
||||
val info = JobInfo.Builder(Const.ID.DOWNLOAD_JOB_ID, cmp)
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setUserInitiated(true)
|
||||
.setTransientExtras(extras)
|
||||
.build()
|
||||
scheduler.schedule(info)
|
||||
} else if (Build.VERSION.SDK_INT >= 26) {
|
||||
context.startForegroundService(createIntent(context, subject))
|
||||
} else {
|
||||
context.startService(createIntent(context, subject))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun download(subject: Subject) {
|
||||
notifyUpdate(subject.notifyId)
|
||||
CoroutineScope(job + Dispatchers.IO).launch {
|
||||
try {
|
||||
val stream = network.fetchFile(subject.url).toProgressStream(subject)
|
||||
when (subject) {
|
||||
is Subject.App -> handleApp(stream, subject)
|
||||
is Subject.Module -> handleModule(stream, subject.file)
|
||||
else -> stream.copyAndClose(subject.file.outputStream())
|
||||
}
|
||||
val activity = ActivityTracker.foreground
|
||||
if (activity != null && subject.autoLaunch) {
|
||||
notifyRemove(subject.notifyId)
|
||||
subject.pendingIntent(activity)?.send()
|
||||
} else {
|
||||
notifyFinish(subject)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
notifyFail(subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun reattach() {
|
||||
val builder = notifications[attachedId] ?: return
|
||||
session.attachNotification(attachedId, builder)
|
||||
}
|
||||
|
||||
private val notifications = SparseArrayCompat<Notification.Builder>()
|
||||
private var attachedId = -1
|
||||
|
||||
private val job = Job()
|
||||
|
||||
private val context get() = session.context
|
||||
private val network get() = ServiceLocator.networkService
|
||||
|
||||
private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
|
||||
val notification = notifyRemove(id)?.also(editor) ?: return -1
|
||||
val newId = Notifications.nextId()
|
||||
Notifications.mgr.notify(newId, notification.build())
|
||||
return newId
|
||||
}
|
||||
|
||||
private fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
|
||||
broadcast(-2f, subject)
|
||||
it.setContentText(context.getString(R.string.download_file_error))
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setOngoing(false)
|
||||
}
|
||||
|
||||
private fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
|
||||
broadcast(1f, subject)
|
||||
it.setContentTitle(subject.title)
|
||||
.setContentText(context.getString(R.string.download_complete))
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.setAutoCancel(true)
|
||||
subject.pendingIntent(context)?.let { intent -> it.setContentIntent(intent) }
|
||||
}
|
||||
|
||||
private fun attachNotification(id: Int, notification: Notification.Builder) {
|
||||
attachedId = id
|
||||
session.attachNotification(id, notification)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) {
|
||||
val notification = (notifications[id] ?: Notifications.startProgress("").also {
|
||||
notifications[id] = it
|
||||
}).apply(editor)
|
||||
|
||||
if (attachedId < 0)
|
||||
attachNotification(id, notification)
|
||||
else
|
||||
Notifications.mgr.notify(id, notification.build())
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun notifyRemove(id: Int): Notification.Builder? {
|
||||
val idx = notifications.indexOfKey(id)
|
||||
var n: Notification.Builder? = null
|
||||
|
||||
if (idx >= 0) {
|
||||
n = notifications.valueAt(idx)
|
||||
notifications.removeAt(idx)
|
||||
|
||||
// The cancelled notification is the one attached to the session, need special handling
|
||||
if (attachedId == id) {
|
||||
if (notifications.isNotEmpty()) {
|
||||
// There are still remaining notifications, pick one and attach to the session
|
||||
val anotherId = notifications.keyAt(0)
|
||||
val notification = notifications.valueAt(0)
|
||||
attachNotification(anotherId, notification)
|
||||
} else {
|
||||
// No more notifications left, terminate the session
|
||||
attachedId = -1
|
||||
session.onDownloadComplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Notifications.mgr.cancel(id)
|
||||
return n
|
||||
}
|
||||
|
||||
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
|
||||
val external = subject.file.outputStream()
|
||||
|
||||
if (isRunningAsStub) {
|
||||
val updateApk = StubApk.update(context)
|
||||
try {
|
||||
// Download full APK to stub update path
|
||||
stream.copyAndClose(TeeOutputStream(external, updateApk.outputStream()))
|
||||
|
||||
// Also upgrade stub
|
||||
notifyUpdate(subject.notifyId) {
|
||||
it.setProgress(0, 0, true)
|
||||
.setContentTitle(context.getString(R.string.hide_app_title))
|
||||
.setContentText("")
|
||||
}
|
||||
|
||||
// Extract stub
|
||||
val zf = ZipFile(updateApk)
|
||||
val apk = context.cachedFile("stub.apk")
|
||||
apk.delete()
|
||||
zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk)
|
||||
zf.close()
|
||||
|
||||
// Patch and install
|
||||
subject.intent = HideAPK.upgrade(context, apk)
|
||||
?: throw IOException("HideAPK patch error")
|
||||
apk.delete()
|
||||
} catch (e: Exception) {
|
||||
// If any error occurred, do not let stub load the new APK
|
||||
updateApk.delete()
|
||||
throw e
|
||||
}
|
||||
} else {
|
||||
val session = APKInstall.startSession(context)
|
||||
stream.copyAndClose(TeeOutputStream(external, session.openStream(context)))
|
||||
subject.intent = session.waitIntent()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleModule(src: InputStream, file: Uri) {
|
||||
val input = ZipInputStream(src)
|
||||
val output = ZipOutputStream(file.outputStream())
|
||||
|
||||
withStreams(input, output) { zin, zout ->
|
||||
zout.putNextEntry(ZipEntry("META-INF/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
|
||||
context.assets.open("module_installer.sh").use { it.copyAll(zout) }
|
||||
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
|
||||
zout.write("#MAGISK\n".toByteArray())
|
||||
|
||||
zin.forEach { entry ->
|
||||
val path = entry.name
|
||||
if (path.isNotEmpty() && !path.startsWith("META-INF")) {
|
||||
zout.putNextEntry(ZipEntry(path))
|
||||
if (!entry.isDirectory) {
|
||||
zin.copyAll(zout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TeeOutputStream(
|
||||
private val o1: OutputStream,
|
||||
private val o2: OutputStream
|
||||
) : OutputStream() {
|
||||
override fun write(b: Int) {
|
||||
o1.write(b)
|
||||
o2.write(b)
|
||||
}
|
||||
override fun write(b: ByteArray?, off: Int, len: Int) {
|
||||
o1.write(b, off, len)
|
||||
o2.write(b, off, len)
|
||||
}
|
||||
override fun close() {
|
||||
o1.close()
|
||||
o2.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResponseBody.toProgressStream(subject: Subject): InputStream {
|
||||
val max = contentLength()
|
||||
val total = max.toFloat() / 1048576
|
||||
val id = subject.notifyId
|
||||
|
||||
notifyUpdate(id) { it.setContentTitle(subject.title) }
|
||||
|
||||
return ProgressInputStream(byteStream()) {
|
||||
val progress = it.toFloat() / 1048576
|
||||
notifyUpdate(id) { notification ->
|
||||
if (max > 0) {
|
||||
broadcast(progress / total, subject)
|
||||
notification
|
||||
.setProgress(max.toInt(), it.toInt(), false)
|
||||
.setContentText("%.2f / %.2f MB".format(progress, total))
|
||||
} else {
|
||||
broadcast(-1f, subject)
|
||||
notification.setContentText("%.2f MB / ??".format(progress))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.net.toFile
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
import com.topjohnwu.magisk.core.ActivityTracker
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.*
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
import com.topjohnwu.magisk.utils.APKInstall
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.Properties
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class DownloadService : NotificationService() {
|
||||
|
||||
private val job = Job()
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
intent.getParcelableExtra<Subject>(SUBJECT_KEY)?.let { download(it) }
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun download(subject: Subject) {
|
||||
notifyUpdate(subject.notifyId)
|
||||
CoroutineScope(job + Dispatchers.IO).launch {
|
||||
try {
|
||||
val stream = service.fetchFile(subject.url).toProgressStream(subject)
|
||||
when (subject) {
|
||||
is Subject.App -> handleApp(stream, subject)
|
||||
is Subject.Module -> handleModule(stream, subject.file)
|
||||
}
|
||||
val activity = ActivityTracker.foreground
|
||||
if (activity != null && subject.autoLaunch) {
|
||||
notifyRemove(subject.notifyId)
|
||||
subject.pendingIntent(activity)?.send()
|
||||
} else {
|
||||
notifyFinish(subject)
|
||||
}
|
||||
subject.postDownload?.invoke()
|
||||
if (!hasNotifications)
|
||||
stopSelf()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
notifyFail(subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleApp(stream: InputStream, subject: Subject.App) {
|
||||
fun writeTee(output: OutputStream) {
|
||||
val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri
|
||||
val external = uri.outputStream()
|
||||
stream.copyAndClose(TeeOutputStream(external, output))
|
||||
}
|
||||
|
||||
if (isRunningAsStub) {
|
||||
val updateApk = StubApk.update(this)
|
||||
try {
|
||||
// Download full APK to stub update path
|
||||
writeTee(updateApk.outputStream())
|
||||
|
||||
val zf = ZipFile(updateApk)
|
||||
val prop = Properties()
|
||||
prop.load(ByteArrayInputStream(zf.comment.toByteArray()))
|
||||
val stubVersion = prop.getProperty("stubVersion").toIntOrNull() ?: -1
|
||||
if (Info.stub!!.version < stubVersion) {
|
||||
// Also upgrade stub
|
||||
notifyUpdate(subject.notifyId) {
|
||||
it.setProgress(0, 0, true)
|
||||
.setContentTitle(getString(R.string.hide_app_title))
|
||||
.setContentText("")
|
||||
}
|
||||
|
||||
// Extract stub
|
||||
val apk = subject.file.toFile()
|
||||
zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk)
|
||||
zf.close()
|
||||
|
||||
// Patch and install
|
||||
subject.intent = HideAPK.upgrade(this, apk)
|
||||
?: throw IOException("HideAPK patch error")
|
||||
apk.delete()
|
||||
} else {
|
||||
ActivityTracker.foreground?.let {
|
||||
// Relaunch the process if we are foreground
|
||||
StubApk.restartProcess(it)
|
||||
} ?: run {
|
||||
// Or else kill the current process after posting notification
|
||||
subject.intent = selfLaunchIntent()
|
||||
subject.postDownload = { Runtime.getRuntime().exit(0) }
|
||||
}
|
||||
return
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// If any error occurred, do not let stub load the new APK
|
||||
updateApk.delete()
|
||||
throw e
|
||||
}
|
||||
} else {
|
||||
val session = APKInstall.startSession(this)
|
||||
writeTee(session.openStream(this))
|
||||
subject.intent = session.waitIntent()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleModule(src: InputStream, file: Uri) {
|
||||
val input = ZipInputStream(src.buffered())
|
||||
val output = ZipOutputStream(file.outputStream().buffered())
|
||||
|
||||
withStreams(input, output) { zin, zout ->
|
||||
zout.putNextEntry(ZipEntry("META-INF/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
|
||||
assets.open("module_installer.sh").copyTo(zout)
|
||||
|
||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
|
||||
zout.write("#MAGISK\n".toByteArray())
|
||||
|
||||
zin.forEach { entry ->
|
||||
val path = entry.name
|
||||
if (path.isNotEmpty() && !path.startsWith("META-INF")) {
|
||||
zout.putNextEntry(ZipEntry(path))
|
||||
if (!entry.isDirectory) {
|
||||
zin.copyTo(zout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TeeOutputStream(
|
||||
private val o1: OutputStream,
|
||||
private val o2: OutputStream
|
||||
) : OutputStream() {
|
||||
override fun write(b: Int) {
|
||||
o1.write(b)
|
||||
o2.write(b)
|
||||
}
|
||||
override fun write(b: ByteArray?, off: Int, len: Int) {
|
||||
o1.write(b, off, len)
|
||||
o2.write(b, off, len)
|
||||
}
|
||||
override fun close() {
|
||||
o1.close()
|
||||
o2.close()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SUBJECT_KEY = "subject"
|
||||
private const val REQUEST_CODE = 1
|
||||
|
||||
fun observeProgress(owner: LifecycleOwner, callback: (Float, Subject) -> Unit) {
|
||||
progressBroadcast.value = null
|
||||
progressBroadcast.observe(owner) {
|
||||
val (progress, subject) = it ?: return@observe
|
||||
callback(progress, subject)
|
||||
}
|
||||
}
|
||||
|
||||
private fun intent(context: Context, subject: Subject) =
|
||||
context.intent<DownloadService>().putExtra(SUBJECT_KEY, subject)
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
fun getPendingIntent(context: Context, subject: Subject): PendingIntent {
|
||||
val flag = FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT or FLAG_ONE_SHOT
|
||||
val intent = intent(context, subject)
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
getForegroundService(context, REQUEST_CODE, intent, flag)
|
||||
} else {
|
||||
getService(context, REQUEST_CODE, intent, flag)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
fun start(activity: BaseActivity, subject: Subject) {
|
||||
activity.withPermission(Manifest.permission.POST_NOTIFICATIONS) {
|
||||
// Always download regardless of notification permission status
|
||||
val app = activity.applicationContext
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
app.startForegroundService(intent(app, subject))
|
||||
} else {
|
||||
app.startService(intent(app, subject))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.base.BaseService
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.ktx.synchronized
|
||||
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import okhttp3.ResponseBody
|
||||
import java.io.InputStream
|
||||
|
||||
open class NotificationService : BaseService() {
|
||||
|
||||
private val notifications = HashMap<Int, Notification.Builder>().synchronized()
|
||||
protected val hasNotifications get() = notifications.isNotEmpty()
|
||||
|
||||
protected val service get() = ServiceLocator.networkService
|
||||
|
||||
private var attachedNotificationId = 0
|
||||
|
||||
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||
super.onTaskRemoved(rootIntent)
|
||||
notifications.forEach { Notifications.mgr.cancel(it.key) }
|
||||
notifications.clear()
|
||||
}
|
||||
|
||||
protected fun ResponseBody.toProgressStream(subject: Subject): InputStream {
|
||||
val max = contentLength()
|
||||
val total = max.toFloat() / 1048576
|
||||
val id = subject.notifyId
|
||||
|
||||
notifyUpdate(id) { it.setContentTitle(subject.title) }
|
||||
|
||||
return ProgressInputStream(byteStream()) {
|
||||
val progress = it.toFloat() / 1048576
|
||||
notifyUpdate(id) { notification ->
|
||||
if (max > 0) {
|
||||
broadcast(progress / total, subject)
|
||||
notification
|
||||
.setProgress(max.toInt(), it.toInt(), false)
|
||||
.setContentText("%.2f / %.2f MB".format(progress, total))
|
||||
} else {
|
||||
broadcast(-1f, subject)
|
||||
notification.setContentText("%.2f MB / ??".format(progress))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int {
|
||||
val notification = notifyRemove(id)?.also(editor) ?: return -1
|
||||
val newId = Notifications.nextId()
|
||||
Notifications.mgr.notify(newId, notification.build())
|
||||
return newId
|
||||
}
|
||||
|
||||
protected fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) {
|
||||
broadcast(-2f, subject)
|
||||
it.setContentText(getString(R.string.download_file_error))
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setOngoing(false)
|
||||
}
|
||||
|
||||
protected fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) {
|
||||
broadcast(1f, subject)
|
||||
it.setContentTitle(subject.title)
|
||||
.setContentText(getString(R.string.download_complete))
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.setAutoCancel(true)
|
||||
subject.pendingIntent(this)?.let { intent -> it.setContentIntent(intent) }
|
||||
}
|
||||
|
||||
private fun attachNotification(id: Int, notification: Notification) {
|
||||
attachedNotificationId = id
|
||||
startForeground(id, notification)
|
||||
}
|
||||
|
||||
private fun maybeDetachNotification(id: Int) : Boolean {
|
||||
if (attachedNotificationId != id) return false
|
||||
if (hasNotifications) {
|
||||
val (anotherId, notification) = notifications.entries.first()
|
||||
// Attaching a new notification will remove the current showing one
|
||||
attachNotification(anotherId, notification.build())
|
||||
return true
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
stopForeground(true)
|
||||
}
|
||||
attachedNotificationId = 0
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) {
|
||||
fun create() = Notifications.startProgress("")
|
||||
|
||||
val wasEmpty = !hasNotifications
|
||||
val notification = notifications.getOrPut(id, ::create).also(editor).build()
|
||||
if (wasEmpty)
|
||||
attachNotification(id, notification)
|
||||
else
|
||||
Notifications.mgr.notify(id, notification)
|
||||
}
|
||||
|
||||
protected fun notifyRemove(id: Int): Notification.Builder? {
|
||||
val n = notifications.remove(id)
|
||||
if (n == null || !maybeDetachNotification(id))
|
||||
Notifications.mgr.cancel(id)
|
||||
return n
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
protected val progressBroadcast = MutableLiveData<Pair<Float, Subject>?>()
|
||||
|
||||
private fun broadcast(progress: Float, subject: Subject) {
|
||||
progressBroadcast.postValue(progress to subject)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,13 +17,8 @@ import com.topjohnwu.magisk.ui.flash.FlashFragment
|
|||
import com.topjohnwu.magisk.view.Notifications
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
private fun cachedFile(name: String) = AppContext.cachedFile(name).apply { delete() }.toUri()
|
||||
|
||||
enum class Action {
|
||||
Flash,
|
||||
Download
|
||||
}
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
sealed class Subject : Parcelable {
|
||||
|
||||
|
@ -32,19 +27,17 @@ sealed class Subject : Parcelable {
|
|||
abstract val title: String
|
||||
abstract val notifyId: Int
|
||||
open val autoLaunch: Boolean get() = true
|
||||
open val postDownload: (() -> Unit)? get() = null
|
||||
|
||||
abstract fun pendingIntent(context: Context): PendingIntent?
|
||||
open fun pendingIntent(context: Context): PendingIntent? = null
|
||||
|
||||
@Parcelize
|
||||
class Module(
|
||||
val module: OnlineModule,
|
||||
val action: Action,
|
||||
private val module: OnlineModule,
|
||||
override val autoLaunch: Boolean,
|
||||
override val notifyId: Int = Notifications.nextId()
|
||||
) : Subject() {
|
||||
override val url: String get() = module.zipUrl
|
||||
override val title: String get() = module.downloadFilename
|
||||
override val autoLaunch: Boolean get() = action == Action.Flash
|
||||
|
||||
@IgnoredOnParcel
|
||||
override val file by lazy {
|
||||
|
@ -65,17 +58,24 @@ sealed class Subject : Parcelable {
|
|||
|
||||
@IgnoredOnParcel
|
||||
override val file by lazy {
|
||||
cachedFile("manager.apk")
|
||||
MediaStoreUtils.getFile("${title}.apk").uri
|
||||
}
|
||||
|
||||
@IgnoredOnParcel
|
||||
override var postDownload: (() -> Unit)? = null
|
||||
|
||||
@IgnoredOnParcel
|
||||
var intent: Intent? = null
|
||||
override fun pendingIntent(context: Context) = intent?.toPending(context)
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
class Test(
|
||||
override val notifyId: Int = Notifications.nextId(),
|
||||
override val title: String = UUID.randomUUID().toString().substring(0, 6)
|
||||
) : Subject() {
|
||||
override val url get() = "https://link.testfile.org/250MB"
|
||||
override val file get() = File("/dev/null").toUri()
|
||||
override val autoLaunch get() = false
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
protected fun Intent.toPending(context: Context): PendingIntent {
|
||||
return PendingIntent.getActivity(context, notifyId, this,
|
||||
|
|
|
@ -2,10 +2,15 @@ package com.topjohnwu.magisk.core.ktx
|
|||
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flatMapMerge
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.lang.reflect.Field
|
||||
|
@ -35,9 +40,38 @@ inline fun <In : InputStream, Out : OutputStream> withStreams(
|
|||
}
|
||||
}
|
||||
|
||||
fun InputStream.copyAndClose(out: OutputStream) = withStreams(this, out) { i, o -> i.copyTo(o) }
|
||||
@Throws(IOException::class)
|
||||
suspend fun InputStream.copyAll(
|
||||
out: OutputStream,
|
||||
bufferSize: Int = DEFAULT_BUFFER_SIZE,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
): Long {
|
||||
return withContext(dispatcher) {
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(bufferSize)
|
||||
var bytes = read(buffer)
|
||||
while (isActive && bytes >= 0) {
|
||||
out.write(buffer, 0, bytes)
|
||||
bytesCopied += bytes
|
||||
bytes = read(buffer)
|
||||
}
|
||||
bytesCopied
|
||||
}
|
||||
}
|
||||
|
||||
fun InputStream.writeTo(file: File) = copyAndClose(file.outputStream())
|
||||
@Throws(IOException::class)
|
||||
suspend inline fun InputStream.copyAndClose(
|
||||
out: OutputStream,
|
||||
bufferSize: Int = DEFAULT_BUFFER_SIZE,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) = withStreams(this, out) { i, o -> i.copyAll(o, bufferSize, dispatcher) }
|
||||
|
||||
@Throws(IOException::class)
|
||||
suspend inline fun InputStream.writeTo(
|
||||
file: File,
|
||||
bufferSize: Int = DEFAULT_BUFFER_SIZE,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) = copyAndClose(file.outputStream(), bufferSize, dispatcher)
|
||||
|
||||
operator fun <E> SparseArrayCompat<E>.set(key: Int, value: E) {
|
||||
put(key, value)
|
||||
|
|
|
@ -26,7 +26,7 @@ open class FlashZip(
|
|||
private lateinit var zipFile: File
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun flash(): Boolean {
|
||||
private suspend fun flash(): Boolean {
|
||||
installDir.deleteRecursively()
|
||||
installDir.mkdirs()
|
||||
|
||||
|
@ -47,13 +47,13 @@ open class FlashZip(
|
|||
}
|
||||
}
|
||||
|
||||
val isValid = runCatching {
|
||||
val isValid = try {
|
||||
zipFile.unzip(installDir, "META-INF/com/google/android", true)
|
||||
val script = File(installDir, "updater-script")
|
||||
script.readText().contains("#MAGISK")
|
||||
}.getOrElse {
|
||||
} catch (e: IOException) {
|
||||
console.add("! Unzip error")
|
||||
throw it
|
||||
throw e
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.topjohnwu.magisk.core.Config
|
|||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Provider
|
||||
import com.topjohnwu.magisk.core.ktx.await
|
||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.utils.AXML
|
||||
|
@ -168,7 +169,7 @@ object HideAPK {
|
|||
activity.finish()
|
||||
}
|
||||
|
||||
private fun patchAndHide(activity: Activity, label: String, onFailure: Runnable): Boolean {
|
||||
private suspend fun patchAndHide(activity: Activity, label: String, onFailure: Runnable): Boolean {
|
||||
val stub = File(activity.cacheDir, "stub.apk")
|
||||
try {
|
||||
activity.assets.open("stub.apk").writeTo(stub)
|
||||
|
@ -195,7 +196,7 @@ object HideAPK {
|
|||
if (Shell.cmd(cmd).exec().isSuccess) return true
|
||||
|
||||
try {
|
||||
session.install(activity, repack)
|
||||
repack.inputStream().copyAndClose(session.openStream(activity))
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
|
@ -244,7 +245,7 @@ object HideAPK {
|
|||
if (Shell.cmd(cmd).await().isSuccess) return
|
||||
val success = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
session.install(activity, apk)
|
||||
apk.inputStream().copyAndClose(session.openStream(activity))
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
return@withContext false
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Process
|
||||
import android.system.ErrnoException
|
||||
import android.system.Os
|
||||
import android.system.OsConstants
|
||||
|
@ -17,6 +18,7 @@ import com.topjohnwu.magisk.core.Const
|
|||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.copyAll
|
||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||
import com.topjohnwu.magisk.core.ktx.reboot
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
|
@ -93,7 +95,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
private fun extractFiles(): Boolean {
|
||||
private suspend fun extractFiles(): Boolean {
|
||||
console.add("- Device platform: ${Const.CPU_ABI}")
|
||||
console.add("- Installing: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||
|
||||
|
@ -104,40 +106,41 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
try {
|
||||
// Extract binaries
|
||||
if (isRunningAsStub) {
|
||||
val zf = ZipFile(StubApk.current(context))
|
||||
ZipFile(StubApk.current(context)).use { zf ->
|
||||
zf.entries().asSequence().filter {
|
||||
!it.isDirectory && it.name.startsWith("/lib/${Const.CPU_ABI}/")
|
||||
}.forEach {
|
||||
val n = it.name.substring(it.name.lastIndexOf('/') + 1)
|
||||
val name = n.substring(3, n.length - 3)
|
||||
val dest = File(installDir, name)
|
||||
zf.getInputStream(it).writeTo(dest)
|
||||
dest.setExecutable(true)
|
||||
}
|
||||
|
||||
// Also extract magisk32 on non 64-bit only 64-bit devices
|
||||
val is32lib = Const.CPU_ABI_32?.let {
|
||||
{ entry: ZipEntry -> entry.name == "lib/$it/libmagisk32.so" }
|
||||
} ?: { false }
|
||||
|
||||
zf.entries().asSequence().filter {
|
||||
!it.isDirectory && (it.name.startsWith("lib/${Const.CPU_ABI}/") || is32lib(it))
|
||||
}.forEach {
|
||||
val n = it.name.substring(it.name.lastIndexOf('/') + 1)
|
||||
val name = n.substring(3, n.length - 3)
|
||||
val dest = File(installDir, name)
|
||||
zf.getInputStream(it).writeTo(dest)
|
||||
dest.setExecutable(true)
|
||||
val abi32 = Const.CPU_ABI_32
|
||||
if (Process.is64Bit() && abi32 != null) {
|
||||
val magisk32 = File(installDir, "magisk32")
|
||||
zf.getInputStream(ZipEntry("lib/$abi32/libmagisk.so")).writeTo(magisk32)
|
||||
magisk32.setExecutable(true)
|
||||
}
|
||||
}
|
||||
zf.close()
|
||||
} else {
|
||||
val info = context.applicationInfo
|
||||
var libs = File(info.nativeLibraryDir).listFiles { _, name ->
|
||||
name.startsWith("lib") && name.endsWith(".so")
|
||||
} ?: emptyArray()
|
||||
|
||||
// Also symlink magisk32 on non 64-bit only 64-bit devices
|
||||
val lib32 = info.javaClass.getDeclaredField("secondaryNativeLibraryDir")
|
||||
.get(info) as String?
|
||||
if (lib32 != null) {
|
||||
libs += File(lib32, "libmagisk32.so")
|
||||
}
|
||||
|
||||
for (lib in libs) {
|
||||
val name = lib.name.substring(3, lib.name.length - 3)
|
||||
Os.symlink(lib.path, "$installDir/$name")
|
||||
}
|
||||
|
||||
// Also symlink magisk32 on 64-bit devices that supports 32-bit
|
||||
val lib32 = info.javaClass.getDeclaredField("secondaryNativeLibraryDir")
|
||||
.get(info) as String?
|
||||
if (lib32 != null) {
|
||||
Os.symlink("$lib32/libmagisk.so", "$installDir/magisk32");
|
||||
}
|
||||
}
|
||||
|
||||
// Extract scripts
|
||||
|
@ -174,7 +177,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
private fun InputStream.copyAndCloseOut(out: OutputStream) = out.use { copyTo(it) }
|
||||
private suspend fun InputStream.copyAndCloseOut(out: OutputStream) = out.use { copyAll(it) }
|
||||
|
||||
private fun newTarEntry(name: String, size: Long): TarEntry {
|
||||
console.add("-- Writing: $name")
|
||||
|
@ -191,7 +194,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
private class NoBootException : IOException()
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun processTar(tarIn: TarInputStream, tarOut: TarOutputStream): ExtendedFile {
|
||||
private suspend fun processTar(tarIn: TarInputStream, tarOut: TarOutputStream): ExtendedFile {
|
||||
console.add("- Processing tar file")
|
||||
lateinit var entry: TarEntry
|
||||
|
||||
|
@ -228,7 +231,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
} else {
|
||||
console.add("-- Copying: ${entry.name}")
|
||||
tarOut.putNextEntry(entry)
|
||||
tarIn.copyTo(tarOut, bufferSize = 1024 * 1024)
|
||||
tarIn.copyAll(tarOut, bufferSize = 1024 * 1024)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,10 +239,10 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
val initBoot = installDir.getChildFile("init_boot.img")
|
||||
val recovery = installDir.getChildFile("recovery.img")
|
||||
|
||||
fun ExtendedFile.copyToTar() {
|
||||
suspend fun ExtendedFile.copyToTar() {
|
||||
newInputStream().use {
|
||||
tarOut.putNextEntry(newTarEntry(name, length()))
|
||||
it.copyTo(tarOut)
|
||||
it.copyAll(tarOut)
|
||||
}
|
||||
delete()
|
||||
}
|
||||
|
@ -273,7 +276,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun processZip(zipIn: ZipInputStream): ExtendedFile {
|
||||
private suspend fun processZip(zipIn: ZipInputStream): ExtendedFile {
|
||||
console.add("- Processing zip file")
|
||||
val boot = installDir.getChildFile("boot.img")
|
||||
val initBoot = installDir.getChildFile("init_boot.img")
|
||||
|
@ -373,23 +376,22 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleFile(uri: Uri): Boolean {
|
||||
private suspend fun handleFile(uri: Uri): Boolean {
|
||||
val outStream: OutputStream
|
||||
val outFile: MediaStoreUtils.UriFile
|
||||
|
||||
// Process input file
|
||||
try {
|
||||
uri.inputStream().buffered().use { src ->
|
||||
src.mark(500)
|
||||
val magic = ByteArray(4)
|
||||
val tarMagic = ByteArray(5)
|
||||
if (src.read(magic) != magic.size || src.skip(253) != 253L ||
|
||||
src.read(tarMagic) != tarMagic.size
|
||||
) {
|
||||
PushbackInputStream(uri.inputStream(), 512).use { src ->
|
||||
val head = ByteArray(512)
|
||||
if (src.read(head) != head.size) {
|
||||
console.add("! Invalid input file")
|
||||
return false
|
||||
}
|
||||
src.reset()
|
||||
src.unread(head)
|
||||
|
||||
val magic = head.copyOf(4)
|
||||
val tarMagic = Arrays.copyOfRange(head, 257, 262)
|
||||
|
||||
val alpha = "abcdefghijklmnopqrstuvwxyz"
|
||||
val alphaNum = "$alpha${alpha.uppercase(Locale.ROOT)}0123456789"
|
||||
|
@ -510,7 +512,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
|
||||
private fun flashBoot() = "direct_install $installDir $srcBoot".sh().isSuccess
|
||||
|
||||
private fun postOTA(): Boolean {
|
||||
private suspend fun postOTA(): Boolean {
|
||||
try {
|
||||
val bootctl = File.createTempFile("bootctl", null, context.cacheDir)
|
||||
context.assets.open("bootctl").writeTo(bootctl)
|
||||
|
@ -521,9 +523,10 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
return false
|
||||
}
|
||||
|
||||
console.add("***************************************")
|
||||
console.add("*************************************************************")
|
||||
console.add(" Next reboot will boot to second slot!")
|
||||
console.add("***************************************")
|
||||
console.add(" Go back to System Updates and press Restart to complete OTA")
|
||||
console.add("*************************************************************")
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -533,14 +536,14 @@ abstract class MagiskInstallImpl protected constructor(
|
|||
private fun String.fsh() = ShellUtils.fastCmd(shell, this)
|
||||
private fun Array<String>.fsh() = ShellUtils.fastCmd(shell, *this)
|
||||
|
||||
protected fun patchFile(file: Uri) = extractFiles() && handleFile(file)
|
||||
protected suspend fun patchFile(file: Uri) = extractFiles() && handleFile(file)
|
||||
|
||||
protected fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot()
|
||||
protected suspend fun direct() = findImage() && extractFiles() && patchBoot() && flashBoot()
|
||||
|
||||
protected fun secondSlot() =
|
||||
protected suspend fun secondSlot() =
|
||||
findSecondary() && extractFiles() && patchBoot() && flashBoot() && postOTA()
|
||||
|
||||
protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
|
||||
protected suspend fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
|
||||
|
||||
protected fun uninstall() = "run_uninstaller $AppApkPath".sh().isSuccess
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import com.topjohnwu.magisk.core.createNewResources
|
|||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
var currentLocale: Locale = Locale.getDefault()
|
||||
|
||||
|
|
|
@ -15,9 +15,6 @@ import com.topjohnwu.magisk.core.di.AppContext
|
|||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.security.MessageDigest
|
||||
import kotlin.experimental.and
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
object MediaStoreUtils {
|
||||
|
@ -120,24 +117,6 @@ object MediaStoreUtils {
|
|||
return this.toString()
|
||||
}
|
||||
|
||||
fun Uri.checkSum(alg: String, reference: String) = runCatching {
|
||||
this.inputStream().use {
|
||||
val digest = MessageDigest.getInstance(alg)
|
||||
it.copyTo(object : OutputStream() {
|
||||
override fun write(b: Int) {
|
||||
digest.update(b.toByte())
|
||||
}
|
||||
|
||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||
digest.update(b, off, len)
|
||||
}
|
||||
})
|
||||
val sb = StringBuilder()
|
||||
digest.digest().forEach { b -> sb.append("%02x".format(b and 0xff.toByte())) }
|
||||
sb.toString() == reference
|
||||
}
|
||||
}.getOrElse { false }
|
||||
|
||||
interface UriFile {
|
||||
val uri: Uri
|
||||
fun delete(): Boolean
|
||||
|
|
|
@ -13,6 +13,8 @@ import com.topjohnwu.magisk.core.ktx.rawResource
|
|||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.util.jar.JarFile
|
||||
|
||||
|
@ -34,7 +36,9 @@ class ShellInit : Shell.Initializer() {
|
|||
val bb = jar.getJarEntry("lib/${Const.CPU_ABI}/libbusybox.so")
|
||||
localBB = context.deviceProtectedContext.cachedFile("busybox")
|
||||
localBB.delete()
|
||||
jar.getInputStream(bb).writeTo(localBB)
|
||||
runBlocking {
|
||||
jar.getInputStream(bb).writeTo(localBB, dispatcher = Dispatchers.Unconfined)
|
||||
}
|
||||
localBB.setExecutable(true)
|
||||
} else {
|
||||
localBB = File(context.applicationInfo.nativeLibraryDir, "libbusybox.so")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import com.topjohnwu.magisk.core.ktx.copyAll
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
@ -7,14 +8,14 @@ import java.util.zip.ZipEntry
|
|||
import java.util.zip.ZipInputStream
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun File.unzip(folder: File, path: String = "", junkPath: Boolean = false) {
|
||||
suspend fun File.unzip(folder: File, path: String = "", junkPath: Boolean = false) {
|
||||
inputStream().buffered().use {
|
||||
it.unzip(folder, path, junkPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) {
|
||||
suspend fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) {
|
||||
try {
|
||||
val zin = ZipInputStream(this)
|
||||
var entry: ZipEntry
|
||||
|
@ -34,7 +35,7 @@ fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) {
|
|||
if (!it.exists())
|
||||
it.mkdirs()
|
||||
}
|
||||
dest.outputStream().use { out -> zin.copyTo(out) }
|
||||
dest.outputStream().use { out -> zin.copyAll(out) }
|
||||
}
|
||||
} catch (e: IllegalArgumentException) {
|
||||
throw IOException(e)
|
||||
|
|
|
@ -8,7 +8,12 @@ import android.text.Spanned
|
|||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.cardview.widget.CardView
|
||||
|
@ -20,7 +25,11 @@ import androidx.databinding.BindingAdapter
|
|||
import androidx.databinding.InverseBindingAdapter
|
||||
import androidx.databinding.InverseBindingListener
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.chip.Chip
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.topjohnwu.magisk.databinding
|
|||
import androidx.databinding.ListChangeRegistry
|
||||
import androidx.databinding.ObservableList
|
||||
import androidx.databinding.ObservableList.OnListChangedCallback
|
||||
import java.util.*
|
||||
import java.util.AbstractList
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.topjohnwu.magisk.R
|
|||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import java.io.File
|
||||
|
@ -29,7 +29,7 @@ class ManagerInstallDialog : MarkDownDialog() {
|
|||
setCancelable(true)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = R.string.install
|
||||
onClick { DownloadService.start(activity, Subject.App()) }
|
||||
onClick { DownloadEngine.startWithActivity(activity, Subject.App()) }
|
||||
}
|
||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
text = android.R.string.cancel
|
||||
|
|
|
@ -2,8 +2,7 @@ package com.topjohnwu.magisk.dialog
|
|||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.Action
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
@ -22,9 +21,7 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog
|
|||
dialog.apply {
|
||||
|
||||
fun download(install: Boolean) {
|
||||
val action = if (install) Action.Flash else Action.Download
|
||||
val subject = Subject.Module(item, action)
|
||||
DownloadService.start(activity, subject)
|
||||
DownloadEngine.startWithActivity(activity, Subject.Module(item, install))
|
||||
}
|
||||
|
||||
val title = context.getString(R.string.repo_install_title,
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.core.content.pm.ShortcutManagerCompat
|
|||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.MainDirections
|
||||
import com.topjohnwu.magisk.R
|
||||
|
@ -24,13 +23,10 @@ import com.topjohnwu.magisk.core.Const
|
|||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class MainViewModel : BaseViewModel()
|
||||
|
@ -62,7 +58,6 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||
setContentView()
|
||||
showUnsupportedMessage()
|
||||
askForHomeShortcut()
|
||||
checkStubComponent()
|
||||
|
||||
// Ask permission to post notifications for background update check
|
||||
if (Config.checkUpdate) {
|
||||
|
@ -231,22 +226,4 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
private fun checkStubComponent() {
|
||||
if (intent.component?.className?.contains(HideAPK.PLACEHOLDER) == true) {
|
||||
// The stub APK was not properly patched, re-apply our changes
|
||||
withPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) { granted ->
|
||||
if (granted) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val apk = File(applicationInfo.sourceDir)
|
||||
HideAPK.upgrade(this@MainActivity, apk)?.let {
|
||||
startActivity(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,23 +8,30 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.JobService
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
@SuppressLint("CustomSplashScreen")
|
||||
abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Binding>() {
|
||||
|
@ -58,7 +65,7 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||
showInvalidStateMessage()
|
||||
return@getShell
|
||||
}
|
||||
preLoad(savedInstanceState)
|
||||
initialize(savedInstanceState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +109,7 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||
}
|
||||
}
|
||||
|
||||
private fun preLoad(savedState: Bundle?) {
|
||||
private fun initialize(savedState: Bundle?) {
|
||||
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)?.let {
|
||||
// Make sure the calling package matches (prevent DoS)
|
||||
if (it == realCallingPackage)
|
||||
|
@ -112,7 +119,21 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||
}
|
||||
|
||||
Config.load(prevPkg)
|
||||
handleRepackage(prevPkg)
|
||||
|
||||
if (packageName != APPLICATION_ID) {
|
||||
runCatching {
|
||||
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
|
||||
packageManager.getApplicationInfo(APPLICATION_ID, 0)
|
||||
Shell.cmd("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
} else {
|
||||
if (Config.suManager.isNotEmpty())
|
||||
Config.suManager = ""
|
||||
if (prevPkg != null) {
|
||||
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
}
|
||||
|
||||
if (prevPkg != null) {
|
||||
runOnUiThread {
|
||||
// Relaunch the process after package migration
|
||||
|
@ -121,6 +142,31 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||
return
|
||||
}
|
||||
|
||||
// Validate stub APK
|
||||
if (isRunningAsStub && (
|
||||
// Version mismatch
|
||||
Info.stub!!.version != BuildConfig.STUB_VERSION ||
|
||||
// Not properly patched
|
||||
intent.component!!.className.contains(HideAPK.PLACEHOLDER)
|
||||
)) {
|
||||
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
|
||||
if (granted) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val apk = File(cacheDir, "stub.apk")
|
||||
try {
|
||||
assets.open("stub.apk").writeTo(apk)
|
||||
HideAPK.upgrade(this@SplashActivity, apk)?.let {
|
||||
startActivity(it)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
JobService.schedule(this)
|
||||
Shortcuts.setupDynamic(this)
|
||||
|
||||
|
@ -144,19 +190,4 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRepackage(pkg: String?) {
|
||||
if (packageName != APPLICATION_ID) {
|
||||
runCatching {
|
||||
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
|
||||
packageManager.getApplicationInfo(APPLICATION_ID, 0)
|
||||
Shell.cmd("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
} else {
|
||||
if (Config.suManager.isNotEmpty())
|
||||
Config.suManager = ""
|
||||
pkg ?: return
|
||||
Shell.cmd("(pm uninstall $pkg)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@ import android.annotation.SuppressLint
|
|||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ComponentInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.*
|
||||
import android.content.pm.PackageManager.GET_ACTIVITIES
|
||||
import android.content.pm.PackageManager.GET_PROVIDERS
|
||||
import android.content.pm.PackageManager.GET_RECEIVERS
|
||||
import android.content.pm.PackageManager.GET_SERVICES
|
||||
import android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
|
@ -12,7 +17,7 @@ import android.os.Build.VERSION.SDK_INT
|
|||
import androidx.core.os.ProcessCompat
|
||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import java.util.*
|
||||
import java.util.TreeSet
|
||||
|
||||
class CmdlineListItem(line: String) {
|
||||
val packageName: String
|
||||
|
|
|
@ -5,7 +5,11 @@ import android.content.Context
|
|||
import android.content.pm.ActivityInfo
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
|
|
|
@ -72,6 +72,7 @@ class FlashViewModel : BaseViewModel() {
|
|||
MagiskInstaller.Direct(outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.FLASH_INACTIVE_SLOT -> {
|
||||
showReboot = false
|
||||
MagiskInstaller.SecondSlot(outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.PATCH_FILE -> {
|
||||
|
|
|
@ -14,7 +14,7 @@ import com.topjohnwu.magisk.R
|
|||
import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
|
||||
|
||||
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
||||
|
@ -25,7 +25,7 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
|||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.setTitle(R.string.section_home)
|
||||
DownloadService.observeProgress(this, viewModel::onProgressUpdate)
|
||||
DownloadEngine.observeProgress(this, viewModel::onProgressUpdate)
|
||||
}
|
||||
|
||||
private fun checkTitle(text: TextView, icon: ImageView) {
|
||||
|
|
|
@ -7,6 +7,8 @@ import android.view.MenuItem
|
|||
import android.widget.PopupMenu
|
||||
import androidx.core.content.getSystemService
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.ktx.reboot as systemReboot
|
||||
|
||||
|
@ -20,6 +22,11 @@ object RebootMenu {
|
|||
R.id.action_reboot_download -> systemReboot("download")
|
||||
R.id.action_reboot_edl -> systemReboot("edl")
|
||||
R.id.action_reboot_recovery -> systemReboot("recovery")
|
||||
R.id.action_reboot_safe_mode -> {
|
||||
val status = !item.isChecked
|
||||
item.isChecked = status
|
||||
Config.bootloop = if (status) 2 else 0
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
return true
|
||||
|
@ -29,10 +36,16 @@ object RebootMenu {
|
|||
val themeWrapper = ContextThemeWrapper(activity, R.style.Foundation_PopupMenu)
|
||||
val menu = PopupMenu(themeWrapper, activity.findViewById(R.id.action_reboot))
|
||||
activity.menuInflater.inflate(R.menu.menu_reboot, menu.menu)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true)
|
||||
menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true
|
||||
menu.setOnMenuItemClickListener(RebootMenu::reboot)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true) {
|
||||
menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true
|
||||
}
|
||||
if (Const.Version.isCanary()) {
|
||||
menu.menu.findItem(R.id.action_reboot_safe_mode).isChecked = Config.bootloop >= 2
|
||||
} else {
|
||||
menu.menu.findItem(R.id.action_reboot_safe_mode).isVisible = false
|
||||
}
|
||||
return menu
|
||||
}
|
||||
|
||||
|
|
|
@ -227,25 +227,14 @@ object Zygisk : BaseSettingsItem.Toggle() {
|
|||
get() = Config.zygisk
|
||||
set(value) {
|
||||
Config.zygisk = value
|
||||
DenyList.isEnabled = value
|
||||
DenyListConfig.isEnabled = value
|
||||
notifyPropertyChanged(BR.description)
|
||||
DenyList.notifyPropertyChanged(BR.description)
|
||||
}
|
||||
val mismatch get() = value != Info.isZygiskEnabled
|
||||
}
|
||||
|
||||
object DenyList : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_denylist_title.asText()
|
||||
override val description get() =
|
||||
if (isEnabled) {
|
||||
if (Zygisk.mismatch)
|
||||
R.string.reboot_apply_change.asText()
|
||||
else
|
||||
R.string.settings_denylist_summary.asText()
|
||||
} else {
|
||||
R.string.settings_denylist_error.asText(R.string.zygisk.asText())
|
||||
}
|
||||
override val description get() = R.string.settings_denylist_summary.asText()
|
||||
|
||||
override var value = Config.denyList
|
||||
set(value) {
|
||||
|
@ -260,18 +249,11 @@ object DenyList : BaseSettingsItem.Toggle() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun refresh() {
|
||||
isEnabled = Zygisk.value
|
||||
}
|
||||
}
|
||||
|
||||
object DenyListConfig : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.settings_denylist_config_title.asText()
|
||||
override val description = R.string.settings_denylist_config_summary.asText()
|
||||
override fun refresh() {
|
||||
isEnabled = Zygisk.value
|
||||
}
|
||||
}
|
||||
|
||||
// --- Superuser
|
||||
|
|
|
@ -11,7 +11,7 @@ import androidx.core.content.getSystemService
|
|||
import androidx.core.graphics.drawable.toIcon
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.core.ktx.getBitmap
|
||||
import com.topjohnwu.magisk.core.ktx.selfLaunchIntent
|
||||
|
@ -67,7 +67,7 @@ object Notifications {
|
|||
|
||||
fun updateAvailable() {
|
||||
AppContext.apply {
|
||||
val intent = DownloadService.getPendingIntent(this, Subject.App())
|
||||
val intent = DownloadEngine.getPendingIntent(this, Subject.App())
|
||||
val bitmap = getBitmap(R.drawable.ic_magisk_outline)
|
||||
val builder = if (SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Notification.Builder(this, UPDATE_CHANNEL)
|
||||
|
|
|
@ -26,4 +26,9 @@
|
|||
android:id="@+id/action_reboot_edl"
|
||||
android:title="@string/reboot_edl" />
|
||||
|
||||
</menu>
|
||||
<item
|
||||
android:id="@+id/action_reboot_safe_mode"
|
||||
android:checkable="true"
|
||||
android:title="@string/reboot_safe_mode" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -14,7 +14,7 @@ env_check() {
|
|||
[ -f "$MAGISKBIN/magiskpolicy" ] || return 1
|
||||
fi
|
||||
if [ "$2" -ge 25210 ]; then
|
||||
[ -b "$MAGISKTMP/.magisk/block/preinit" ] || return 2
|
||||
[ -b "$MAGISKTMP/.magisk/device/preinit" ] || [ -b "$MAGISKTMP/.magisk/block/preinit" ] || return 2
|
||||
fi
|
||||
grep -xqF "MAGISK_VER='$1'" "$MAGISKBIN/util_functions.sh" || return 3
|
||||
grep -xqF "MAGISK_VER_CODE=$2" "$MAGISKBIN/util_functions.sh" || return 3
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
<string name="install">Installieren</string>
|
||||
<string name="section_home">Startseite</string>
|
||||
<string name="section_theme">Themen</string>
|
||||
<string name="denylist">Verweigerungsliste</string>
|
||||
<string name="denylist">Ausnahmeliste</string>
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">Keine Verbindung verfügbar</string>
|
||||
<string name="app_changelog">Änderungen</string>
|
||||
<string name="loading">Laden …</string>
|
||||
<string name="update">Aktualisieren</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="not_available">Nicht verfügbar</string>
|
||||
<string name="hide">Verstecken</string>
|
||||
<string name="home_package">Paket</string>
|
||||
<string name="home_app_title">App</string>
|
||||
|
@ -88,6 +88,9 @@
|
|||
<string name="logs_cleared">Protokoll erfolgreich gelöscht.</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Ziel-UID: %1$d</string>
|
||||
<string name="target_pid">NS Target PID einbinden: %s</string>
|
||||
<string name="selinux_context">SELinux Kontext: %s</string>
|
||||
<string name="supp_group">Ergänzende Gruppe: %s</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
|
@ -138,11 +141,11 @@
|
|||
<string name="settings_update_custom">Benutzerdefiniert</string>
|
||||
<string name="settings_update_custom_msg">Benutzerdefinierte URL einfügen</string>
|
||||
<string name="settings_zygisk_summary">Teile von Magisk im Zygoten-Daemon ausführen</string>
|
||||
<string name="settings_denylist_title">Verweigerungsliste erzwingen</string>
|
||||
<string name="settings_denylist_summary">Bei Prozessen, die auf der Verweigerungsliste stehen, werden alle Magisk-Änderungen rückgängig gemacht.</string>
|
||||
<string name="settings_denylist_title">Ausnahmeliste erzwingen</string>
|
||||
<string name="settings_denylist_summary">Bei Prozessen, die auf der Ausnahmeliste stehen, werden alle Magisk-Änderungen rückgängig gemacht.</string>
|
||||
<string name="settings_denylist_error">Für diese Funktion muss %1$s aktiviert sein</string>
|
||||
<string name="settings_denylist_config_title">Verweigerungsliste konfigurieren</string>
|
||||
<string name="settings_denylist_config_summary">Auswahl der Prozesse, die in die Verweigerungsliste aufgenommen werden sollen</string>
|
||||
<string name="settings_denylist_config_title">Ausnahmeliste konfigurieren</string>
|
||||
<string name="settings_denylist_config_summary">Auswahl der Prozesse, die in die Ausnahmeliste aufgenommen werden sollen</string>
|
||||
<string name="settings_hosts_title">Systemlose Hosts-Datei</string>
|
||||
<string name="settings_hosts_summary">Systemlose Unterstützung für Werbeblocker</string>
|
||||
<string name="settings_hosts_toast">Systemloses Hosts-Modul hinzugefügt</string>
|
||||
|
@ -167,6 +170,9 @@
|
|||
<string name="settings_su_reauth_summary">Superuser-Berechtigungen nach App-Aktualisierung erneut authentifizieren</string>
|
||||
<string name="settings_su_tapjack_title">Tapjacking-Schutz aktivieren</string>
|
||||
<string name="settings_su_tapjack_summary">Das Dialogfeld der Superuser-Eingabeaufforderung reagiert nicht auf Eingaben, wenn es durch ein anderes Fenster oder Überlagerung verdeckt wird</string>
|
||||
<string name="settings_su_auth_title">Benutzerauthentifizierung</string>
|
||||
<string name="settings_su_auth_summary">Nachfrage nach Benutzerauthentifizierung bei Superuser-Anfragen</string>
|
||||
<string name="settings_su_auth_insecure">Auf dem Gerät ist keine Authentifizierungsmethode konfiguriert</string>>
|
||||
<string name="settings_customization">Personalisierung</string>
|
||||
<string name="setting_add_shortcut_summary">Hinzufügen einer hübschen Startbildschirm-Verknüpfung, falls der Name und das Symbol nach dem Ausblenden der App schwer zu erkennen sind</string>
|
||||
<string name="settings_doh_title">DNS über HTTPS</string>
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
<string name="hide">Ocultar</string>
|
||||
<string name="home_package">Nombre de paquete:</string>
|
||||
<string name="home_app_title">App</string>
|
||||
|
||||
<string name="home_notice_content">Descarga Magisk únicamente desde la página oficial de GitHub. ¡Las descargas desde fuentes desconocidas pueden ser maliciosas!</string>
|
||||
<string name="home_support_title">Apóyanos</string>
|
||||
<string name="home_follow_title">Síguenos</string>
|
||||
|
@ -75,7 +74,6 @@
|
|||
<string name="su_revoke_msg">Confirma para revocarle los privilegios de superusuario a %1$s</string>
|
||||
<string name="toast">Mensaje emergente</string>
|
||||
<string name="none">Ninguno</string>
|
||||
|
||||
<string name="superuser_toggle_notification">Notificaciones</string>
|
||||
<string name="superuser_toggle_revoke">Revocar</string>
|
||||
<string name="superuser_policy_none">Ninguna app ha solicitado privilegios de superusuario aún.</string>
|
||||
|
@ -87,7 +85,10 @@
|
|||
<string name="menuClearLog">Limpiar registro</string>
|
||||
<string name="logs_cleared">Registros limpiados correctamente</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Target UID: %1$d</string>
|
||||
<string name="target_uid">Objetivo UID: %1$d</string>
|
||||
<string name="target_pid">Montar ns objetivo PID: %s</string>
|
||||
<string name="selinux_context">Contexto SELinux: %s</string>
|
||||
<string name="supp_group">Grupo suplementario: %s</string>
|
||||
|
||||
<!--SafetyNet/PlayIntegrity-->
|
||||
|
||||
|
@ -167,11 +168,13 @@
|
|||
<string name="settings_su_reauth_summary">Las apps volverán a solicitar privilegios de superusuario tras actualizarse</string>
|
||||
<string name="settings_su_tapjack_title">Protección contra tapjacking</string>
|
||||
<string name="settings_su_tapjack_summary">No podrás interactuar con las solicitudes de superusuario mientras estén tapadas por cualquier otra ventana o superposición</string>
|
||||
<string name="settings_su_auth_title">Autenticación de usuario</string>
|
||||
<string name="settings_su_auth_summary">Preguntar por la autenticación de usuario durante las peticiones de Superusuario</string>
|
||||
<string name="settings_su_auth_insecure">No hay método de autenticación configurado en el dispositivo</string>
|
||||
<string name="settings_customization">Personalización</string>
|
||||
<string name="setting_add_shortcut_summary">Añade un atajo a la app con el ícono de Magisk a la pantalla de inicio en caso de que te resulte difícil reconocerla tras haberle cambiado el nombre y el ícono</string>
|
||||
<string name="settings_doh_title">DNS sobre HTTPS</string>
|
||||
<string name="settings_doh_description">Proporciona una solución alternativa (workaround) contra el envenenamiento de DNS en algunos países</string>
|
||||
|
||||
<string name="multiuser_mode">Modo multiusuario</string>
|
||||
<string name="settings_owner_only">Propietario del dispositivo</string>
|
||||
<string name="settings_owner_manage">Administrado por el propietario del dispositivo</string>
|
||||
|
@ -179,7 +182,6 @@
|
|||
<string name="owner_only_summary">Solo el administrador tiene acceso root</string>
|
||||
<string name="owner_manage_summary">Solo el administrador puede manipular y recibir solicitudes de superusuario</string>
|
||||
<string name="user_independent_summary">Cada usuario tiene sus propias reglas y acceso al root</string>
|
||||
|
||||
<string name="mount_namespace_mode">Modo del namespace de montaje</string>
|
||||
<string name="settings_ns_global">Namespace global</string>
|
||||
<string name="settings_ns_requester">Namespace heredado</string>
|
||||
|
@ -238,4 +240,4 @@
|
|||
<string name="reboot_apply_change">Reinicia para aplicar los cambios</string>
|
||||
<string name="restore_app_confirmation">Se restaurará la app oculta de vuelta a la original. ¿Quieres continuar?</string>
|
||||
|
||||
</resources>
|
||||
</resources>
|
|
@ -165,6 +165,9 @@
|
|||
<string name="settings_su_reauth_summary">Richiedi nuovamente i permessi di root dopo l\'aggiornamento di un\'app</string>
|
||||
<string name="settings_su_tapjack_title">Protezione anti-tapjacking</string>
|
||||
<string name="settings_su_tapjack_summary">La schermata di richiesta dei permessi di root non risponderà al tocco mentre è oscurata da altre finestre o elementi in sovraimpressione</string>
|
||||
<string name="settings_su_auth_title">Autenticazione utente</string>
|
||||
<string name="settings_su_auth_summary">Richiedi l\'autenticazione dell\'utente per le richieste di accesso root</string>
|
||||
<string name="settings_su_auth_insecure">Sul dispositivo non è configurato alcun metodo di autenticazione</string>
|
||||
<string name="settings_customization">Personalizzazione</string>
|
||||
<string name="setting_add_shortcut_summary">Aggiungi un collegamento alla schermata iniziale se il nome e l\'icona sono difficili da riconoscere dopo aver nascosto l\'app</string>
|
||||
<string name="settings_doh_title">DNS over HTTPS</string>
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
<string name="settings_su_reauth_summary">アプリのアップグレード後にスーパーユーザー権限を再認証します</string>
|
||||
<string name="settings_su_tapjack_title">タップジャッキング保護を有効にする</string>
|
||||
<string name="settings_su_tapjack_summary">他のウィンドウやオーバーレイで表示されている間は、スーパーユーザー権限の要求ダイアログが入力に応答しないようにします</string>
|
||||
<string name="settings_su_auth_title">ユーザー認証</string>
|
||||
<string name="settings_su_auth_summary">スーパーユーザー権限の要求でユーザー認証を行ないます</string>
|
||||
<string name="settings_su_auth_insecure">端末の認証方法が設定されていません</string>
|
||||
<string name="settings_customization">カスタマイズ</string>
|
||||
<string name="setting_add_shortcut_summary">アプリを隠した後に見つけられなくなったときは、ここでホーム画面にショートカットを追加できます</string>
|
||||
<string name="settings_doh_title">DNS over HTTPS</string>
|
||||
|
|
|
@ -182,7 +182,7 @@
|
|||
<string name="settings_ns_isolate">격리된 네임스페이스</string>
|
||||
<string name="global_summary">모든 루트 세션이 전역 마운트 네임스페이스를 사용합니다.</string>
|
||||
<string name="requester_summary">루트 세션은 요청자의 네임스페이스를 상속합니다.</string>
|
||||
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 네임스페이를를 사용합니다.</string>
|
||||
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 네임스페이스를 사용합니다.</string>
|
||||
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">Magisk 업데이트</string>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<string name="home_notice_content">ഔദ്യോഗിക ഗിറ്റ്ഹബ് പേജിൽ നിന്ന് മാത്രം മജിസ്ക് ഡൗൺലോഡ് ചെയ്യുക. അജ്ഞാത ഉറവിടങ്ങളിൽ നിന്നുള്ള ഫയലുകൾ ക്ഷുദ്രകരമാകാം!</string>
|
||||
<string name="home_support_title">ഞങ്ങളെ തുണയ്ക്കുക</string>
|
||||
<string name="home_follow_title">ഞങ്ങളെ പിന്തുടരുക</string>
|
||||
<string name="home_follow_title">ഞങ്ങളെ ഫോളോ ചെയ്യുക</string>
|
||||
<string name="home_item_source">സോഴ്സ്</string>
|
||||
<string name="home_support_content">മജിസ്ക് എല്ലായ്പ്പോഴും സ്വതന്ത്രവും ഓപ്പൺ സോഴ്സും ആയിരിക്കും. എന്നിരുന്നാലും, ഒരു സംഭാവന നൽകിക്കൊണ്ട് നിങ്ങൾ പിന്തുണയ്ക്കുന്നുവെന്ന് ഞങ്ങളെ കാണിക്കാനാകും.</string>
|
||||
<string name="home_installed_version">ഇൻസ്റ്റാൾ ചെയ്ത പതിപ്പ്</string>
|
||||
|
@ -58,7 +58,7 @@
|
|||
<string name="grant">അനുവദിക്കുക</string>
|
||||
<string name="su_warning">നിങ്ങളുടെ ഉപകരണത്തിലേക്ക് പൂർണ്ണ ആക്സസ് നൽകും.\nനിങ്ങൾക്ക് ഉറപ്പില്ലെങ്കിൽ നിരസിക്കുക!</string>
|
||||
<string name="forever">എന്നേക്കും</string>
|
||||
<string name="once">ഒരിക്കല്</string>
|
||||
<string name="once">ഒരിക്കൽ</string>
|
||||
<string name="tenmin">10 മിനിറ്റ്</string>
|
||||
<string name="twentymin">20 മിനിറ്റ്</string>
|
||||
<string name="thirtymin">30 മിനിറ്റ്</string>
|
||||
|
@ -133,8 +133,8 @@
|
|||
<string name="settings_update_channel_title">അപ്ഡേറ്റിനുള്ള ചാനൽ</string>
|
||||
<string name="settings_update_stable">സ്റ്റേബിൾ</string>
|
||||
<string name="settings_update_beta">ബീറ്റ</string>
|
||||
<string name="settings_update_custom">കസ്റ്റമ്</string>
|
||||
<string name="settings_update_custom_msg">കസ്റ്റമ് ചാനലിന്റെ URL ചേർക്കുക</string>
|
||||
<string name="settings_update_custom">കസ്റ്റം</string>
|
||||
<string name="settings_update_custom_msg">കസ്റ്റം ചാനലിന്റെ URL ചേർക്കുക</string>
|
||||
<string name="settings_zygisk_summary">സൈഗോട്ട് ഡെമണിൽ മജിസ്കിന്റെ ഭാഗങ്ങൾ പ്രവർത്തിപ്പിക്കുക</string>
|
||||
<string name="settings_denylist_title">നിഷിദ്ധ പട്ടിക പ്രാബല്യത്തിലാകുക</string>
|
||||
<string name="settings_denylist_summary">നിഷിദ്ധ പട്ടികയിലെ പ്രോസസ്സുകൾക്കായി എല്ലാ മജിസ്ക് പരിഷ്ക്കരണങ്ങളും പഴയപടിയാക്കും</string>
|
||||
|
@ -165,10 +165,10 @@
|
|||
<string name="settings_su_reauth_summary">ആപ്പുകൾ അപ്ഗ്രേഡ് ചെയ്തതിന് ശേഷം സൂപ്പർയൂസർ അനുമതികൾക്കായി വീണ്ടും ആവശ്യപ്പെടുക</string>
|
||||
<string name="settings_su_tapjack_title">ടാപ്പ്ജാക്കിംഗ് സംരക്ഷണം</string>
|
||||
<string name="settings_su_tapjack_summary">സൂപ്പർയൂസർ പ്രോംപ്റ്റ് ഡയലോഗ് മറ്റേതെങ്കിലും വിൻഡോയോ ഓവർലേയോ മറയ്ക്കുമ്പോൾ ഇൻപുട്ടിനോട് പ്രതികരിക്കില്</string>
|
||||
<string name="settings_customization">Customization</string>
|
||||
<string name="settings_customization">കസ്റ്റമയിസേഷൻ</string>
|
||||
<string name="setting_add_shortcut_summary">ആപ്പ് മറച്ചതിന് ശേഷം പേരും ഐക്കണും തിരിച്ചറിയാൻ പ്രയാസമാണെങ്കിൽ ഹോം സ്ക്രീനിലേക്ക് മനോഹരമായ ഒരു ഷോർട്ട്ക്കട് ചേർക്കുക</string>
|
||||
<string name="settings_doh_title">DNS ഓവർ HTTPS</string>
|
||||
<string name="settings_doh_description">ചില രാജ്യങ്ങളിൽ DNS പോയ്സണിങിന് പരിഹാരം</string>
|
||||
<string name="settings_doh_description">ചില രാജ്യങ്ങളിലെ DNS പോയ്സണിങിന് പരിഹാരം</string>
|
||||
|
||||
<string name="multiuser_mode">മൾട്ടിയൂസർ മോഡ്</string>
|
||||
<string name="settings_owner_only">ഉപകരണ ഉടമ മാത്രം</string>
|
||||
|
@ -229,7 +229,7 @@
|
|||
<string name="external_rw_permission_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ സ്റ്റോറജ് അനുമതി നൽകുക</string>
|
||||
<string name="post_notifications_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ അറിയിപ്പ് അനുമതി നൽകുക</string>
|
||||
<string name="install_unknown_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ "install unknown apps" അനുവദിക്കുക</string>
|
||||
<string name="add_shortcut_title">ഹോം സ്ക്രീനിലേക്ക് ഷോർറ്റ്കറ്റ് ചേർക്കുക</string>
|
||||
<string name="add_shortcut_title">ഹോം സ്ക്രീനിലേക്ക് ഷോർട്ട്കട്ട് ചേർക്കുക</string>
|
||||
<string name="add_shortcut_msg">ഈ ആപ്പ് മറച്ചതിന് ശേഷം, അതിന്റെ പേരും ഐക്കണും തിരിച്ചറിയാൻ ബുദ്ധിമുട്ടായേക്കാം. ഹോം സ്ക്രീനിലേക്ക് മനോഹരമായ ഒരു ഷോർറ്റ്കറ്റ ചേർക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?</string>
|
||||
<string name="app_not_found">ഈ പ്രവർത്തനം കൈകാര്യം ചെയ്യാൻ ഒരു ആപ്പും കണ്ടെത്തിയില്ല</string>
|
||||
<string name="reboot_apply_change">മാറ്റങ്ങൾ പ്രയോഗിക്കാൻ റീബൂട്ട് ചെയ്യുക</string>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<string name="install">Instaluj</string>
|
||||
<string name="section_home">Strona główna</string>
|
||||
<string name="section_theme">Motywy</string>
|
||||
<string name="denylist">Lista odmów</string>
|
||||
<string name="denylist">Lista odmów (DenyList)</string>
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">Połączenie niedostępne</string>
|
||||
|
@ -28,8 +28,8 @@
|
|||
<string name="home_installed_version">Zainstalowany</string>
|
||||
<string name="home_latest_version">Ostatni</string>
|
||||
<string name="invalid_update_channel">Nieprawidłowy kanał aktualizacji</string>
|
||||
<string name="uninstall_magisk_title">Odinstaluj Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Wszystkie moduły zostaną wyłączone/usunięte!\nRoot zostanie usunięty!\nTwoje dane mogą zostać potencjalnie zaszyfrowane, jeśli jeszcze nie są!</string>
|
||||
<string name="uninstall_magisk_title">Odinstalowywanie Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Wszystkie moduły zostaną wyłączone/usunięte!\nRoot zostanie usunięty!\nWszelka wewnętrzna pamięć niezaszyfrowana w związku z użytkowaniem Magisk zostanie ponownie zaszyfrowana!</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">Zachowaj force encryption (wymuszenie szyfrowania)</string>
|
||||
|
@ -40,23 +40,23 @@
|
|||
<string name="install_method_title">Metoda</string>
|
||||
<string name="install_next">Dalej</string>
|
||||
<string name="install_start">Zaczynajmy</string>
|
||||
<string name="manager_download_install">Naciśnij, aby pobrać i zainstalować</string>
|
||||
<string name="manager_download_install">Kliknij, aby pobrać i zainstalować</string>
|
||||
<string name="direct_install">Bezpośrednia instalacja (zalecana)</string>
|
||||
<string name="install_inactive_slot">Zainstaluj w nieaktywnym gnieździe (po OTA)</string>
|
||||
<string name="install_inactive_slot_msg">Po restarcie twoje urządzenie zostanie ZMUSZONE do rozruchu z aktualnie nieaktywnego gniazda!\nUżyj tej opcji wyłącznie po ukończeniu aktualizacji OTA.\nKontynuować?</string>
|
||||
<string name="install_inactive_slot">Zainstaluj w nieaktywnym slocie (po OTA)</string>
|
||||
<string name="install_inactive_slot_msg">Po ponownym uruchomieniu twoje urządzenie zostanie ZMUSZONE do rozruchu z aktualnie nieaktywnego slotu!\nUżywaj tej opcji tylko po ukończeniu aktualizacji OTA.\nKontynuować?</string>
|
||||
<string name="setup_title">Dodatkowa konfiguracja</string>
|
||||
<string name="select_patch_file">Wybierz i załataj plik</string>
|
||||
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik tar ODIN (*.tar)</string>
|
||||
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik tar ODIN (*.tar) lub payload.bin (*.bin)</string>
|
||||
<string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string>
|
||||
<string name="flash_screen_title">Instalacja</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Żądanie dostępu do Superusera</string>
|
||||
<string name="touch_filtered_warning">Ponieważ zapytanie o Superuser aplikacji jest przysłonięte, Magisk nie może zweryfikować twojej odpowiedzi.</string>
|
||||
<string name="touch_filtered_warning">Ponieważ aplikacja zasłania żądanie o Superusera, Magisk nie może zweryfikować twojej odpowiedzi</string>
|
||||
<string name="deny">Odmów</string>
|
||||
<string name="prompt">Zapytaj</string>
|
||||
<string name="grant">Zezwól</string>
|
||||
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów jeśli nie jesteś pewien!</string>
|
||||
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów, jeżeli nie jesteś pewien!</string>
|
||||
<string name="forever">Zawsze</string>
|
||||
<string name="once">Raz</string>
|
||||
<string name="tenmin">10 min</string>
|
||||
|
@ -66,28 +66,31 @@
|
|||
<string name="su_allow_toast">%1$s otrzymał uprawnienia Superusera</string>
|
||||
<string name="su_deny_toast">%1$s odmówiono uprawnień Superusera</string>
|
||||
<string name="su_snack_grant">Przyznano uprawnienia Superusera dla %1$s</string>
|
||||
<string name="su_snack_deny">Odmówiono uprawnień Superusera dla %1$s</string>
|
||||
<string name="su_snack_deny">Unieważniono uprawnienia Superusera dla %1$s</string>
|
||||
<string name="su_snack_notif_on">Włączono powiadomienia dla %1$s</string>
|
||||
<string name="su_snack_notif_off">Wyłączono powiadomienia dla %1$s</string>
|
||||
<string name="su_snack_log_on">Włączono logowanie dla %1$s</string>
|
||||
<string name="su_snack_log_off">Wyłączono logowanie dla %1$s</string>
|
||||
<string name="su_revoke_title">Odwołać?</string>
|
||||
<string name="su_revoke_msg">Potwierdzasz odwołanie uprawnień dla %1$s?</string>
|
||||
<string name="su_revoke_title">Unieważnić?</string>
|
||||
<string name="su_revoke_msg">Potwierdź, aby unieważnić uprawnienia Superusera dla %1$s</string>
|
||||
<string name="toast">Wyskakujące powiadomienie</string>
|
||||
<string name="none">Brak</string>
|
||||
|
||||
<string name="superuser_toggle_notification">Powiadomienia</string>
|
||||
<string name="superuser_toggle_revoke">Odwołaj</string>
|
||||
<string name="superuser_toggle_revoke">Unieważnij</string>
|
||||
<string name="superuser_policy_none">Żadna aplikacja nie poprosiła jeszcze o uprawnienia Superusera.</string>
|
||||
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">Logi są puste, spróbuj użyć aplikacji wymagających roota.</string>
|
||||
<string name="log_data_magisk_none">Logi Magisk są puste, to jest dziwne.</string>
|
||||
<string name="log_data_none">Nie masz żadnych logów, spróbuj użyć aplikacji wymagających roota</string>
|
||||
<string name="log_data_magisk_none">Logi Magisk są puste, to jest dziwne</string>
|
||||
<string name="menuSaveLog">Zapisz log</string>
|
||||
<string name="menuClearLog">Wyczyść log</string>
|
||||
<string name="logs_cleared">Log został pomyślnie wyczyszczony.</string>
|
||||
<string name="logs_cleared">Log został pomyślnie wyczyszczony</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Docelowy UID: %1$d</string>
|
||||
<string name="target_pid">Docelowy PID p.n. montowania: %s</string>
|
||||
<string name="selinux_context">Kontekst SELinux: %s</string>
|
||||
<string name="supp_group">Grupa uzupełniająca: %s</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
|
@ -98,7 +101,7 @@
|
|||
<string name="hide_search">Szukaj</string>
|
||||
|
||||
<!--Module -->
|
||||
<string name="no_info_provided">(Nie umieszczono informacji)</string>
|
||||
<string name="no_info_provided">(Brak informacji)</string>
|
||||
<string name="reboot_userspace">Miękki reboot</string>
|
||||
<string name="reboot_recovery">Reboot do trybu Recovery</string>
|
||||
<string name="reboot_bootloader">Reboot do trybu Bootloader</string>
|
||||
|
@ -109,11 +112,11 @@
|
|||
<string name="module_state_restore">Przywróć</string>
|
||||
<string name="module_action_install_external">Zainstaluj z pamięci</string>
|
||||
<string name="update_available">Dostępna aktualizacja</string>
|
||||
<string name="suspend_text_riru">Moduł uśpiony ponieważ %1$s jest włączony</string>
|
||||
<string name="suspend_text_zygisk">Moduł uśpiony ponieważ %1$s jest wyłączony</string>
|
||||
<string name="zygisk_module_unloaded">Moduł Zygisk nie załadowany ze względu na niekompatybilność</string>
|
||||
<string name="module_empty">Żaden moduł nie jest zainstalowany</string>
|
||||
<string name="confirm_install">Zainstaloać moduł %1$s?</string>
|
||||
<string name="suspend_text_riru">Moduł jest zawieszony, ponieważ %1$s jest włączony</string>
|
||||
<string name="suspend_text_zygisk">Moduł jest zawieszony, ponieważ %1$s nie jest włączony</string>
|
||||
<string name="zygisk_module_unloaded">Moduł Zygisk nie został załadowany z powodu niekompatybilności</string>
|
||||
<string name="module_empty">Brak zainstalowanych modułów</string>
|
||||
<string name="confirm_install">Zainstalować moduł %1$s?</string>
|
||||
<string name="confirm_install_title">Potwierdzenie instalacji</string>
|
||||
|
||||
<!--Settings -->
|
||||
|
@ -125,7 +128,7 @@
|
|||
<string name="settings_download_path_title">Ścieżka pobierania plików</string>
|
||||
<string name="settings_download_path_message">Pliki zostaną zapisane do %1$s</string>
|
||||
<string name="settings_hide_app_title">Ukryj aplikację Magisk</string>
|
||||
<string name="settings_hide_app_summary">Zainstaluj aplikację z losowym ID pakietu i własną etykietą.</string>
|
||||
<string name="settings_hide_app_summary">Zainstaluj aplikację proxy z losowym ID pakietu i własną etykietą</string>
|
||||
<string name="settings_restore_app_title">Przywróć aplikację Magisk</string>
|
||||
<string name="settings_restore_app_summary">Przestań ukrywać aplikację i przywróć oryginalny plik APK</string>
|
||||
<string name="language">Język</string>
|
||||
|
@ -137,18 +140,18 @@
|
|||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Własny kanał</string>
|
||||
<string name="settings_update_custom_msg">Wprowadź adres URL własnego kanału</string>
|
||||
<string name="settings_zygisk_summary">Uruchom cześć Magiska w zygocie Demona</string>
|
||||
<string name="settings_denylist_title">Wymuś Listę Odmów</string>
|
||||
<string name="settings_denylist_summary">Procesy z Listy Odmów będą miały wszystkie modyfikacje Magisk cofnięte</string>
|
||||
<string name="settings_denylist_error">Ta funkcja wymaga aby %1$s było włączone</string>
|
||||
<string name="settings_denylist_config_title">Ustaw Listę Odmów</string>
|
||||
<string name="settings_denylist_config_summary">Wybierz proces który ma zostać zawarty w Liście Odmów</string>
|
||||
<string name="settings_zygisk_summary">Uruchom część Magisk w demonie zygote</string>
|
||||
<string name="settings_denylist_title">Egzekwowanie listy odmów (DenyList)</string>
|
||||
<string name="settings_denylist_summary">Procesy znajdujące się na liście odmów (DenyList) będą miały cofnięte wszystkie modyfikacje Magisk</string>
|
||||
<string name="settings_denylist_error">Ta funkcja wymaga, aby %1$s było włączone</string>
|
||||
<string name="settings_denylist_config_title">Konfiguracja listy odmów (DenyList)</string>
|
||||
<string name="settings_denylist_config_summary">Wybierz procesy, które mają się znajdować na liście odmów (DenyList)</string>
|
||||
<string name="settings_hosts_title">Hosty Systemless</string>
|
||||
<string name="settings_hosts_summary">Wsparcie hostów Systemless dla aplikacji typu Adblock</string>
|
||||
<string name="settings_hosts_summary">Wsparcie hostów Systemless dla aplikacji blokujących reklamy</string>
|
||||
<string name="settings_hosts_toast">Dodano moduł hostów Systemless</string>
|
||||
<string name="settings_app_name_hint">Nowa nazwa</string>
|
||||
<string name="settings_app_name_helper">Aplikacja zostanie przepakowana do tej nazwy</string>
|
||||
<string name="settings_app_name_error">Błędny format</string>
|
||||
<string name="settings_app_name_helper">Aplikacja zostanie przepakowana z tą nazwą</string>
|
||||
<string name="settings_app_name_error">Nieprawidłowy format</string>
|
||||
<string name="settings_su_app_adb">Aplikacje i ADB</string>
|
||||
<string name="settings_su_app">Tylko aplikacje</string>
|
||||
<string name="settings_su_adb">Tylko ADB</string>
|
||||
|
@ -164,20 +167,23 @@
|
|||
<string name="request_timeout">Limit czasu żądania</string>
|
||||
<string name="superuser_notification">Powiadomienia Superusera</string>
|
||||
<string name="settings_su_reauth_title">Ponowienie uwierzytelniania po aktualizacji</string>
|
||||
<string name="settings_su_reauth_summary">Ponowienie dostępu do uprawnień Superusera po uaktualnieniu aplikacji</string>
|
||||
<string name="settings_su_tapjack_title">Włącz ochronę przed Tapjacking (niezamierzone kliknięcie)</string>
|
||||
<string name="settings_su_tapjack_summary">Pytanie o Superuser nie będzie reagować na odpowiedź jeżeli będzie zasłonięte lub przyćmione.</string>
|
||||
<string name="settings_su_reauth_summary">Zapytaj ponownie o uprawnienia Superusera po uaktualnieniu aplikacji</string>
|
||||
<string name="settings_su_tapjack_title">Ochrona przed Tapjackingiem (niezamierzonym kliknięciem)</string>
|
||||
<string name="settings_su_tapjack_summary">Okno dialogowe z żądaniem Superusera nie będzie reagować na odpowiedź, jeżeli będzie zasłonięte przez inne okno lub nakładkę</string>
|
||||
<string name="settings_su_auth_title">Uwierzytelnianie użytkownika</string>
|
||||
<string name="settings_su_auth_summary">Pytaj o uwierzytelnienie użytkownika podczas żądań Superusera</string>
|
||||
<string name="settings_su_auth_insecure">Nie skonfigurowano żadnej metody uwierzytelniania na tym urządzeniu</string>
|
||||
<string name="settings_customization">Personalizacja</string>
|
||||
<string name="setting_add_shortcut_summary">Dodaj ładny skrót na ekranie głównym na wypadek, gdyby nazwa i ikona były trudne do rozpoznania po ukryciu aplikacji</string>
|
||||
<string name="setting_add_shortcut_summary">Umieść ładny skrót na ekranie głównym na wypadek, gdyby nazwa i ikona były trudne do rozpoznania po ukryciu aplikacji</string>
|
||||
<string name="settings_doh_title">DNS over HTTPS</string>
|
||||
<string name="settings_doh_description">Zapobiegaj zatruwaniu DNS (DNS poisoning) w niektórych krajach</string>
|
||||
|
||||
<string name="multiuser_mode">Tryb wielu użytkowników (Multiuser)</string>
|
||||
<string name="settings_owner_only">Tylko właściciel urządzenia</string>
|
||||
<string name="settings_owner_manage">Zarządzanie przez właściciela urządzenia</string>
|
||||
<string name="settings_user_independent">Niezależni użytkownicy</string>
|
||||
<string name="settings_user_independent">Niezależne ustawienia użytkowników</string>
|
||||
<string name="owner_only_summary">Tylko właściciel ma dostęp do roota</string>
|
||||
<string name="owner_manage_summary">Tylko właściciel może zarządzać ustawieniami dostępu do roota i otrzymywać żądania dostępu</string>
|
||||
<string name="owner_manage_summary">Tylko właściciel może zarządzać dostępem do roota i otrzymywać żądania dostępu do roota</string>
|
||||
<string name="user_independent_summary">Każdy użytkownik ma niezależne ustawienia dostępu do roota</string>
|
||||
|
||||
<string name="mount_namespace_mode">Tryb przestrzeni nazw montowania</string>
|
||||
|
@ -185,7 +191,7 @@
|
|||
<string name="settings_ns_requester">Dziedziczona przestrzeń nazw</string>
|
||||
<string name="settings_ns_isolate">Izolowana przestrzeń nazw</string>
|
||||
<string name="global_summary">Wszystkie sesje roota będą używać globalnej przestrzeni nazw montowania</string>
|
||||
<string name="requester_summary">Sesje roota odziedziczą przestrzeń nazw od żądającego</string>
|
||||
<string name="requester_summary">Sesje roota odziedziczą przestrzeń nazw żądającego dostępu</string>
|
||||
<string name="isolate_summary">Każda sesja roota otrzyma własną, izolowaną przestrzeń nazw</string>
|
||||
|
||||
<!--Notifications-->
|
||||
|
@ -196,7 +202,7 @@
|
|||
<string name="download_file_error">Błąd pobierania pliku</string>
|
||||
<string name="magisk_update_title">Aktualizacja Magisk dostępna!</string>
|
||||
<string name="updated_title">Magisk zaktualizowany</string>
|
||||
<string name="updated_text">Naciśnij aby otworzyć applikację</string>
|
||||
<string name="updated_text">Kliknij, aby otworzyć aplikację</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="yes">Tak</string>
|
||||
|
@ -208,7 +214,7 @@
|
|||
<string name="flashing">Flashowanie…</string>
|
||||
<string name="done">Gotowe!</string>
|
||||
<string name="failure">Błąd</string>
|
||||
<string name="hide_app_title">Ukrywam aplikację Magisk…</string>
|
||||
<string name="hide_app_title">Ukrywanie aplikacji Magisk…</string>
|
||||
<string name="open_link_failed_toast">Nie znaleziono aplikacji do otwarcia linku</string>
|
||||
<string name="complete_uninstall">Odinstaluj całkowicie</string>
|
||||
<string name="restore_img">Przywróć obrazy</string>
|
||||
|
@ -216,26 +222,26 @@
|
|||
<string name="restore_done">Przywracanie zakończone!</string>
|
||||
<string name="restore_fail">Kopia zapasowa nie istnieje!</string>
|
||||
<string name="setup_fail">Konfiguracja nieudana</string>
|
||||
<string name="env_fix_title">Wymaga dodatkowej konfiguracji</string>
|
||||
<string name="env_fix_msg">Twoje urządzenie wymaga dodatkowej konfiguracji aby Magisk działał właściwie. Czy chcesz kontynuować i uruchomić ponownie?</string>
|
||||
<string name="env_full_fix_msg">Twoje urządzenie musi wgrać ponowanie Magisk, aby działać poprawnie. Proszę przeinstaluj Magisk w aplikacji, tryb Recovery nie potrafi poprawnie rozpoznać urządzenia.</string>
|
||||
<string name="env_fix_title">Wymagana dodatkowa konfiguracja</string>
|
||||
<string name="env_fix_msg">Twoje urządzenie wymaga dodatkowej konfiguracji, aby Magisk działał poprawnie. Czy chcesz kontynuować i uruchomić ponownie?</string>
|
||||
<string name="env_full_fix_msg">Twoje urządzenie wymaga ponownej instalacji Magisk, aby działać poprawnie. Zainstaluj ponownie Magisk używając aplikacji, tryb recovery nie może uzyskać prawidłowych informacji o urządzeniu.</string>
|
||||
<string name="setup_msg">Uruchamianie środowiska konfiguracji…</string>
|
||||
<string name="authenticate">Uwierzytelnianie</string>
|
||||
<string name="unsupport_magisk_title">Nieobsługiwana wersja Magisk</string>
|
||||
<string name="unsupport_magisk_msg">Ta wersja aplikacji nie obsługuje Magisk w wersji niższej niż %1$s.\n\nAplikacja będzie zachowywać się tak jakby Magisk nie był zainstalowany, proszę uaktualnij Magisk.</string>
|
||||
<string name="unsupport_magisk_msg">Ta wersja aplikacji nie obsługuje Magisk w wersji niższej niż %1$s.\n\nAplikacja będzie zachowywać się tak, jakby Magisk nie był zainstalowany, zaktualizuj Magisk tak szybko, jak to możliwe.</string>
|
||||
<string name="unsupport_general_title">Nieprawidłowy stan</string>
|
||||
<string name="unsupport_system_app_msg">Uruchomienie tej aplikacji jako systemowa nie jest obsługiwane. Proszę przemienić ją na aplikację użytkownika.</string>
|
||||
<string name="unsupport_other_su_msg">Wykryto komendę \"su\" nie należącą do Magisk. Proszę usunąć tę drugą aplikację \"su\".</string>
|
||||
<string name="unsupport_external_storage_msg">Zainstalowano Magisk na pamięci zewnętrznej. Proszę przenieść ją na pamięć wewnętrzną.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">Ta aplikacja nie może dłużej działać w trybie ukrycia jako że root został utracony. Proszę przywrócić ją do oryginalnego stanu.</string>
|
||||
<string name="unsupport_system_app_msg">Uruchomienie tej aplikacji jako aplikacja systemowa nie jest obsługiwane. Przywróć aplikację do stanu aplikacji użytkownika.</string>
|
||||
<string name="unsupport_other_su_msg">Wykryto plik binarny \"su\" nie należący do Magisk. Usuń wszelkie konkurencyjne rozwiązania root i/lub zainstaluj ponownie Magisk.</string>
|
||||
<string name="unsupport_external_storage_msg">Magisk jest zainstalowany w pamięci zewnętrznej. Przenieś aplikację do pamięci wewnętrznej.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">Ukryta aplikacja Magisk nie może dłużej działać, ponieważ uprawnienia roota zostały utracone. Przywróć oryginalny plik APK.</string>
|
||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||
<string name="external_rw_permission_denied">Zezwól na dostęp do pamięci wewnętrznej, aby włączyć tę funkcję.</string>
|
||||
<string name="post_notifications_denied">Zezwól na otrzymywanie powiadomień, aby aktywować tą funkcję</string>
|
||||
<string name="install_unknown_denied">Zezwól na "Instaluj z nieznanych źródeł" by włączyć tą funkcję</string>
|
||||
<string name="external_rw_permission_denied">Zezwól na dostęp do pamięci, aby włączyć tę funkcję</string>
|
||||
<string name="post_notifications_denied">Zezwól na otrzymywanie powiadomień, aby włączyć tę funkcję</string>
|
||||
<string name="install_unknown_denied">Zezwól na \"Instaluj z nieznanych źródeł\", aby włączyć tę funkcję</string>
|
||||
<string name="add_shortcut_title">Utwórz skrót na ekranie głównym</string>
|
||||
<string name="add_shortcut_msg">Po ukryciu tej aplikacji, jej nazwa i ikona może być trudna do rozpoznania. Czy chcesz dodać ładny skrót na ekranie głównym?</string>
|
||||
<string name="app_not_found">Nie znaleziono aplikacji do wykonania tej czynności</string>
|
||||
<string name="reboot_apply_change">Uruchom ponownie by zastosować zmiany</string>
|
||||
<string name="restore_app_confirmation">To przywróci ukrytą aplikację z powrotem do orginalnej aplikacji. Czy na pewno chcesz to zrobić?</string>
|
||||
<string name="reboot_apply_change">Uruchom ponownie, aby zastosować zmiany</string>
|
||||
<string name="restore_app_confirmation">Spowoduje to przywrócenie ukrytej aplikacji z powrotem do stanu oryginalnej aplikacji. Czy na pewno chcesz to zrobić?</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -6,35 +6,35 @@
|
|||
<string name="logs">Registros</string>
|
||||
<string name="settings">Configurações</string>
|
||||
<string name="install">Instalar</string>
|
||||
<string name="section_home">Resumo</string>
|
||||
<string name="section_home">Início</string>
|
||||
<string name="section_theme">Temas</string>
|
||||
<string name="denylist">Lista de Negação</string>
|
||||
<string name="denylist">Lista de negação</string>
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">Nenhuma conexão disponível</string>
|
||||
<string name="app_changelog">Registro de alterações</string>
|
||||
<string name="loading">Carregando…</string>
|
||||
<string name="update">Atualizar</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="not_available">Não disponível</string>
|
||||
<string name="hide">Ocultar</string>
|
||||
<string name="home_package">Pacote</string>
|
||||
<string name="home_app_title">App</string>
|
||||
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
|
||||
<string name="home_support_title">Apoie</string>
|
||||
<string name="home_follow_title">Siga</string>
|
||||
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos!</string>
|
||||
<string name="home_support_title">Apoie-nos</string>
|
||||
<string name="home_follow_title">Siga-nos</string>
|
||||
<string name="home_item_source">Fonte</string>
|
||||
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode agradecer enviando uma pequena doação.</string>
|
||||
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.</string>
|
||||
<string name="home_installed_version">Instalado</string>
|
||||
<string name="home_latest_version">Recente</string>
|
||||
<string name="invalid_update_channel">Canal de atualização inválido</string>
|
||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
|
||||
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">Manter criptografia forçada</string>
|
||||
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
|
||||
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
|
||||
<string name="recovery_mode">Modo de recuperação</string>
|
||||
<string name="recovery_mode">Modo Recovery</string>
|
||||
<string name="install_options_title">Opções</string>
|
||||
<string name="install_method_title">Método</string>
|
||||
<string name="install_next">Próximo</string>
|
||||
|
@ -51,7 +51,7 @@
|
|||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Solicitação de SuperUsuário</string>
|
||||
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de SuperUsuário, o Magisk não pode conferir suas resposta</string>
|
||||
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
|
||||
<string name="deny">Negar</string>
|
||||
<string name="prompt">Perguntar</string>
|
||||
<string name="grant">Permitir</string>
|
||||
|
@ -62,28 +62,28 @@
|
|||
<string name="twentymin">20 mins</string>
|
||||
<string name="thirtymin">30 mins</string>
|
||||
<string name="sixtymin">60 mins</string>
|
||||
<string name="su_allow_toast">%1$s foi permitido o acesso SuperUsuário</string>
|
||||
<string name="su_deny_toast">%1$s foi negado o acesso SuperUsuário</string>
|
||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
|
||||
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
||||
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
|
||||
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
||||
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
||||
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
||||
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
|
||||
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
|
||||
<string name="su_revoke_title">Remover?</string>
|
||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de %1$s?</string>
|
||||
<string name="su_revoke_title">Revogar?</string>
|
||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
|
||||
<string name="toast">Notificação (Pop-up)</string>
|
||||
<string name="none">Nenhum</string>
|
||||
<string name="superuser_toggle_notification">Notificações</string>
|
||||
<string name="superuser_toggle_revoke">Remover</string>
|
||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
|
||||
<string name="superuser_toggle_revoke">Revogar</string>
|
||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
|
||||
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para SuperUsuário.</string>
|
||||
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
|
||||
<string name="menuSaveLog">Salvar Registro</string>
|
||||
<string name="menuClearLog">Limpar Registro agora</string>
|
||||
<string name="logs_cleared">Registro limpo com sucesso.</string>
|
||||
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
|
||||
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
|
||||
<string name="menuSaveLog">Salvar registros</string>
|
||||
<string name="menuClearLog">Limpar registros agora</string>
|
||||
<string name="logs_cleared">Registros limpo com sucesso</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Alvo UID: %1$d</string>
|
||||
<string name="target_pid">Alvo PID: %s</string>
|
||||
|
@ -91,14 +91,14 @@
|
|||
<string name="supp_group">Grupo suplementar: %s</string>
|
||||
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">Mostrar apps do Sistema</string>
|
||||
<string name="show_os_app">Mostrar apps do Sistema</string>
|
||||
<string name="show_system_app">Mostrar apps do sistema</string>
|
||||
<string name="show_os_app">Mostrar apps do sistema operacional</string>
|
||||
<string name="hide_filter_hint">Filtrar pelo nome</string>
|
||||
<string name="hide_search">Pesquisa</string>
|
||||
<string name="hide_search">Pesquisar</string>
|
||||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
|
||||
<string name="reboot_userspace">Reinício rápido</string>
|
||||
<string name="reboot_userspace">Reinicialização suave</string>
|
||||
<string name="reboot_recovery">Reiniciar em modo Recovery</string>
|
||||
<string name="reboot_bootloader">Reiniciar em modo Bootloader</string>
|
||||
<string name="reboot_download">Reiniciar em modo Download</string>
|
||||
|
@ -108,48 +108,48 @@
|
|||
<string name="module_state_restore">Restaurar</string>
|
||||
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
|
||||
<string name="update_available">Atualização disponível</string>
|
||||
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
|
||||
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
|
||||
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativado</string>
|
||||
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativado</string>
|
||||
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
|
||||
<string name="module_empty">Nenhum módulo instalado</string>
|
||||
<string name="confirm_install">Instalar módulo %1$s?</string>
|
||||
<string name="confirm_install_title">Confirmação de Instalação</string>
|
||||
<string name="confirm_install_title">Confirmação de instalação</string>
|
||||
|
||||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">Modo de tema</string>
|
||||
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
|
||||
<string name="settings_dark_mode_light">Sempre Claro</string>
|
||||
<string name="settings_dark_mode_system">Baseado no Sistema</string>
|
||||
<string name="settings_dark_mode_dark">Sempre Escuro</string>
|
||||
<string name="settings_download_path_title">Caminho para Baixar</string>
|
||||
<string name="settings_dark_mode_title">Modo do tema</string>
|
||||
<string name="settings_dark_mode_message">Selecione o modo mais adequado para você!</string>
|
||||
<string name="settings_dark_mode_light">Sempre claro</string>
|
||||
<string name="settings_dark_mode_system">Seguir sistema</string>
|
||||
<string name="settings_dark_mode_dark">Sempre escuro</string>
|
||||
<string name="settings_download_path_title">Caminho para baixar</string>
|
||||
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
|
||||
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
|
||||
<string name="settings_hide_app_title">Ocultar app do Magisk</string>
|
||||
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
|
||||
<string name="settings_restore_app_title">Restaurar o App do Magisk</string>
|
||||
<string name="settings_restore_app_title">Restaurar app do Magisk</string>
|
||||
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="system_default">(Padrão do sistema)</string>
|
||||
<string name="settings_check_update_title">Ativar Verificação de Atualizações</string>
|
||||
<string name="settings_check_update_summary">Verifica periodicamente em segundo plano se há atualizações</string>
|
||||
<string name="settings_update_channel_title">Canal de Atualização</string>
|
||||
<string name="settings_check_update_title">Verificar por atualizações</string>
|
||||
<string name="settings_check_update_summary">Verifique automaticamente se há atualizações ao abrir o app</string>
|
||||
<string name="settings_update_channel_title">Canal de atualização</string>
|
||||
<string name="settings_update_stable">Estável</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Canal Personalizado</string>
|
||||
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
|
||||
<string name="settings_update_custom">Personalizado</string>
|
||||
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
|
||||
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
||||
<string name="settings_denylist_title">Forçar Aplicação da Lista de Negação</string>
|
||||
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações feitas pelo Magisk</string>
|
||||
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
|
||||
<string name="settings_denylist_config_title">Configurar Lista de Negação</string>
|
||||
<string name="settings_denylist_title">Aplicar lista de negação</string>
|
||||
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
|
||||
<string name="settings_denylist_error">Este recurso requer que %1$s esteja ativado</string>
|
||||
<string name="settings_denylist_config_title">Configurar lista de negação</string>
|
||||
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
|
||||
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
|
||||
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
|
||||
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
|
||||
<string name="settings_hosts_title">Hosts sem sistema</string>
|
||||
<string name="settings_hosts_summary">Suporte de hosts sem sistema para apps AdBlock</string>
|
||||
<string name="settings_hosts_toast">Adicionado módulo de hosts sem sistema</string>
|
||||
<string name="settings_app_name_hint">Novo nome</string>
|
||||
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
|
||||
<string name="settings_app_name_error">Formato inválido</string>
|
||||
<string name="settings_su_app_adb">Aplicativos e ADB</string>
|
||||
<string name="settings_su_app">Apenas aplicativos</string>
|
||||
<string name="settings_su_app_adb">Apps e ADB</string>
|
||||
<string name="settings_su_app">Apenas apps</string>
|
||||
<string name="settings_su_adb">Apenas ADB</string>
|
||||
<string name="settings_su_disable">Desativado</string>
|
||||
<string name="settings_su_request_10">10 segundos</string>
|
||||
|
@ -160,30 +160,33 @@
|
|||
<string name="settings_su_request_60">60 segundos</string>
|
||||
<string name="superuser_access">Acesso de SuperUsuário</string>
|
||||
<string name="auto_response">Resposta automática</string>
|
||||
<string name="request_timeout">Tempo Limite da Solicitação</string>
|
||||
<string name="request_timeout">Tempo limite da solicitação</string>
|
||||
<string name="superuser_notification">Notificação de SuperUsuário</string>
|
||||
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
|
||||
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar aplicativo</string>
|
||||
<string name="settings_su_tapjack_title">Ativar Proteção Contra Atividades Sobrepostas</string>
|
||||
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
|
||||
<string name="settings_su_reauth_title">Reautenticar após atualização</string>
|
||||
<string name="settings_su_reauth_summary">Solicite permissões de SuperUsuário novamente após atualizar os apps</string>
|
||||
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
|
||||
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
|
||||
<string name="settings_su_auth_title">Autenticação de usuário</string>
|
||||
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
|
||||
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
|
||||
<string name="settings_customization">Personalizações</string>
|
||||
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
|
||||
<string name="settings_doh_title">Ativar DNS sobre HTTPS</string>
|
||||
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
|
||||
<string name="settings_doh_title">DNS sobre HTTPS</string>
|
||||
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
|
||||
<string name="multiuser_mode">Ativar Modo Multiusuário</string>
|
||||
<string name="multiuser_mode">Modo Multiusuário</string>
|
||||
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
|
||||
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
|
||||
<string name="settings_user_independent">Independente do usuário</string>
|
||||
<string name="owner_only_summary">Somente o proprietário tem acesso ao SuperUsuário</string>
|
||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do SuperUsuário e receber pedidos de solicitação</string>
|
||||
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
|
||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
|
||||
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
|
||||
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
|
||||
<string name="settings_ns_global">Namespace global</string>
|
||||
<string name="settings_ns_requester">Herdar Namespace</string>
|
||||
<string name="settings_ns_isolate">Namespace isolado</string>
|
||||
<string name="mount_namespace_mode">Montar namespace</string>
|
||||
<string name="settings_ns_global">Global</string>
|
||||
<string name="settings_ns_requester">Herdado</string>
|
||||
<string name="settings_ns_isolate">Individual</string>
|
||||
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
|
||||
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
|
||||
<string name="isolate_summary">Cada sessão do SuperUsuário terá seu próprio namespace isolado</string>
|
||||
<string name="isolate_summary">Cada sessão root terá seu próprio namespace individual</string>
|
||||
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">Atualizações do Magisk</string>
|
||||
|
@ -191,8 +194,8 @@
|
|||
<string name="updated_channel">Atualização concluída</string>
|
||||
<string name="download_complete">Download concluído</string>
|
||||
<string name="download_file_error">Erro ao baixar arquivo</string>
|
||||
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
|
||||
<string name="updated_title">Magisk Atualizado</string>
|
||||
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
|
||||
<string name="updated_title">Magisk atualizado</string>
|
||||
<string name="updated_text">Toque para abrir o app</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
|
@ -202,35 +205,35 @@
|
|||
<string name="download">Baixar</string>
|
||||
<string name="reboot">Reiniciar</string>
|
||||
<string name="release_notes">Notas da atualização</string>
|
||||
<string name="flashing">Fazendo Flash…</string>
|
||||
<string name="flashing">Flashando…</string>
|
||||
<string name="done">Concluído!</string>
|
||||
<string name="failure">Falha</string>
|
||||
<string name="failure">Falhou!</string>
|
||||
<string name="hide_app_title">Ocultando o app do Magisk…</string>
|
||||
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
|
||||
<string name="complete_uninstall">Desinstalação completa</string>
|
||||
<string name="restore_img">Restaurar imagens</string>
|
||||
<string name="restore_img_msg">Restaurando…</string>
|
||||
<string name="restore_done">Restauração concluída!</string>
|
||||
<string name="restore_fail">O backup original não foi encontrado!</string>
|
||||
<string name="restore_fail">O backup original não existe!</string>
|
||||
<string name="setup_fail">Falha na instalação</string>
|
||||
<string name="env_fix_title">Configuração adicional exigida</string>
|
||||
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
|
||||
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Reinstale o Magisk no aplicativo, o modo de recuperação não pode obter as devidas informações do dispositivo.</string>
|
||||
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
|
||||
<string name="setup_msg">Executando a configuração do ambiente…</string>
|
||||
<string name="authenticate">Autenticar</string>
|
||||
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
|
||||
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
|
||||
<string name="unsupport_general_title">Estado Anormal</string>
|
||||
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
|
||||
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
|
||||
<string name="unsupport_general_title">Estado anormal</string>
|
||||
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
|
||||
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
|
||||
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o SuperUsuário foi perdido. Por favor, restaure o APK original.</string>
|
||||
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
|
||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
|
||||
<string name="post_notifications_denied">Autorize a permissão de notificaçoes para ativar esta funcionalidade</string>
|
||||
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
|
||||
<string name="add_shortcut_title">Adicionar Atalho à Tela Inicial</string>
|
||||
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
||||
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
||||
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
||||
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
|
||||
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
|
||||
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
||||
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
||||
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
|
||||
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
|
||||
|
|
|
@ -6,35 +6,35 @@
|
|||
<string name="logs">Registros</string>
|
||||
<string name="settings">Configurações</string>
|
||||
<string name="install">Instalar</string>
|
||||
<string name="section_home">Resumo</string>
|
||||
<string name="section_home">Início</string>
|
||||
<string name="section_theme">Temas</string>
|
||||
<string name="denylist">Lista de Negação</string>
|
||||
<string name="denylist">Lista de negação</string>
|
||||
|
||||
<!--Home-->
|
||||
<string name="no_connection">Nenhuma conexão disponível</string>
|
||||
<string name="app_changelog">Registro de alterações</string>
|
||||
<string name="loading">Carregando…</string>
|
||||
<string name="update">Atualizar</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="not_available">Não disponível</string>
|
||||
<string name="hide">Ocultar</string>
|
||||
<string name="home_package">Pacote</string>
|
||||
<string name="home_app_title">App</string>
|
||||
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
|
||||
<string name="home_support_title">Apoie</string>
|
||||
<string name="home_follow_title">Siga</string>
|
||||
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos!</string>
|
||||
<string name="home_support_title">Apoie-nos</string>
|
||||
<string name="home_follow_title">Siga-nos</string>
|
||||
<string name="home_item_source">Fonte</string>
|
||||
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode agradecer enviando uma pequena doação.</string>
|
||||
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.</string>
|
||||
<string name="home_installed_version">Instalado</string>
|
||||
<string name="home_latest_version">Recente</string>
|
||||
<string name="invalid_update_channel">Canal de atualização inválido</string>
|
||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
|
||||
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">Manter criptografia forçada</string>
|
||||
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
|
||||
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
|
||||
<string name="recovery_mode">Modo de recuperação</string>
|
||||
<string name="recovery_mode">Modo Recovery</string>
|
||||
<string name="install_options_title">Opções</string>
|
||||
<string name="install_method_title">Método</string>
|
||||
<string name="install_next">Próximo</string>
|
||||
|
@ -51,7 +51,7 @@
|
|||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Solicitação de SuperUsuário</string>
|
||||
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de SuperUsuário, o Magisk não pode conferir suas resposta</string>
|
||||
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
|
||||
<string name="deny">Negar</string>
|
||||
<string name="prompt">Perguntar</string>
|
||||
<string name="grant">Permitir</string>
|
||||
|
@ -62,28 +62,28 @@
|
|||
<string name="twentymin">20 mins</string>
|
||||
<string name="thirtymin">30 mins</string>
|
||||
<string name="sixtymin">60 mins</string>
|
||||
<string name="su_allow_toast">%1$s foi permitido o acesso SuperUsuário</string>
|
||||
<string name="su_deny_toast">%1$s foi negado o acesso SuperUsuário</string>
|
||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
|
||||
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
|
||||
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
|
||||
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
|
||||
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
|
||||
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
|
||||
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
|
||||
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
|
||||
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
|
||||
<string name="su_revoke_title">Remover?</string>
|
||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de %1$s?</string>
|
||||
<string name="su_revoke_title">Revogar?</string>
|
||||
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
|
||||
<string name="toast">Notificação (Pop-up)</string>
|
||||
<string name="none">Nenhum</string>
|
||||
<string name="superuser_toggle_notification">Notificações</string>
|
||||
<string name="superuser_toggle_revoke">Remover</string>
|
||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
|
||||
<string name="superuser_toggle_revoke">Revogar</string>
|
||||
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
|
||||
|
||||
<!--Logs-->
|
||||
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para SuperUsuário.</string>
|
||||
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
|
||||
<string name="menuSaveLog">Salvar Registro</string>
|
||||
<string name="menuClearLog">Limpar Registro agora</string>
|
||||
<string name="logs_cleared">Registro limpo com sucesso.</string>
|
||||
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
|
||||
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
|
||||
<string name="menuSaveLog">Salvar registros</string>
|
||||
<string name="menuClearLog">Limpar registros agora</string>
|
||||
<string name="logs_cleared">Registros limpo com sucesso</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Alvo UID: %1$d</string>
|
||||
<string name="target_pid">Alvo PID: %s</string>
|
||||
|
@ -91,14 +91,14 @@
|
|||
<string name="supp_group">Grupo suplementar: %s</string>
|
||||
|
||||
<!--MagiskHide-->
|
||||
<string name="show_system_app">Mostrar apps do Sistema</string>
|
||||
<string name="show_os_app">Mostrar apps do Sistema</string>
|
||||
<string name="show_system_app">Mostrar apps do sistema</string>
|
||||
<string name="show_os_app">Mostrar apps do sistema operacional</string>
|
||||
<string name="hide_filter_hint">Filtrar pelo nome</string>
|
||||
<string name="hide_search">Pesquisa</string>
|
||||
<string name="hide_search">Pesquisar</string>
|
||||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
|
||||
<string name="reboot_userspace">Reinício rápido</string>
|
||||
<string name="reboot_userspace">Reinicialização suave</string>
|
||||
<string name="reboot_recovery">Reiniciar em modo Recovery</string>
|
||||
<string name="reboot_bootloader">Reiniciar em modo Bootloader</string>
|
||||
<string name="reboot_download">Reiniciar em modo Download</string>
|
||||
|
@ -108,48 +108,48 @@
|
|||
<string name="module_state_restore">Restaurar</string>
|
||||
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
|
||||
<string name="update_available">Atualização disponível</string>
|
||||
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
|
||||
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
|
||||
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativado</string>
|
||||
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativado</string>
|
||||
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
|
||||
<string name="module_empty">Nenhum módulo instalado</string>
|
||||
<string name="confirm_install">Instalar módulo %1$s?</string>
|
||||
<string name="confirm_install_title">Confirmação de Instalação</string>
|
||||
<string name="confirm_install_title">Confirmação de instalação</string>
|
||||
|
||||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">Modo de tema</string>
|
||||
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
|
||||
<string name="settings_dark_mode_light">Sempre Claro</string>
|
||||
<string name="settings_dark_mode_system">Baseado no Sistema</string>
|
||||
<string name="settings_dark_mode_dark">Sempre Escuro</string>
|
||||
<string name="settings_download_path_title">Caminho para Baixar</string>
|
||||
<string name="settings_dark_mode_title">Modo do tema</string>
|
||||
<string name="settings_dark_mode_message">Selecione o modo mais adequado para você!</string>
|
||||
<string name="settings_dark_mode_light">Sempre claro</string>
|
||||
<string name="settings_dark_mode_system">Seguir sistema</string>
|
||||
<string name="settings_dark_mode_dark">Sempre escuro</string>
|
||||
<string name="settings_download_path_title">Caminho para baixar</string>
|
||||
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
|
||||
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
|
||||
<string name="settings_hide_app_title">Ocultar app do Magisk</string>
|
||||
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
|
||||
<string name="settings_restore_app_title">Restaurar o App do Magisk</string>
|
||||
<string name="settings_restore_app_title">Restaurar app do Magisk</string>
|
||||
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="system_default">(Padrão do sistema)</string>
|
||||
<string name="settings_check_update_title">Ativar Verificação de Atualizações</string>
|
||||
<string name="settings_check_update_summary">Verifica periodicamente em segundo plano se há atualizações</string>
|
||||
<string name="settings_update_channel_title">Canal de Atualização</string>
|
||||
<string name="settings_check_update_title">Verificar por atualizações</string>
|
||||
<string name="settings_check_update_summary">Verifique automaticamente se há atualizações ao abrir o app</string>
|
||||
<string name="settings_update_channel_title">Canal de atualização</string>
|
||||
<string name="settings_update_stable">Estável</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Canal Personalizado</string>
|
||||
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
|
||||
<string name="settings_update_custom">Personalizado</string>
|
||||
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
|
||||
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
|
||||
<string name="settings_denylist_title">Forçar Aplicação da Lista de Negação</string>
|
||||
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações feitas pelo Magisk</string>
|
||||
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
|
||||
<string name="settings_denylist_config_title">Configurar Lista de Negação</string>
|
||||
<string name="settings_denylist_title">Aplicar lista de negação</string>
|
||||
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
|
||||
<string name="settings_denylist_error">Este recurso requer que %1$s esteja ativado</string>
|
||||
<string name="settings_denylist_config_title">Configurar lista de negação</string>
|
||||
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
|
||||
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
|
||||
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
|
||||
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
|
||||
<string name="settings_hosts_title">Hosts sem sistema</string>
|
||||
<string name="settings_hosts_summary">Suporte de hosts sem sistema para apps AdBlock</string>
|
||||
<string name="settings_hosts_toast">Adicionado módulo de hosts sem sistema</string>
|
||||
<string name="settings_app_name_hint">Novo nome</string>
|
||||
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
|
||||
<string name="settings_app_name_error">Formato inválido</string>
|
||||
<string name="settings_su_app_adb">Aplicativos e ADB</string>
|
||||
<string name="settings_su_app">Apenas aplicativos</string>
|
||||
<string name="settings_su_app_adb">Apps e ADB</string>
|
||||
<string name="settings_su_app">Apenas apps</string>
|
||||
<string name="settings_su_adb">Apenas ADB</string>
|
||||
<string name="settings_su_disable">Desativado</string>
|
||||
<string name="settings_su_request_10">10 segundos</string>
|
||||
|
@ -160,30 +160,33 @@
|
|||
<string name="settings_su_request_60">60 segundos</string>
|
||||
<string name="superuser_access">Acesso de SuperUsuário</string>
|
||||
<string name="auto_response">Resposta automática</string>
|
||||
<string name="request_timeout">Tempo Limite da Solicitação</string>
|
||||
<string name="request_timeout">Tempo limite da solicitação</string>
|
||||
<string name="superuser_notification">Notificação de SuperUsuário</string>
|
||||
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
|
||||
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar aplicativo</string>
|
||||
<string name="settings_su_tapjack_title">Ativar Proteção Contra Atividades Sobrepostas</string>
|
||||
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
|
||||
<string name="settings_su_reauth_title">Reautenticar após atualização</string>
|
||||
<string name="settings_su_reauth_summary">Solicite permissões de SuperUsuário novamente após atualizar os apps</string>
|
||||
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
|
||||
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
|
||||
<string name="settings_su_auth_title">Autenticação de usuário</string>
|
||||
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
|
||||
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
|
||||
<string name="settings_customization">Personalizações</string>
|
||||
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
|
||||
<string name="settings_doh_title">Ativar DNS sobre HTTPS</string>
|
||||
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
|
||||
<string name="settings_doh_title">DNS sobre HTTPS</string>
|
||||
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
|
||||
<string name="multiuser_mode">Ativar Modo Multiusuário</string>
|
||||
<string name="multiuser_mode">Modo Multiusuário</string>
|
||||
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
|
||||
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
|
||||
<string name="settings_user_independent">Independente do usuário</string>
|
||||
<string name="owner_only_summary">Somente o proprietário tem acesso ao SuperUsuário</string>
|
||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do SuperUsuário e receber pedidos de solicitação</string>
|
||||
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
|
||||
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
|
||||
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
|
||||
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
|
||||
<string name="settings_ns_global">Namespace global</string>
|
||||
<string name="settings_ns_requester">Herdar Namespace</string>
|
||||
<string name="settings_ns_isolate">Namespace isolado</string>
|
||||
<string name="mount_namespace_mode">Montar namespace</string>
|
||||
<string name="settings_ns_global">Global</string>
|
||||
<string name="settings_ns_requester">Herdado</string>
|
||||
<string name="settings_ns_isolate">Individual</string>
|
||||
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
|
||||
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
|
||||
<string name="isolate_summary">Cada sessão do SuperUsuário terá seu próprio namespace isolado</string>
|
||||
<string name="isolate_summary">Cada sessão root terá seu próprio namespace individual</string>
|
||||
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">Atualizações do Magisk</string>
|
||||
|
@ -191,8 +194,8 @@
|
|||
<string name="updated_channel">Atualização concluída</string>
|
||||
<string name="download_complete">Download concluído</string>
|
||||
<string name="download_file_error">Erro ao baixar arquivo</string>
|
||||
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
|
||||
<string name="updated_title">Magisk Atualizado</string>
|
||||
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
|
||||
<string name="updated_title">Magisk atualizado</string>
|
||||
<string name="updated_text">Toque para abrir o app</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
|
@ -202,35 +205,35 @@
|
|||
<string name="download">Baixar</string>
|
||||
<string name="reboot">Reiniciar</string>
|
||||
<string name="release_notes">Notas da atualização</string>
|
||||
<string name="flashing">Fazendo Flash…</string>
|
||||
<string name="flashing">Flashando…</string>
|
||||
<string name="done">Concluído!</string>
|
||||
<string name="failure">Falha</string>
|
||||
<string name="failure">Falhou!</string>
|
||||
<string name="hide_app_title">Ocultando o app do Magisk…</string>
|
||||
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
|
||||
<string name="complete_uninstall">Desinstalação completa</string>
|
||||
<string name="restore_img">Restaurar imagens</string>
|
||||
<string name="restore_img_msg">Restaurando…</string>
|
||||
<string name="restore_done">Restauração concluída!</string>
|
||||
<string name="restore_fail">O backup original não foi encontrado!</string>
|
||||
<string name="restore_fail">O backup original não existe!</string>
|
||||
<string name="setup_fail">Falha na instalação</string>
|
||||
<string name="env_fix_title">Configuração adicional exigida</string>
|
||||
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
|
||||
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Reinstale o Magisk no aplicativo, o modo de recuperação não pode obter as devidas informações do dispositivo.</string>
|
||||
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
|
||||
<string name="setup_msg">Executando a configuração do ambiente…</string>
|
||||
<string name="authenticate">Autenticar</string>
|
||||
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
|
||||
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
|
||||
<string name="unsupport_general_title">Estado Anormal</string>
|
||||
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
|
||||
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
|
||||
<string name="unsupport_general_title">Estado anormal</string>
|
||||
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
|
||||
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
|
||||
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o SuperUsuário foi perdido. Por favor, restaure o APK original.</string>
|
||||
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
|
||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
|
||||
<string name="post_notifications_denied">Autorize a permissão de notificaçoes para ativar esta funcionalidade</string>
|
||||
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
|
||||
<string name="add_shortcut_title">Adicionar Atalho à Tela Inicial</string>
|
||||
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
||||
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
|
||||
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
|
||||
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
|
||||
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
|
||||
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
|
||||
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
|
||||
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
|
||||
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<string name="app_changelog">Değişiklik günlüğü</string>
|
||||
<string name="loading">Yükleniyor…</string>
|
||||
<string name="update">Güncelle</string>
|
||||
<string name="not_available">Mevcut değil</string>
|
||||
<string name="not_available">Yüklü değil</string>
|
||||
<string name="hide">Gizle</string>
|
||||
<string name="home_package">Paket</string>
|
||||
<string name="home_app_title">Uygulama</string>
|
||||
|
@ -24,29 +24,29 @@
|
|||
<string name="home_support_title">Bizi Destekleyin</string>
|
||||
<string name="home_follow_title">Bizi Takip Edin</string>
|
||||
<string name="home_item_source">Kaynak</string>
|
||||
<string name="home_support_content">Magisk ücretsiz ve açık kaynaktır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize değer verdiğinizi gösterebilirsiniz.</string>
|
||||
<string name="home_installed_version">Yüklendi</string>
|
||||
<string name="home_support_content">Magisk ücretsiz ve açık kaynaktır ve her zaman öyle kalacaktır. Ancak bir bağış yaparak bize destek olduğunuzu gösterebilirsiniz.</string>
|
||||
<string name="home_installed_version">Durum</string>
|
||||
<string name="home_latest_version">En son sürüm</string>
|
||||
<string name="invalid_update_channel">Geçersiz Güncelleme Kanalı</string>
|
||||
<string name="uninstall_magisk_title">Magisk\'i Kaldırın</string>
|
||||
<string name="uninstall_magisk_title">Magisk\'i Kaldır</string>
|
||||
<string name="uninstall_magisk_msg">Tüm modüller devre dışı bırakılacak/kaldırılacak!\nKök kaldırılacak!\nMagisk kullanılarak şifrelenmemiş herhangi bir dahili depolama yeniden şifrelenecek!</string>
|
||||
|
||||
<!--Install-->
|
||||
<string name="keep_force_encryption">Zorla şifrelemeyi koru</string>
|
||||
<string name="keep_dm_verity">AVB 2.0/dm-verity\'yi koruyun</string>
|
||||
<string name="keep_dm_verity">AVB 2.0/dm-verity\'yi koru</string>
|
||||
<string name="patch_vbmeta">Önyükleme görüntüsünde vbmeta yamasını uygula</string>
|
||||
<string name="recovery_mode">Kurtarma Modu</string>
|
||||
<string name="install_options_title">Seçenekler</string>
|
||||
<string name="install_method_title">Yöntem</string>
|
||||
<string name="install_next">Sonraki</string>
|
||||
<string name="install_start">Hadi gidelim</string>
|
||||
<string name="install_start">Haydi başlayalım</string>
|
||||
<string name="manager_download_install">İndirmek ve yüklemek için basın</string>
|
||||
<string name="direct_install">Doğrudan Kurulum (Önerilir)</string>
|
||||
<string name="install_inactive_slot">Etkin Olmayan Yuvaya Kur (OTA\'dan Sonra)</string>
|
||||
<string name="install_inactive_slot">Etkin Olmayan Yuvaya Yükle (OTA\'dan Sonra)</string>
|
||||
<string name="install_inactive_slot_msg">Yeniden başlatmanın ardından cihazınız mevcut etkin olmayan yuvaya önyükleme yapmaya ZORLANACAK!\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.\nDevam edilsin mi?</string>
|
||||
<string name="setup_title">Ek Kurulum</string>
|
||||
<string name="select_patch_file">Bir Dosya Seçin ve Yamalayın</string>
|
||||
<string name="patch_file_msg">Bir ham görüntü (*.img) veya bir ODIN tar dosyası (*.tar) seçin</string>
|
||||
<string name="select_patch_file">Bir Dosya Seç ve Yama Yap</string>
|
||||
<string name="patch_file_msg">Bir ham görüntü (*.img) veya bir ODIN tar dosyası (*.tar) veya bir payload.bin (*.bin) seçin</string>
|
||||
<string name="reboot_delay_toast">5 saniye içinde yeniden başlatılıyor…</string>
|
||||
<string name="flash_screen_title">Yükleniyor</string>
|
||||
|
||||
|
@ -54,11 +54,11 @@
|
|||
<string name="su_request_title">Süper Kullanıcı İsteği</string>
|
||||
<string name="touch_filtered_warning">Bir uygulama bir Süper Kullanıcı isteğini engellediği için Magisk yanıtınızı doğrulayamıyor</string>
|
||||
<string name="deny">Reddet</string>
|
||||
<string name="prompt">Hemen</string>
|
||||
<string name="prompt">Sor</string>
|
||||
<string name="grant">İzin ver</string>
|
||||
<string name="su_warning">Cihazınıza tam erişim sağlar.\nEğer emin değilseniz reddedin!</string>
|
||||
<string name="forever">Daima</string>
|
||||
<string name="once">Bir kere</string>
|
||||
<string name="once">Bir kez</string>
|
||||
<string name="tenmin">10 dakika</string>
|
||||
<string name="twentymin">20 dakika</string>
|
||||
<string name="thirtymin">30 dakika</string>
|
||||
|
@ -85,9 +85,12 @@
|
|||
<string name="log_data_magisk_none">Magisk günlükleri boş, bu garip</string>
|
||||
<string name="menuSaveLog">Günlüğü kaydet</string>
|
||||
<string name="menuClearLog">Günlüğü şimdi temizle</string>
|
||||
<string name="logs_cleared">Günlük başarıyla temizlendi</string>
|
||||
<string name="logs_cleared">Günlük kaydı başarıyla temizlendi</string>
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Hedef UID: %1$d</string>
|
||||
<string name="target_pid">Ns hedef PID\'sini bağla: %s</string>
|
||||
<string name="selinux_context">SELinux içeriği: %s</string>
|
||||
<string name="supp_group">Ek grup: %s</string>
|
||||
|
||||
<!--SafetyNet-->
|
||||
|
||||
|
@ -99,18 +102,18 @@
|
|||
|
||||
<!--Module-->
|
||||
<string name="no_info_provided">(Bilgi verilmedi)</string>
|
||||
<string name="reboot_userspace">Yazılımsal olarak yeniden başlat</string>
|
||||
<string name="reboot_recovery">Kurtarma modunda Yeniden Başlat</string>
|
||||
<string name="reboot_bootloader">Önyükleyici modunda Yeniden Başlat</string>
|
||||
<string name="reboot_download">Download modu için Yeniden Başlat</string>
|
||||
<string name="reboot_edl">EDL modunda Yeniden Başlat</string>
|
||||
<string name="reboot_userspace">Hızlı yeniden başlat</string>
|
||||
<string name="reboot_recovery">Kurtarma modunda yeniden başlat</string>
|
||||
<string name="reboot_bootloader">Önyükleyici modunda yeniden başlat</string>
|
||||
<string name="reboot_download">İndirme modunda yeniden başlat</string>
|
||||
<string name="reboot_edl">EDL modunda yeniden başlat</string>
|
||||
<string name="module_version_author">%1$s / %2$s</string>
|
||||
<string name="module_state_remove">Kaldır</string>
|
||||
<string name="module_state_restore">Geri yükle</string>
|
||||
<string name="module_action_install_external">Depolamadan yükle</string>
|
||||
<string name="update_available">Güncelleme Mevcut</string>
|
||||
<string name="suspend_text_riru">%1$s etkinleştirildiği için modül askıya alındı</string>
|
||||
<string name="suspend_text_zygisk">%1$s etkin olmadığı için modül askıya alındı</string>
|
||||
<string name="suspend_text_zygisk">%1$s etkinleştirilmediği için modül askıya alındı</string>
|
||||
<string name="zygisk_module_unloaded">Uyumsuzluk nedeniyle Zygisk modülü yüklenmedi</string>
|
||||
<string name="module_empty">Yüklü modül yok</string>
|
||||
<string name="confirm_install">%1$s modülü yüklensin mi?</string>
|
||||
|
@ -119,33 +122,33 @@
|
|||
<!--Settings-->
|
||||
<string name="settings_dark_mode_title">Tema Modu</string>
|
||||
<string name="settings_dark_mode_message">Tarzınıza en uygun modu seçin!</string>
|
||||
<string name="settings_dark_mode_light">Her zaman Açık</string>
|
||||
<string name="settings_dark_mode_light">Daima Açık</string>
|
||||
<string name="settings_dark_mode_system">Sistemi Takip Et</string>
|
||||
<string name="settings_dark_mode_dark">Her zaman Koyu</string>
|
||||
<string name="settings_dark_mode_dark">Daima Koyu</string>
|
||||
<string name="settings_download_path_title">İndirme yolu</string>
|
||||
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
|
||||
<string name="settings_hide_app_title">Magisk uygulamasını gizleyin</string>
|
||||
<string name="settings_hide_app_summary">Rastgele bir paket kimliğine ve özel uygulama etiketine sahip bir proxy uygulaması yükleyin</string>
|
||||
<string name="settings_restore_app_title">Magisk uygulamasını geri yükleyin</string>
|
||||
<string name="settings_restore_app_summary">Uygulamayı gösterin ve orijinal APK\'yı geri yükleyin</string>
|
||||
<string name="settings_hide_app_title">Magisk uygulamasını gizle</string>
|
||||
<string name="settings_hide_app_summary">Rastgele bir paket kimliği ve özel uygulama etiketi olan bir proxy uygulaması yükleyin</string>
|
||||
<string name="settings_restore_app_title">Magisk uygulamasını geri yükle</string>
|
||||
<string name="settings_restore_app_summary">Uygulamayı göster ve orijinal APK\'yı geri yükle</string>
|
||||
<string name="language">Dil</string>
|
||||
<string name="system_default">(Sistem Varsayılanı)</string>
|
||||
<string name="settings_check_update_title">Güncellemeleri Kontrol Et</string>
|
||||
<string name="settings_check_update_summary">Arka planda güncellemeleri düzenli olarak kontrol edin</string>
|
||||
<string name="settings_check_update_summary">Arka plandaki güncellemeleri düzenli olarak kontrol et</string>
|
||||
<string name="settings_update_channel_title">Güncelleme Kanalı</string>
|
||||
<string name="settings_update_stable">Stabil</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Özel</string>
|
||||
<string name="settings_update_custom_msg">Özel bir kanal URL\'si ekleyin</string>
|
||||
<string name="settings_zygisk_summary">Zygisk arka plan programında Magisk\'in bazı bölümlerini çalıştırın</string>
|
||||
<string name="settings_update_custom_msg">Özel bir kanal bağlantısı ekle</string>
|
||||
<string name="settings_zygisk_summary">Zygisk arka plan programında Magisk\'in bazı bölümlerini çalıştır</string>
|
||||
<string name="settings_denylist_title">Reddetme Listesini Zorla</string>
|
||||
<string name="settings_denylist_summary">Reddetme listesindeki işlemlerde tüm Magisk değişiklikleri geri alınır</string>
|
||||
<string name="settings_denylist_error">Bu özelliğin etkinleştirilmesi için %1$s gerekir</string>
|
||||
<string name="settings_denylist_error">Bu özelliğin etkinleştirilmesi için %1$s gerekiyor</string>
|
||||
<string name="settings_denylist_config_title">Reddetme Listesini Yapılandır</string>
|
||||
<string name="settings_denylist_config_summary">Reddetme listesine dahil edilecek işlemleri seçin</string>
|
||||
<string name="settings_hosts_title">Sistemsiz host</string>
|
||||
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz host desteği</string>
|
||||
<string name="settings_hosts_toast">Sistemsiz host modülü eklendi</string>
|
||||
<string name="settings_denylist_config_summary">Reddetme listesine dahil edilecek işlemleri seç</string>
|
||||
<string name="settings_hosts_title">Sistemsiz ana makineler (systemless hosts)</string>
|
||||
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz ana makineler (systemless hosts) desteği</string>
|
||||
<string name="settings_hosts_toast">Sistemsiz ana makineler (systemless hosts) modülü eklendi</string>
|
||||
<string name="settings_app_name_hint">Yeni ad</string>
|
||||
<string name="settings_app_name_helper">Uygulama bu adla yeniden paketlenecek</string>
|
||||
<string name="settings_app_name_error">Geçersiz format</string>
|
||||
|
@ -160,15 +163,18 @@
|
|||
<string name="settings_su_request_45">45 saniye</string>
|
||||
<string name="settings_su_request_60">60 saniye</string>
|
||||
<string name="superuser_access">Süper Kullanıcı Erişimi</string>
|
||||
<string name="auto_response">Otomatik Cevap</string>
|
||||
<string name="request_timeout">İstek Zaman Aşımına Uğradı</string>
|
||||
<string name="auto_response">Otomatik Yanıt</string>
|
||||
<string name="request_timeout">İstek Zaman Aşımı</string>
|
||||
<string name="superuser_notification">Süper Kullanıcı Bildirimi</string>
|
||||
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrulaması yapın</string>
|
||||
<string name="settings_su_reauth_summary">Uygulamaları yükselttikten sonra Süper Kullanıcı izinlerini tekrar isteyin</string>
|
||||
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrulaması yap</string>
|
||||
<string name="settings_su_reauth_summary">Uygulamaları yükselttikten sonra Süper Kullanıcı izinlerini tekrar iste</string>
|
||||
<string name="settings_su_tapjack_title">Sahte Ekran (Tapjacking) Koruması</string>
|
||||
<string name="settings_su_tapjack_summary">Süper Kullanıcı bilgi istemi iletişim kutusu, herhangi bir başka pencere veya yer paylaşımı tarafından engellendiğinde girişe yanıt vermeyecektir.</string>
|
||||
<string name="settings_su_auth_title">Kullanıcı Kimlik Doğrulaması</string>
|
||||
<string name="settings_su_auth_summary">Süper Kullanıcı istekleri sırasında kullanıcı kimlik doğrulaması iste</string>
|
||||
<string name="settings_su_auth_insecure">Cihazda hiçbir kimlik doğrulama yöntemi yapılandırılmamış</string>
|
||||
<string name="settings_customization">Özelleştir</string>
|
||||
<string name="setting_add_shortcut_summary">Uygulamayı gizledikten sonra adın ve simgenin tanınmasının zor olması durumunda ana ekrana güzel bir kısayol ekleyin</string>
|
||||
<string name="setting_add_shortcut_summary">Uygulamayı gizledikten sonra adın ve simgenin tanınmasının zor olması durumunda ana ekrana güzel bir kısayol ekle</string>
|
||||
<string name="settings_doh_title">HTTPS üzerinden DNS</string>
|
||||
<string name="settings_doh_description">Bazı ülkelerde DNS zehirlenmesine geçici çözüm</string>
|
||||
|
||||
|
@ -176,31 +182,31 @@
|
|||
<string name="settings_owner_only">Yalnızca Cihaz Sahibi</string>
|
||||
<string name="settings_owner_manage">Cihaz Sahibi Tarafından Yönetildi</string>
|
||||
<string name="settings_user_independent">Kullanıcıdan Bağımsız</string>
|
||||
<string name="owner_only_summary">Yalnızca sahibinin kök erişimi vardır</string>
|
||||
<string name="owner_manage_summary">Yalnızca sahip, kök erişimini yönetebilir ve istek istemleri alabilir</string>
|
||||
<string name="owner_only_summary">Kök erişimi yalnızca sahibine aittir</string>
|
||||
<string name="owner_manage_summary">Kök erişimini yalnızca sahip yönetebilir ve istek istemlerini alabilir</string>
|
||||
<string name="user_independent_summary">Her kullanıcının kendi ayrı kök kuralları vardır</string>
|
||||
|
||||
<string name="mount_namespace_mode">Bağlama Ad Alanı Modu</string>
|
||||
<string name="settings_ns_global">Küresel Ad Alanı</string>
|
||||
<string name="settings_ns_requester">Ad Alanını Devral</string>
|
||||
<string name="settings_ns_isolate">İzole Ad Alanı</string>
|
||||
<string name="settings_ns_isolate">İzole Edilmiş Ad Alanı</string>
|
||||
<string name="global_summary">Tüm kök oturumları, global bağlama ad alanını kullanır</string>
|
||||
<string name="requester_summary">Kök oturumları, istek sahibinin ad alanını devralır</string>
|
||||
<string name="isolate_summary">Her kök oturumun kendi yalıtılmış ad alanı olacaktır</string>
|
||||
<string name="isolate_summary">Her kök oturumun kendi izole edilmiş ad alanı olacaktır</string>
|
||||
|
||||
<!--Notifications-->
|
||||
<string name="update_channel">Magisk Güncellemeleri</string>
|
||||
<string name="progress_channel">İlerleme Bildirimleri</string>
|
||||
<string name="updated_channel">Güncelleme Tamamlandı</string>
|
||||
<string name="download_complete">İndirme tamamlandı</string>
|
||||
<string name="download_complete">İndirme Tamamlandı</string>
|
||||
<string name="download_file_error">Dosya indirilirken hata oluştu</string>
|
||||
<string name="magisk_update_title">Magisk Güncellemesi Mevcut!</string>
|
||||
<string name="updated_title">Magisk Güncellendi</string>
|
||||
<string name="updated_text">Uygulamayı açmak için dokunun</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="yes">Evet</string>
|
||||
<string name="no">Hayır</string>
|
||||
<string name="yes">Mevcut</string>
|
||||
<string name="no">Mevcut değil</string>
|
||||
<string name="repo_install_title">%1$s %2$s(%3$d) yükle</string>
|
||||
<string name="download">İndir</string>
|
||||
<string name="reboot">Yeniden başlat</string>
|
||||
|
@ -218,22 +224,22 @@
|
|||
<string name="setup_fail">Kurulum başarısız oldu</string>
|
||||
<string name="env_fix_title">Ek Kurulum Gerekiyor</string>
|
||||
<string name="env_fix_msg">Magisk\'in düzgün çalışması için cihazınızın ek kuruluma ihtiyacı var. Devam etmek ve yeniden başlatmak istiyor musunuz?</string>
|
||||
<string name="env_full_fix_msg">Cihazınızın düzgün çalışması için Magisk\'in yeniden yüklenmeye ihtiyacı var. Lütfen Magisk\'i uygulama içinde yeniden yükleyin, kurtarma modu doğru cihaz bilgilerini alamıyor.</string>
|
||||
<string name="env_full_fix_msg">Cihazınızın düzgün çalışması için Magisk\'in yeniden başlatılması gerekiyor. Lütfen Magisk\'i uygulama içinden yeniden yükleyin, kurtarma modu doğru cihaz bilgilerini alamıyor.</string>
|
||||
<string name="setup_msg">Ortam kurulumu çalıştırılıyor…</string>
|
||||
<string name="authenticate">Kimlik Doğrula</string>
|
||||
<string name="authenticate">Kimlik doğrulaması yap</string>
|
||||
<string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string>
|
||||
<string name="unsupport_magisk_msg">Uygulamanın bu sürümü, %1$s\'den daha düşük Magisk sürümlerini desteklemiyor.\n\nUygulama, Magisk kurulu değilmiş gibi davranacak, lütfen Magisk\'i mümkün olan en kısa sürede yükseltin.</string>
|
||||
<string name="unsupport_magisk_msg">Uygulamanın bu sürümü %1$s altındaki Magisk sürümlerini desteklemiyor.\n\nUygulama Magisk yüklenmemiş gibi davranacak, lütfen en kısa sürede Magisk\'i yükseltin.</string>
|
||||
<string name="unsupport_general_title">Anormal Durum</string>
|
||||
<string name="unsupport_system_app_msg">Bu uygulamayı bir sistem uygulaması olarak çalıştırma desteklenmiyor. Lütfen uygulamayı bir kullanıcı uygulamasına geri döndürün.</string>
|
||||
<string name="unsupport_other_su_msg">Magisk\'ten olmayan bir \"su\" ikili dosyası algılandı. Lütfen başka kök çözümlerini kaldırın ve/veya Magisk\'i yeniden yükleyin.</string>
|
||||
<string name="unsupport_external_storage_msg">Magisk, harici depolama birimine kurulur. Lütfen uygulamayı dahili depolamaya taşıyın.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">Kök kaybolduğu için gizli Magisk uygulaması çalışmaya devam edemiyor. Lütfen orijinal APK\'yı geri yükleyin.</string>
|
||||
<string name="unsupport_system_app_msg">Bu uygulamanın sistem uygulaması olarak çalıştırılması desteklenmiyor. Lütfen uygulamayı bir kullanıcı uygulamasına geri yükleyin.</string>
|
||||
<string name="unsupport_other_su_msg">Magisk\'ten olmayan bir \"su\" ikilisi algılandı. Lütfen rakip kök çözümlerini kaldırın ve/veya Magisk\'i yeniden yükleyin.</string>
|
||||
<string name="unsupport_external_storage_msg">Magisk harici depolamaya yüklenmiş. Lütfen uygulamayı dahili depolamaya taşıyın.</string>
|
||||
<string name="unsupport_nonroot_stub_msg">Kök (root) kaybolduğu için gizli Magisk uygulaması çalışmaya devam edemiyor. Lütfen orijinal APK\'yı geri yükleyin.</string>
|
||||
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||
<string name="external_rw_permission_denied">Bu işlevi etkinleştirmek için depolama izni veriniz.</string>
|
||||
<string name="post_notifications_denied">Bu işlevi etkinleştirmek için bildirim izni veriniz.</string>
|
||||
<string name="install_unknown_denied">Bu işlevi etkinleştirmek için "Bilinmeyen uygulamaları yükle" ayarına izin veriniz.</string>
|
||||
<string name="add_shortcut_title">Ana ekrana kısayol ekle</string>
|
||||
<string name="add_shortcut_msg">Bu uygulamayı gizledikten sonra adını ve simgesini tanımak zorlaşabilir. Ana ekrana hoş bir kısayol eklemek ister misiniz?</string>
|
||||
<string name="add_shortcut_msg">Bu uygulamayı gizledikten sonra adını ve simgesini tanımak zorlaşabilir. Ana ekrana güzel bir kısayol eklemek ister misiniz?</string>
|
||||
<string name="app_not_found">Bu eylemi gerçekleştirecek uygulama bulunamadı</string>
|
||||
<string name="reboot_apply_change">Değişiklikleri uygulamak için yeniden başlatın</string>
|
||||
<string name="restore_app_confirmation">Bu işlem, gizli uygulamayı orijinal uygulama ile değiştirecektir. Bu işlemi yapmak istediğinizden emin misiniz?</string>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="enable_fg_service">false</bool>
|
||||
</resources>
|
|
@ -15,4 +15,6 @@
|
|||
|
||||
<drawable name="ic_launcher">@drawable/ic_logo</drawable>
|
||||
|
||||
<bool name="enable_fg_service">true</bool>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
<string name="reboot_bootloader">Reboot to Bootloader</string>
|
||||
<string name="reboot_download">Reboot to Download</string>
|
||||
<string name="reboot_edl">Reboot to EDL</string>
|
||||
<string name="reboot_safe_mode">Safe mode</string>
|
||||
<string name="module_version_author">%1$s by %2$s</string>
|
||||
<string name="module_state_remove">Remove</string>
|
||||
<string name="module_state_restore">Restore</string>
|
||||
|
|
256
build.py
256
build.py
|
@ -4,7 +4,6 @@ import glob
|
|||
import lzma
|
||||
import multiprocessing
|
||||
import os
|
||||
import os.path as op
|
||||
import platform
|
||||
import shutil
|
||||
import stat
|
||||
|
@ -13,6 +12,7 @@ import sys
|
|||
import tarfile
|
||||
import textwrap
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile
|
||||
|
||||
|
||||
|
@ -79,18 +79,16 @@ default_targets = ["magisk", "magiskinit", "magiskboot", "magiskpolicy", "busybo
|
|||
support_targets = default_targets + ["resetprop"]
|
||||
rust_targets = ["magisk", "magiskinit", "magiskboot", "magiskpolicy"]
|
||||
|
||||
sdk_path = os.environ["ANDROID_SDK_ROOT"]
|
||||
ndk_root = op.join(sdk_path, "ndk")
|
||||
ndk_path = op.join(ndk_root, "magisk")
|
||||
ndk_build = op.join(ndk_path, "ndk-build")
|
||||
rust_bin = op.join(ndk_path, "toolchains", "rust", "bin")
|
||||
llvm_bin = op.join(
|
||||
ndk_path, "toolchains", "llvm", "prebuilt", f"{os_name}-x86_64", "bin"
|
||||
)
|
||||
cargo = op.join(rust_bin, "cargo" + EXE_EXT)
|
||||
gradlew = op.join(".", "gradlew" + (".bat" if is_windows else ""))
|
||||
adb_path = op.join(sdk_path, "platform-tools", "adb" + EXE_EXT)
|
||||
native_gen_path = op.realpath(op.join("native", "out", "generated"))
|
||||
sdk_path = Path(os.environ["ANDROID_SDK_ROOT"])
|
||||
ndk_root = sdk_path / "ndk"
|
||||
ndk_path = ndk_root / "magisk"
|
||||
ndk_build = ndk_path / "ndk-build"
|
||||
rust_bin = ndk_path / "toolchains" / "rust" / "bin"
|
||||
llvm_bin = ndk_path / "toolchains" / "llvm" / "prebuilt" / f"{os_name}-x86_64" / "bin"
|
||||
cargo = rust_bin / f"cargo{EXE_EXT}"
|
||||
gradlew = Path("gradlew" + (".bat" if is_windows else "")).resolve()
|
||||
adb_path = sdk_path / "platform-tools" / f"adb{EXE_EXT}"
|
||||
native_gen_path = Path("native", "out", "generated").resolve()
|
||||
|
||||
# Global vars
|
||||
config = {}
|
||||
|
@ -98,7 +96,7 @@ STDOUT = None
|
|||
build_tools = None
|
||||
|
||||
|
||||
def mv(source, target):
|
||||
def mv(source: Path, target: Path):
|
||||
try:
|
||||
shutil.move(source, target)
|
||||
vprint(f"mv {source} -> {target}")
|
||||
|
@ -106,7 +104,7 @@ def mv(source, target):
|
|||
pass
|
||||
|
||||
|
||||
def cp(source, target):
|
||||
def cp(source: Path, target: Path):
|
||||
try:
|
||||
shutil.copyfile(source, target)
|
||||
vprint(f"cp {source} -> {target}")
|
||||
|
@ -114,7 +112,7 @@ def cp(source, target):
|
|||
pass
|
||||
|
||||
|
||||
def rm(file):
|
||||
def rm(file: Path):
|
||||
try:
|
||||
os.remove(file)
|
||||
vprint(f"rm {file}")
|
||||
|
@ -132,22 +130,11 @@ def rm_on_error(func, path, _):
|
|||
pass
|
||||
|
||||
|
||||
def rm_rf(path):
|
||||
def rm_rf(path: Path):
|
||||
vprint(f"rm -rf {path}")
|
||||
shutil.rmtree(path, ignore_errors=False, onerror=rm_on_error)
|
||||
|
||||
|
||||
def mkdir(path, mode=0o755):
|
||||
try:
|
||||
os.mkdir(path, mode)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def mkdir_p(path, mode=0o755):
|
||||
os.makedirs(path, mode, exist_ok=True)
|
||||
|
||||
|
||||
def execv(cmd, env=None):
|
||||
return subprocess.run(cmd, stdout=STDOUT, env=env)
|
||||
|
||||
|
@ -192,11 +179,13 @@ def load_config(args):
|
|||
config["versionCode"] = 1000000
|
||||
config["outdir"] = "out"
|
||||
|
||||
args.config = Path(args.config)
|
||||
|
||||
# Load prop files
|
||||
if op.exists(args.config):
|
||||
if args.config.exists():
|
||||
config.update(parse_props(args.config))
|
||||
|
||||
if op.exists("gradle.properties"):
|
||||
if Path("gradle.properties").exists():
|
||||
for key, value in parse_props("gradle.properties").items():
|
||||
if key.startswith("magisk."):
|
||||
config[key[7:]] = value
|
||||
|
@ -206,17 +195,19 @@ def load_config(args):
|
|||
except ValueError:
|
||||
error('Config error: "versionCode" is required to be an integer')
|
||||
|
||||
mkdir_p(config["outdir"])
|
||||
config["outdir"] = Path(config["outdir"])
|
||||
|
||||
config["outdir"].mkdir(mode=0o755, parents=True, exist_ok=True)
|
||||
global STDOUT
|
||||
STDOUT = None if args.verbose else subprocess.DEVNULL
|
||||
|
||||
|
||||
def clean_elf():
|
||||
if is_windows:
|
||||
elf_cleaner = op.join("tools", "elf-cleaner.exe")
|
||||
elf_cleaner = Path("tools", "elf-cleaner.exe")
|
||||
else:
|
||||
elf_cleaner = op.join("native", "out", "elf-cleaner")
|
||||
if not op.exists(elf_cleaner):
|
||||
elf_cleaner = Path("native", "out", "elf-cleaner")
|
||||
if not elf_cleaner.exists():
|
||||
execv(
|
||||
[
|
||||
"gcc",
|
||||
|
@ -231,7 +222,7 @@ def clean_elf():
|
|||
)
|
||||
args = [elf_cleaner, "--api-level", "23"]
|
||||
args.extend(
|
||||
op.join("native", "out", arch, bin)
|
||||
Path("native", "out", arch, bin)
|
||||
for arch in archs
|
||||
for bin in ["magisk", "magiskpolicy"]
|
||||
)
|
||||
|
@ -246,25 +237,23 @@ def run_ndk_build(flags):
|
|||
error("Build binary failed!")
|
||||
os.chdir("..")
|
||||
for arch in archs:
|
||||
for tgt in support_targets + ["libinit-ld.so", "libzygisk-ld.so"]:
|
||||
source = op.join("native", "libs", arch, tgt)
|
||||
target = op.join("native", "out", arch, tgt)
|
||||
for tgt in support_targets + ["libinit-ld.so"]:
|
||||
source = Path("native", "libs", arch, tgt)
|
||||
target = Path("native", "out", arch, tgt)
|
||||
mv(source, target)
|
||||
|
||||
|
||||
def run_cargo(cmds, triple="aarch64-linux-android"):
|
||||
env = os.environ.copy()
|
||||
env["PATH"] = f'{rust_bin}{os.pathsep}{env["PATH"]}'
|
||||
env["CARGO_BUILD_RUSTC"] = op.join(rust_bin, "rustc" + EXE_EXT)
|
||||
env["RUSTFLAGS"] = "-Clinker-plugin-lto"
|
||||
env["TARGET_CC"] = op.join(llvm_bin, "clang" + EXE_EXT)
|
||||
env["TARGET_CFLAGS"] = f"--target={triple}23"
|
||||
env["CARGO_BUILD_RUSTC"] = str(rust_bin / f"rustc{EXE_EXT}")
|
||||
env["RUSTFLAGS"] = f"-Clinker-plugin-lto -Zthreads={min(8, cpu_count)}"
|
||||
return execv([cargo, *cmds], env)
|
||||
|
||||
|
||||
def run_cargo_build(args):
|
||||
native_out = op.join("..", "out")
|
||||
mkdir(native_out)
|
||||
native_out = Path("..", "out")
|
||||
native_out.mkdir(mode=0o755, exist_ok=True)
|
||||
|
||||
targets = set(args.target) & set(rust_targets)
|
||||
if "resetprop" in args.target:
|
||||
|
@ -297,11 +286,11 @@ def run_cargo_build(args):
|
|||
if proc.returncode != 0:
|
||||
error("Build binary failed!")
|
||||
|
||||
arch_out = op.join(native_out, arch)
|
||||
mkdir(arch_out)
|
||||
arch_out = native_out / arch
|
||||
arch_out.mkdir(mode=0o755, exist_ok=True)
|
||||
for tgt in targets:
|
||||
source = op.join("target", rust_triple, rust_out, f"lib{tgt}.a")
|
||||
target = op.join(arch_out, f"lib{tgt}-rs.a")
|
||||
source = Path("target", rust_triple, rust_out, f"lib{tgt}.a")
|
||||
target = arch_out / f"lib{tgt}-rs.a"
|
||||
mv(source, target)
|
||||
|
||||
|
||||
|
@ -310,14 +299,14 @@ def run_cargo_cmd(args):
|
|||
STDOUT = None
|
||||
if len(args.commands) >= 1 and args.commands[0] == "--":
|
||||
args.commands = args.commands[1:]
|
||||
os.chdir(op.join("native", "src"))
|
||||
os.chdir(Path("native", "src"))
|
||||
run_cargo(args.commands)
|
||||
os.chdir(op.join("..", ".."))
|
||||
os.chdir(Path("..", ".."))
|
||||
|
||||
|
||||
def write_if_diff(file_name, text):
|
||||
def write_if_diff(file_name: Path, text: str):
|
||||
do_write = True
|
||||
if op.exists(file_name):
|
||||
if file_name.exists():
|
||||
with open(file_name, "r") as f:
|
||||
orig = f.read()
|
||||
do_write = orig != text
|
||||
|
@ -337,15 +326,12 @@ def binary_dump(src, var_name, compressor=xz):
|
|||
|
||||
|
||||
def dump_bin_header(args):
|
||||
mkdir_p(native_gen_path)
|
||||
native_gen_path.mkdir(mode=0o755, parents=True, exist_ok=True)
|
||||
for arch in archs:
|
||||
preload = op.join("native", "out", arch, "libinit-ld.so")
|
||||
preload = Path("native", "out", arch, "libinit-ld.so")
|
||||
with open(preload, "rb") as src:
|
||||
text = binary_dump(src, "init_ld_xz")
|
||||
preload = op.join("native", "out", arch, "libzygisk-ld.so")
|
||||
with open(preload, "rb") as src:
|
||||
text += binary_dump(src, "zygisk_ld", compressor=lambda x: x)
|
||||
write_if_diff(op.join(native_gen_path, f"{arch}_binaries.h"), text)
|
||||
write_if_diff(Path(native_gen_path, f"{arch}_binaries.h"), text)
|
||||
|
||||
|
||||
def dump_flag_header():
|
||||
|
@ -362,14 +348,14 @@ def dump_flag_header():
|
|||
flag_txt += f'#define MAGISK_VER_CODE {config["versionCode"]}\n'
|
||||
flag_txt += f"#define MAGISK_DEBUG {0 if args.release else 1}\n"
|
||||
|
||||
mkdir_p(native_gen_path)
|
||||
write_if_diff(op.join(native_gen_path, "flags.h"), flag_txt)
|
||||
native_gen_path.mkdir(mode=0o755, parents=True, exist_ok=True)
|
||||
write_if_diff(Path(native_gen_path, "flags.h"), flag_txt)
|
||||
|
||||
|
||||
def build_binary(args):
|
||||
# Verify NDK install
|
||||
try:
|
||||
with open(op.join(ndk_path, "ONDK_VERSION"), "r") as ondk_ver:
|
||||
with open(Path(ndk_path, "ONDK_VERSION"), "r") as ondk_ver:
|
||||
assert ondk_ver.read().strip(" \t\r\n") == config["ondkVersion"]
|
||||
except:
|
||||
error('Unmatched NDK. Please install/upgrade NDK with "build.py ndk"')
|
||||
|
@ -386,56 +372,50 @@ def build_binary(args):
|
|||
|
||||
header("* Building binaries: " + " ".join(args.target))
|
||||
|
||||
os.chdir(op.join("native", "src"))
|
||||
os.chdir(Path("native", "src"))
|
||||
run_cargo_build(args)
|
||||
os.chdir(op.join("..", ".."))
|
||||
os.chdir(Path("..", ".."))
|
||||
|
||||
dump_flag_header()
|
||||
|
||||
flag = ""
|
||||
clean = False
|
||||
|
||||
if "magisk" in args.target or "magiskinit" in args.target:
|
||||
flag += " B_PRELOAD=1"
|
||||
if "magisk" in args.target:
|
||||
flag += " B_MAGISK=1"
|
||||
clean = True
|
||||
|
||||
if "magiskpolicy" in args.target:
|
||||
flag += " B_POLICY=1"
|
||||
clean = True
|
||||
|
||||
if "test" in args.target:
|
||||
flag += " B_TEST=1"
|
||||
|
||||
if "magiskinit" in args.target:
|
||||
flag += " B_PRELOAD=1"
|
||||
|
||||
if "resetprop" in args.target:
|
||||
flag += " B_PROP=1"
|
||||
|
||||
if flag:
|
||||
run_ndk_build(flag)
|
||||
|
||||
flag = ""
|
||||
|
||||
if "magiskinit" in args.target:
|
||||
# magiskinit embeds preload.so
|
||||
dump_bin_header(args)
|
||||
flag += " B_INIT=1"
|
||||
|
||||
if "magiskboot" in args.target:
|
||||
flag += " B_BOOT=1"
|
||||
|
||||
if flag:
|
||||
run_ndk_build(flag)
|
||||
|
||||
# magiskinit and magisk embeds preload.so
|
||||
|
||||
flag = ""
|
||||
|
||||
if "magisk" in args.target:
|
||||
flag += " B_MAGISK=1"
|
||||
clean = True
|
||||
|
||||
if "magiskinit" in args.target:
|
||||
flag += " B_INIT=1"
|
||||
|
||||
if flag:
|
||||
dump_bin_header(args)
|
||||
flag += " B_CRT0=1"
|
||||
run_ndk_build(flag)
|
||||
|
||||
if clean:
|
||||
clean_elf()
|
||||
|
||||
# BusyBox is built with different libc
|
||||
# BusyBox is built with different API level
|
||||
|
||||
if "busybox" in args.target:
|
||||
run_ndk_build("B_BB=1")
|
||||
|
@ -445,10 +425,10 @@ def find_jdk():
|
|||
env = os.environ.copy()
|
||||
if "ANDROID_STUDIO" in env:
|
||||
studio = env["ANDROID_STUDIO"]
|
||||
jbr = op.join(studio, "jbr", "bin")
|
||||
if not op.exists(jbr):
|
||||
jbr = op.join(studio, "Contents", "jbr", "Contents", "Home", "bin")
|
||||
if op.exists(jbr):
|
||||
jbr = Path(studio, "jbr", "bin")
|
||||
if not jbr.exists():
|
||||
jbr = Path(studio, "Contents", "jbr", "Contents", "Home", "bin")
|
||||
if jbr.exists():
|
||||
env["PATH"] = f'{jbr}{os.pathsep}{env["PATH"]}'
|
||||
|
||||
no_jdk = False
|
||||
|
@ -481,7 +461,7 @@ def build_apk(args, module):
|
|||
[
|
||||
gradlew,
|
||||
f"{module}:assemble{build_type}",
|
||||
"-PconfigPath=" + op.abspath(args.config),
|
||||
f"-PconfigPath={args.config.resolve()}",
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
|
@ -491,10 +471,10 @@ def build_apk(args, module):
|
|||
build_type = build_type.lower()
|
||||
|
||||
apk = f"{module}-{build_type}.apk"
|
||||
source = op.join(module, "build", "outputs", "apk", build_type, apk)
|
||||
target = op.join(config["outdir"], apk)
|
||||
source = Path(module, "build", "outputs", "apk", build_type, apk)
|
||||
target = config["outdir"] / apk
|
||||
mv(source, target)
|
||||
header("Output: " + target)
|
||||
header(f"Output: {target}")
|
||||
|
||||
|
||||
def build_app(args):
|
||||
|
@ -505,8 +485,8 @@ def build_app(args):
|
|||
# build process. Copy the stub APK into output directory.
|
||||
build_type = "release" if args.release else "debug"
|
||||
apk = f"stub-{build_type}.apk"
|
||||
source = op.join("app", "src", build_type, "assets", "stub.apk")
|
||||
target = op.join(config["outdir"], apk)
|
||||
source = Path("app", "src", build_type, "assets", "stub.apk")
|
||||
target = config["outdir"] / apk
|
||||
cp(source, target)
|
||||
|
||||
|
||||
|
@ -527,30 +507,30 @@ def cleanup(args):
|
|||
|
||||
if "cpp" in args.target:
|
||||
header("* Cleaning C++")
|
||||
rm_rf(op.join("native", "libs"))
|
||||
rm_rf(op.join("native", "obj"))
|
||||
rm_rf(op.join("native", "out"))
|
||||
rm_rf(Path("native", "libs"))
|
||||
rm_rf(Path("native", "obj"))
|
||||
rm_rf(Path("native", "out"))
|
||||
|
||||
if "rust" in args.target:
|
||||
header("* Cleaning Rust")
|
||||
rm_rf(op.join("native", "src", "target"))
|
||||
rm(op.join("native", "src", "boot", "proto", "mod.rs"))
|
||||
rm(op.join("native", "src", "boot", "proto", "update_metadata.rs"))
|
||||
rm_rf(Path("native", "src", "target"))
|
||||
rm(Path("native", "src", "boot", "proto", "mod.rs"))
|
||||
rm(Path("native", "src", "boot", "proto", "update_metadata.rs"))
|
||||
for rs_gen in glob.glob("native/**/*-rs.*pp", recursive=True):
|
||||
rm(rs_gen)
|
||||
|
||||
if "java" in args.target:
|
||||
header("* Cleaning java")
|
||||
execv([gradlew, "app:clean", "app:shared:clean", "stub:clean"], env=find_jdk())
|
||||
rm_rf(op.join("app", "src", "debug"))
|
||||
rm_rf(op.join("app", "src", "release"))
|
||||
rm_rf(Path("app", "src", "debug"))
|
||||
rm_rf(Path("app", "src", "release"))
|
||||
|
||||
|
||||
def setup_ndk(args):
|
||||
ndk_ver = config["ondkVersion"]
|
||||
url = f"https://github.com/topjohnwu/ondk/releases/download/{ndk_ver}/ondk-{ndk_ver}-{os_name}.tar.xz"
|
||||
ndk_archive = url.split("/")[-1]
|
||||
ondk_path = op.join(ndk_root, f"ondk-{ndk_ver}")
|
||||
ondk_path = Path(ndk_root, f"ondk-{ndk_ver}")
|
||||
|
||||
header(f"* Downloading and extracting {ndk_archive}")
|
||||
rm_rf(ondk_path)
|
||||
|
@ -561,34 +541,15 @@ def setup_ndk(args):
|
|||
rm_rf(ndk_path)
|
||||
mv(ondk_path, ndk_path)
|
||||
|
||||
header("* Patching static libs")
|
||||
for target in ["arm-linux-androideabi", "i686-linux-android"]:
|
||||
arch = target.split("-")[0]
|
||||
lib_dir = op.join(
|
||||
ndk_path,
|
||||
"toolchains",
|
||||
"llvm",
|
||||
"prebuilt",
|
||||
f"{os_name}-x86_64",
|
||||
"sysroot",
|
||||
"usr",
|
||||
"lib",
|
||||
f"{target}",
|
||||
"23",
|
||||
)
|
||||
if not op.exists(lib_dir):
|
||||
continue
|
||||
src_dir = op.join("tools", "ndk-bins", arch)
|
||||
rm(op.join(src_dir, ".DS_Store"))
|
||||
shutil.copytree(src_dir, lib_dir, copy_function=cp, dirs_exist_ok=True)
|
||||
|
||||
|
||||
def push_files(args, script):
|
||||
abi = cmd_out([adb_path, "shell", "getprop", "ro.product.cpu.abi"])
|
||||
apk = config["outdir"] + ("/app-release.apk" if args.release else "/app-debug.apk")
|
||||
apk = Path(
|
||||
config["outdir"], ("app-release.apk" if args.release else "app-debug.apk")
|
||||
)
|
||||
|
||||
# Extract busybox from APK
|
||||
busybox = f'{config["outdir"]}/busybox'
|
||||
busybox = Path(config["outdir"], "busybox")
|
||||
with ZipFile(apk) as zf:
|
||||
with zf.open(f"lib/{abi}/libbusybox.so") as libbb:
|
||||
with open(busybox, "wb") as bb:
|
||||
|
@ -612,7 +573,7 @@ def setup_avd(args):
|
|||
|
||||
header("* Setting up emulator")
|
||||
|
||||
push_files(args, "scripts/avd_magisk.sh")
|
||||
push_files(args, Path("scripts", "avd_magisk.sh"))
|
||||
|
||||
proc = execv([adb_path, "shell", "sh", "/data/local/tmp/avd_magisk.sh"])
|
||||
if proc.returncode != 0:
|
||||
|
@ -624,26 +585,28 @@ def patch_avd_ramdisk(args):
|
|||
args.release = False
|
||||
build_all(args)
|
||||
|
||||
args.ramdisk = Path(args.ramdisk)
|
||||
|
||||
header("* Patching emulator ramdisk.img")
|
||||
|
||||
# Create a backup to prevent accidental overwrites
|
||||
backup = args.ramdisk + ".bak"
|
||||
if not op.exists(backup):
|
||||
backup = args.ramdisk.parent / f"{args.ramdisk.name}.bak"
|
||||
if not backup.exists():
|
||||
cp(args.ramdisk, backup)
|
||||
|
||||
ini = op.join(op.dirname(args.ramdisk), "advancedFeatures.ini")
|
||||
ini = args.ramdisk.parent / "advancedFeatures.ini"
|
||||
with open(ini, "r") as f:
|
||||
adv_ft = f.read()
|
||||
|
||||
# Need to turn off system as root
|
||||
if "SystemAsRoot = on" in adv_ft:
|
||||
# Create a backup
|
||||
cp(ini, ini + ".bak")
|
||||
cp(ini, ini.parent / f"{ini.name}.bak")
|
||||
adv_ft = adv_ft.replace("SystemAsRoot = on", "SystemAsRoot = off")
|
||||
with open(ini, "w") as f:
|
||||
f.write(adv_ft)
|
||||
|
||||
push_files(args, "scripts/avd_patch.sh")
|
||||
push_files(args, Path("scripts", "avd_patch.sh"))
|
||||
|
||||
proc = execv([adb_path, "push", backup, "/data/local/tmp/ramdisk.cpio.tmp"])
|
||||
if proc.returncode != 0:
|
||||
|
@ -663,6 +626,31 @@ def build_all(args):
|
|||
build_app(args)
|
||||
|
||||
|
||||
def setup_rustup(args):
|
||||
wrapper_dir = Path(args.wrapper_dir)
|
||||
rm_rf(wrapper_dir)
|
||||
wrapper_dir.mkdir(mode=0o755, parents=True, exist_ok=True)
|
||||
if "CARGO_HOME" in os.environ:
|
||||
cargo_home = Path(os.environ["CARGO_HOME"])
|
||||
else:
|
||||
cargo_home = Path.home() / ".cargo"
|
||||
cargo_bin = cargo_home / "bin"
|
||||
for src in cargo_bin.iterdir():
|
||||
tgt = wrapper_dir / src.name
|
||||
tgt.symlink_to(src)
|
||||
|
||||
# Build rustup_wrapper
|
||||
wrapper_src = Path("tools", "rustup_wrapper")
|
||||
cargo_toml = wrapper_src / "Cargo.toml"
|
||||
execv([cargo, "build", "--release", f"--manifest-path={cargo_toml}"])
|
||||
|
||||
# Replace rustup with wrapper
|
||||
wrapper = wrapper_dir / (f"rustup{EXE_EXT}")
|
||||
wrapper.unlink(missing_ok=True)
|
||||
cp(wrapper_src / "target" / "release" / (f"rustup_wrapper{EXE_EXT}"), wrapper)
|
||||
wrapper.chmod(0o755)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description="Magisk build script")
|
||||
parser.set_defaults(func=lambda x: None)
|
||||
parser.add_argument(
|
||||
|
@ -693,6 +681,10 @@ cargo_parser = subparsers.add_parser("cargo", help="run cargo with proper enviro
|
|||
cargo_parser.add_argument("commands", nargs=argparse.REMAINDER)
|
||||
cargo_parser.set_defaults(func=run_cargo_cmd)
|
||||
|
||||
rustup_parser = subparsers.add_parser("rustup", help="setup rustup wrapper")
|
||||
rustup_parser.add_argument("wrapper_dir", help="path to setup rustup wrapper binaries")
|
||||
rustup_parser.set_defaults(func=setup_rustup)
|
||||
|
||||
app_parser = subparsers.add_parser("app", help="build the Magisk app")
|
||||
app_parser.set_defaults(func=build_app)
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ gradlePlugin {
|
|||
|
||||
dependencies {
|
||||
implementation(embeddedKotlin("gradle-plugin"))
|
||||
implementation("com.android.tools.build:gradle:8.1.2")
|
||||
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.4")
|
||||
implementation("com.android.tools.build:gradle:8.4.0")
|
||||
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.7")
|
||||
implementation("org.lsposed.lsparanoid:gradle-plugin:0.5.2")
|
||||
implementation("org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r")
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ fun Project.setupCommon() {
|
|||
compileSdkVersion(34)
|
||||
buildToolsVersion = "34.0.0"
|
||||
ndkPath = "$sdkDirectory/ndk/magisk"
|
||||
ndkVersion = "27.0.11718014"
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
|
@ -165,6 +166,10 @@ private fun Project.setupAppCommon() {
|
|||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
buildConfigField("int", "STUB_VERSION", Config.stubVersion)
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
signingConfigs["config"].also {
|
||||
debug {
|
||||
|
@ -226,25 +231,25 @@ fun Project.setupApp() {
|
|||
into("armeabi-v7a") {
|
||||
from(rootProject.file("native/out/armeabi-v7a")) {
|
||||
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
|
||||
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
|
||||
rename { "lib$it.so" }
|
||||
}
|
||||
}
|
||||
into("x86") {
|
||||
from(rootProject.file("native/out/x86")) {
|
||||
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
|
||||
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
|
||||
rename { "lib$it.so" }
|
||||
}
|
||||
}
|
||||
into("arm64-v8a") {
|
||||
from(rootProject.file("native/out/arm64-v8a")) {
|
||||
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
|
||||
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
|
||||
rename { "lib$it.so" }
|
||||
}
|
||||
}
|
||||
into("x86_64") {
|
||||
from(rootProject.file("native/out/x86_64")) {
|
||||
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
|
||||
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
|
||||
rename { "lib$it.so" }
|
||||
}
|
||||
}
|
||||
onlyIf {
|
||||
|
@ -336,7 +341,7 @@ fun Project.setupStub() {
|
|||
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
|
||||
val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2")
|
||||
val apk = layout.buildDirectory.file("intermediates/processed_res/" +
|
||||
"${variantLowered}/out/resources-${variantLowered}.ap_").get().asFile
|
||||
"${variantLowered}/process${variantCapped}Resources/out/resources-${variantLowered}.ap_").get().asFile
|
||||
|
||||
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
|
||||
inputs.property("seed", RAND_SEED)
|
||||
|
@ -378,9 +383,9 @@ fun Project.setupStub() {
|
|||
}
|
||||
// Override optimizeReleaseResources task
|
||||
val apk = layout.buildDirectory.file("intermediates/processed_res/" +
|
||||
"release/out/resources-release.ap_").get().asFile
|
||||
"release/processReleaseResources/out/resources-release.ap_").get().asFile
|
||||
val optRes = layout.buildDirectory.file("intermediates/optimized_processed_res/" +
|
||||
"release/resources-release-optimize.ap_").get().asFile
|
||||
"release/optimizeReleaseResources/resources-release-optimize.ap_").get().asFile
|
||||
afterEvaluate {
|
||||
tasks.named("optimizeReleaseResources") {
|
||||
doLast { apk.copyTo(optRes, true) }
|
||||
|
|
|
@ -34,13 +34,15 @@
|
|||
|
||||
## IDE Support
|
||||
|
||||
- The repository can be directly opened with Android Studio as a project.
|
||||
- The Kotlin, Java, C++, and C code in the project should be properly supported in Android Studio out of the box.
|
||||
- Run `./build.py binary` before working on native code, as some generated code is only created during the build process.
|
||||
- Kotlin, Java, C++, and C code in the project should be supported in Android Studio out of the box. This repository can be directly opened with Android Studio as a project.
|
||||
- For Rust development, see the next section.
|
||||
- Before working on any native code, build all native code first with `./build.py binary`, as some generated code is only created during the build process.
|
||||
|
||||
### Developing Rust in Android Studio
|
||||
### Developing Rust
|
||||
|
||||
Because the Magisk NDK package, [ONDK](https://github.com/topjohnwu/ondk) (the one installed with `./build.py ndk`), contains a fully self contained Clang + Rust toolchain, building the Magisk project alone does not require configuring toolchains. However, due to the way the IntelliJ Rust plugin works, you'll have to go through some additional setup to make Android Studio work with Magisk's Rust codebase:
|
||||
The Magisk NDK package [ONDK](https://github.com/topjohnwu/ondk) (the one installed with `./build.py ndk`) bundles a complete Rust toolchain, so *building* the Magisk project itself does not require any further configuration. However, if you'd like to work on the Rust codebase with proper support, you'd need some setup as most development tools are built around `rustup`.
|
||||
|
||||
Let's first setup `rustup` to use our custom ONDK Rust toolchain by default:
|
||||
|
||||
- Install [rustup](https://rustup.rs/), the official Rust toolchain manager
|
||||
- Link the ONDK Rust toolchain and set it as default:
|
||||
|
@ -48,13 +50,30 @@ Because the Magisk NDK package, [ONDK](https://github.com/topjohnwu/ondk) (the o
|
|||
```bash
|
||||
# Link the ONDK toolchain with the name "magisk"
|
||||
rustup toolchain link magisk "$ANDROID_SDK_ROOT/ndk/magisk/toolchains/rust"
|
||||
# Set as default
|
||||
# Set magisk as default
|
||||
rustup default magisk
|
||||
```
|
||||
|
||||
- Install the [Intellij Rust plugin](https://www.jetbrains.com/rust/) in Android Studio
|
||||
- In Preferences > Languages & Frameworks > Rust, set `$ANDROID_SDK_ROOT/ndk/magisk/toolchains/rust/bin` as the toolchain location
|
||||
- Open `native/src/Cargo.toml`, and select "Attach" in the "No Cargo projects found" banner
|
||||
If you plan to use VSCode, you can then install the [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) plugin and everything should be good to go. If you plan to use Jetbrain IDEs (e.g. [Rustrover](https://www.jetbrains.com/rust/), or its Rust Plugin), due to its poor support with custom toolchains, we need some additional setup:
|
||||
|
||||
- Install the official nightly toolchain and add some components. We won't actually use the nightly toolchain for anything other than tricking the IDE to cooperate; the magic happens in the wrapper we setup in the next step.
|
||||
|
||||
```bash
|
||||
rustup toolchain install nightly
|
||||
# Add some components that is also included in ONDK
|
||||
rustup +nightly component add rust-src clippy
|
||||
```
|
||||
|
||||
- Create a wrapper cargo bin directory to workaround `rustup` limitations
|
||||
|
||||
```bash
|
||||
# We choose ~/.cargo/wrapper here as an example (and a good recommendation)
|
||||
# Pick any path you like, you just need to use this path in the next step
|
||||
./build.py rustup ~/.cargo/wrapper
|
||||
```
|
||||
|
||||
- In Settings > Rust > Toolchain location, set this to the path of the wrapper directory we just created.
|
||||
- The IDE should now be fully functional, and you are able to enable `rustfmt` and use `Clippy` as the external linter.
|
||||
|
||||
## Signing and Distribution
|
||||
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# Magisk Changelog
|
||||
|
||||
### v27.0
|
||||
|
||||
- [Zygisk] Introduce new code injection mechanism
|
||||
- [Zygisk] Support new signature introduced in U QPR2
|
||||
- [SEPolicy] Update libsepol to properly set some policy config bits
|
||||
- [MagiskBoot] Support compressing `init` so Magisk is installable on devices with small boot partitions
|
||||
- [ResetProp] Add new wait for property feature `resetprop -w`
|
||||
|
||||
### v26.4
|
||||
|
||||
- [MagiskBoot] Don't pad zeros if signed boot image is larger
|
||||
|
|
|
@ -110,4 +110,4 @@ Before Android 8.0, all allowed su client domains are allowed to directly connec
|
|||
|
||||
After Android 8.0, to reduce relaxation of rules in Android's sandbox, a new SELinux model is deployed. The `magisk` binary is labelled with `magisk_exec` file type, and processes running as allowed su client domains executing the `magisk` binary (this includes the `su` command) will transit to `magisk_client` by using a `type_transition` rule. Rules strictly restrict that only `magisk` domain processes are allowed to attribute files to `magisk_exec`. Direct connection to sockets of `magiskd` are not allowed; the only way to access the daemon is through a `magisk_client` process. These changes allow us to keep the sandbox intact, and keep Magisk specific rules separated from the rest of the policies.
|
||||
|
||||
The full set of rules can be found in `magiskpolicy/rules.cpp`.
|
||||
The full set of rules can be found in `sepolicy/rules.cpp`.
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
|
||||
If you have USB debugging enabled in developer options, connect your phone to the PC. If your device is detected (check by `adb devices`), enter ADB shell and run the command `magisk --remove-modules`. This will remove all your modules and automatically reboot the device.
|
||||
|
||||
If unfortunately you do not have USB debugging enabled, reboot into Safe Mode. Most modern Android devices support pressing a special key combo at boot to enter Safe Mode as an emergency option. Magisk will detect Safe Mode being activated, and all modules will be disabled. Then reboot back to normal mode (the module disable state persists) and manage your modules through the Magisk app.
|
||||
If unfortunately you do not have USB debugging enabled you can boot using the Safe Mode key combo to cause Magisk to create an empty file named 'disable' in modules directories which disables modules when next booted with Magisk. Most modern Android devices support such a special key combo at boot to enter system Safe Mode as an emergency option, but **please note** that Magisk's key combo detection occurs _earlier_ than system detection so the key combo timing indicated by many online guides may need to be altered to activate Magisk's Safe Mode. (It's possible to activate system Safe Mode but not Magisk Safe Mode and vice versa.)
|
||||
|
||||
The following details should ensure that modules are properly disabled:
|
||||
1) Many online guides for entering Safe Mode say 'When the animated logo appears, press and hold the volume down button until the system boots' or similar. This may actually be _too late_ for Magisk detection however and result in activating system Safe Mode but modules are not disabled.
|
||||
2) By pressing the volume down button some seconds before the animation and releasing it as soon as the boot animation appears, Magisk's Safe Mode should be activated without activating system Safe Mode (thus avoiding disabling other device and app settings) and the device should then simply boot to normal system with modules disabled.
|
||||
3) By pressing the volume down button some seconds before the animation and holding it until the system boots, both Magisk's Safe Mode and system Safe Mode should be activated. Next, after booting back to normal system, modules will be disabled.
|
||||
|
||||
### Q: Why is X app detecting root?
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ Update JSON format:
|
|||
|
||||
#### Shell scripts (`*.sh`)
|
||||
|
||||
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script.
|
||||
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script. If you need to wait for boot completed, you can use `resetprop -w sys.boot_completed 0`.
|
||||
|
||||
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
|
||||
If Zygisk is enabled, the environment variable `ZYGISK_ENABLED` will be set to `1`.
|
||||
|
@ -265,7 +265,7 @@ Overlay files shall be placed in the `overlay.d` folder in boot image ramdisk, a
|
|||
|
||||
To add additional files which you can refer to in your custom `*.rc` scripts, add them into `overlay.d/sbin`. The 3 rules above do not apply to anything in this folder; instead, they will be directly copied to Magisk's internal `tmpfs` directory (which used to always be `/sbin`).
|
||||
|
||||
Starting from Android 11, the `/sbin` folder may no longer exists, and in that scenario, Magisk randomly generates a different `tmpfs` folder each boot. Every occurrence of the pattern `${MAGISKTMP}` in your `*.rc` scripts will be replaced with the Magisk `tmpfs` folder when `magiskinit` injects it into `init.rc`. On pre Android 11 devices, `${MAGISKTMP}` will simply be replaced with `/sbin`, so **NEVER** hardcode `/sbin` in the `*.rc` scripts when referencing these additional files.
|
||||
Starting from Android 11, the `/sbin` folder may no longer exists, and in that scenario, Magisk uses `/debug_ramdisk` instead. Every occurrence of the pattern `${MAGISKTMP}` in your `*.rc` scripts will be replaced with the Magisk `tmpfs` folder when `magiskinit` injects it into `init.rc`. On pre Android 11 devices, `${MAGISKTMP}` will simply be replaced with `/sbin`, so **NEVER** hardcode `/sbin` in the `*.rc` scripts when referencing these additional files.
|
||||
|
||||
Here is an example of how to setup `overlay.d` with a custom `*.rc` script:
|
||||
|
||||
|
|
|
@ -26,19 +26,10 @@ If your device has boot ramdisk, get a copy of the `boot.img` (or `init_boot.img
|
|||
If your device does **NOT** have boot ramdisk, get a copy of the `recovery.img`.<br>
|
||||
You should be able to extract the file you need from official firmware packages or your custom ROM zip.
|
||||
|
||||
Next, we need to know whether your device has a separate `vbmeta` partition.
|
||||
|
||||
- If your official firmware package contains `vbmeta.img`, then yes, your device **has** a separate `vbmeta` partition
|
||||
- You can also check by connecting your device to a PC and run the command:<br>
|
||||
`adb shell ls -l /dev/block/by-name`
|
||||
- If you find `vbmeta`, `vbmeta_a`, or `vbmeta_b`, then yes, your device **has** a separate `vbmeta` partition
|
||||
- Otherwise, your device **does not** have a separate `vbmeta` partition.
|
||||
|
||||
Quick recap, at this point, you should have known and prepared:
|
||||
|
||||
1. Whether your device has boot ramdisk
|
||||
2. Whether your device has a separate `vbmeta` partition
|
||||
3. A `boot.img`, `init_boot.img` or `recovery.img` based on (1)
|
||||
2. A `boot.img`, `init_boot.img` or `recovery.img` based on (1)
|
||||
|
||||
Let's continue to [Patching Images](#patching-images).
|
||||
|
||||
|
@ -47,21 +38,21 @@ Let's continue to [Patching Images](#patching-images).
|
|||
- Copy the boot/init_boot/recovery image to your device
|
||||
- Press the **Install** button in the Magisk card
|
||||
- If you are patching a recovery image, check the **"Recovery Mode"** option
|
||||
- If your device does **NOT** have a separate `vbmeta` partition, check the **"Patch vbmeta in boot image"** option
|
||||
- Choose **"Select and Patch a File"** in method, and select the boot/init_boot/recovery image
|
||||
- Start the installation, and copy the patched image to your PC using ADB:<br>
|
||||
`adb pull /sdcard/Download/magisk_patched_[random_strings].img`
|
||||
- Flash the patched boot/init_boot/recovery image to your device;<br>
|
||||
for most devices, reboot into fastboot mode and flash with command:<br>
|
||||
`fastboot flash boot[_x] /path/to/magisk_patched_[random_strings].img` or <br>
|
||||
`fastboot flash init_boot[_x] /path/to/magisk_patched.img_[random_strings]` or <br>
|
||||
`fastboot flash boot /path/to/magisk_patched_[random_strings].img` or <br>
|
||||
`fastboot flash init_boot /path/to/magisk_patched.img_[random_strings]` or <br>
|
||||
`fastboot flash recovery /path/to/magisk_patched.img_[random_strings]`, <br>
|
||||
where `[_x]` should be `_a` or `_b` or empty depending on your device
|
||||
- (Optional) If your device has a separate `vbmeta` partition, you can patch the `vbmeta` partition with command:<br>
|
||||
`fastboot flash vbmeta --disable-verity --disable-verification vbmeta.img` (note that it may **wipe your data**)
|
||||
- Reboot and launch Magisk app (you will see a stub Magisk app if you have wiped your data; use it to bootstrap to a complete Magisk app), and you will see a prompt asking for environment fix; click and wait for the reboot
|
||||
- Voila!
|
||||
|
||||
> Warning: **NEVER** flash patched image shared by others or patch image on another device even if they have the same device model! You may need to do a full data wipe to recover your device. **ALWAYS** patch boot image **on the same device where you want to install Magisk**.
|
||||
|
||||
## Uninstallation
|
||||
|
||||
The easiest way to uninstall Magisk is directly through the Magisk app. If you insist on using custom recoveries, rename the Magisk APK to `uninstall.zip` and flash it like any other ordinary flashable zip.
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
## 2024.2.3 Magisk v27.0
|
||||
|
||||
- [Zygisk] Introduce new code injection mechanism
|
||||
- [Zygisk] Support new signature introduced in U QPR2
|
||||
- [SEPolicy] Update libsepol to properly set some policy config bits
|
||||
- [MagiskBoot] Support compressing `init` so Magisk is installable on devices with small boot partitions
|
||||
- [ResetProp] Add new wait for property feature `resetprop -w`
|
||||
|
||||
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)
|
|
@ -1,5 +1,6 @@
|
|||
# Release Notes
|
||||
|
||||
- [v27.0](27000.md)
|
||||
- [v26.4](26400.md)
|
||||
- [v26.3](26300.md)
|
||||
- [v26.2](26200.md)
|
||||
|
|
|
@ -16,7 +16,7 @@ su -> magisk
|
|||
|
||||
A tool to unpack / repack boot images, parse / patch / extract cpio, patch dtb, hex patch binaries, and compress / decompress files with multiple algorithms.
|
||||
|
||||
`magiskboot` natively supports (which means it does not rely on external tools) common compression formats including `gzip`, `lz4`, `lz4_legacy` ([only used on LG](https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf)), `lzma`, `xz`, and `bzip2`.
|
||||
`magiskboot` natively supports (which means it does not rely on external tools) common compression formats including `gzip`, `lz4`, `lz4_legacy` , `lz4_lg` ([the LG edition](https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf) of `lz4_legacy`, only used on LG), `lzma`, `xz`, and `bzip2`.
|
||||
|
||||
The concept of `magiskboot` is to make boot image modification simpler. For unpacking, it parses the header and extracts all sections in the image, decompressing on-the-fly if compression is detected in any sections. For repacking, the original boot image is required so the original headers can be used, changing only the necessary entries such as section sizes and checksum. All sections will be compressed back to the original format if required. The tool also supports many CPIO and DTB operations.
|
||||
|
||||
|
@ -51,6 +51,28 @@ Supported actions:
|
|||
If env variable PATCHVBMETAFLAG is set to true, all disable flags in
|
||||
the boot image's vbmeta header will be set.
|
||||
|
||||
verify <bootimg> [x509.pem]
|
||||
Check whether the boot image is signed with AVB 1.0 signature.
|
||||
Optionally provide a certificate to verify whether the image is
|
||||
signed by the public key certificate.
|
||||
Return value:
|
||||
0:valid 1:error
|
||||
|
||||
sign <bootimg> [name] [x509.pem pk8]
|
||||
Sign <bootimg> with AVB 1.0 signature.
|
||||
Optionally provide the name of the image (default: '/boot').
|
||||
Optionally provide the certificate/private key pair for signing.
|
||||
If the certificate/private key pair is not provided, the AOSP
|
||||
verity key bundled in the executable will be used.
|
||||
|
||||
extract <payload.bin> [partition] [outfile]
|
||||
Extract [partition] from <payload.bin> to [outfile].
|
||||
If [outfile] is not specified, then output to '[partition].img'.
|
||||
If [partition] is not specified, then attempt to extract either
|
||||
'init_boot' or 'boot'. Which partition was chosen can be determined
|
||||
by whichever 'init_boot.img' or 'boot.img' exists.
|
||||
<payload.bin> can be '-' to be STDIN.
|
||||
|
||||
hexpatch <file> <hexpattern1> <hexpattern2>
|
||||
Search <hexpattern1> in <file>, and replace it with <hexpattern2>
|
||||
|
||||
|
@ -75,7 +97,7 @@ Supported actions:
|
|||
test
|
||||
Test the cpio's status
|
||||
Return value is 0 or bitwise or-ed of following values:
|
||||
0x1:Magisk 0x2:unsupported 0x4:Sony
|
||||
0x1:Magisk 0x2:unsupported
|
||||
patch
|
||||
Apply ramdisk patches
|
||||
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
|
||||
|
@ -83,8 +105,6 @@ Supported actions:
|
|||
Create ramdisk backups from ORIG
|
||||
restore
|
||||
Restore ramdisk from ramdisk backup stored within incpio
|
||||
sha1
|
||||
Print stock boot SHA1 if previously backed up in ramdisk
|
||||
|
||||
dtb <file> <action> [args...]
|
||||
Do dtb related actions to <file>
|
||||
|
@ -222,7 +242,7 @@ Options:
|
|||
-v print running daemon version
|
||||
-V print running daemon version code
|
||||
--list list all available applets
|
||||
--remove-modules remove all modules and reboot
|
||||
--remove-modules [-n] remove all modules, reboot if -n is not provided
|
||||
--install-module ZIP install a module zip file
|
||||
|
||||
Advanced Options (Internal APIs):
|
||||
|
@ -237,6 +257,7 @@ Advanced Options (Internal APIs):
|
|||
--sqlite SQL exec SQL commands to Magisk database
|
||||
--path print Magisk tmpfs mount path
|
||||
--denylist ARGS denylist config CLI
|
||||
--preinit-device resolve a device to store preinit files
|
||||
|
||||
Available applets:
|
||||
su, resetprop
|
||||
|
@ -261,20 +282,24 @@ An applet of `magisk`, the MagiskSU entry point. Good old `su` command.
|
|||
Usage: su [options] [-] [user [argument...]]
|
||||
|
||||
Options:
|
||||
-c, --command COMMAND pass COMMAND to the invoked shell
|
||||
-h, --help display this help message and exit
|
||||
-, -l, --login pretend the shell to be a login shell
|
||||
-c, --command COMMAND Pass COMMAND to the invoked shell
|
||||
-g, --group GROUP Specify the primary group
|
||||
-G, --supp-group GROUP Specify a supplementary group.
|
||||
The first specified supplementary group is also used
|
||||
as a primary group if the option -g is not specified.
|
||||
-Z, --context CONTEXT Change SELinux context
|
||||
-t, --target PID PID to take mount namespace from
|
||||
-h, --help Display this help message and exit
|
||||
-, -l, --login Pretend the shell to be a login shell
|
||||
-m, -p,
|
||||
--preserve-environment preserve the entire environment
|
||||
-s, --shell SHELL use SHELL instead of the default /system/bin/sh
|
||||
-v, --version display version number and exit
|
||||
-V display version code and exit
|
||||
--preserve-environment Preserve the entire environment
|
||||
-s, --shell SHELL Use SHELL instead of the default /system/bin/sh
|
||||
-v, --version Display version number and exit
|
||||
-V Display version code and exit
|
||||
-mm, -M,
|
||||
--mount-master force run in the global mount namespace
|
||||
--mount-master Force run in the global mount namespace
|
||||
```
|
||||
|
||||
Note: even though the `-Z, --context` option is not listed above, the option still exists for CLI compatibility with apps designed for SuperSU. However the option is silently ignored since it's no longer relevant.
|
||||
|
||||
### resetprop
|
||||
|
||||
An applet of `magisk`. An advanced system property manipulation utility. Check the [Resetprop Details](details.md#resetprop) for more background information.
|
||||
|
|
|
@ -26,6 +26,6 @@ android.injected.testOnly=false
|
|||
android.nonFinalResIds=false
|
||||
|
||||
# Magisk
|
||||
magisk.stubVersion=38
|
||||
magisk.versionCode=26400
|
||||
magisk.ondkVersion=r26.1
|
||||
magisk.stubVersion=39
|
||||
magisk.versionCode=27002
|
||||
magisk.ondkVersion=r27.1
|
||||
|
|
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ plugins {
|
|||
setupCommon()
|
||||
|
||||
android {
|
||||
namespace = "com.topjohnwu.magisk.native"
|
||||
namespace = "com.topjohnwu.magisk.binary"
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
|
@ -22,7 +22,8 @@ android {
|
|||
ndkBuild {
|
||||
// Pass arguments to ndk-build.
|
||||
arguments(
|
||||
"B_MAGISK=1", "B_INIT=1", "B_BOOT=1", "B_TEST=1", "B_POLICY=1", "B_PRELOAD=1", "B_PROP=1"
|
||||
"B_MAGISK=1", "B_INIT=1", "B_BOOT=1", "B_POLICY=1",
|
||||
"B_PRELOAD=1", "B_PROP=1", "B_CRT0=1"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,19 +7,3 @@ target = "aarch64-linux-android"
|
|||
build-std = ["std", "panic_abort"]
|
||||
build-std-features = ["panic_immediate_abort"]
|
||||
profile-rustflags = true
|
||||
|
||||
# Workaround bug for undefined symbol errors that occur with the
|
||||
# combination of `-Zbuild-std`, `opt-level = "z"`, and `lto = true`.
|
||||
# compiler_builtins are expected to be built with special flags.
|
||||
# https://github.com/rust-lang/rust/issues/108853
|
||||
# https://github.com/rust-lang/wg-cargo-std-aware/issues/62
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
rustflags = ["-Zshare-generics=off"]
|
||||
overflow-checks = false
|
||||
debug-assertions = false
|
||||
|
||||
[profile.dev.package.compiler_builtins]
|
||||
rustflags = ["-Zshare-generics=off"]
|
||||
overflow-checks = false
|
||||
debug-assertions = false
|
||||
|
|
|
@ -8,6 +8,7 @@ LIBRARY_PATH = ../out/$(TARGET_ARCH_ABI)/libmagisk-rs.a
|
|||
ifneq (,$(wildcard $(LOCAL_PATH)/$(LIBRARY_PATH)))
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magisk-rs
|
||||
LOCAL_EXPORT_C_INCLUDES := src/core/include
|
||||
LOCAL_SRC_FILES := $(LIBRARY_PATH)
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
||||
|
|
|
@ -11,7 +11,6 @@ LOCAL_MODULE := magisk
|
|||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libsystemproperties \
|
||||
libphmap \
|
||||
liblsplt \
|
||||
libmagisk-rs
|
||||
|
||||
|
@ -27,20 +26,19 @@ LOCAL_SRC_FILES := \
|
|||
core/selinux.cpp \
|
||||
core/module.cpp \
|
||||
core/thread.cpp \
|
||||
core/resetprop/resetprop.cpp \
|
||||
core/core-rs.cpp \
|
||||
core/resetprop/resetprop.cpp \
|
||||
core/su/su.cpp \
|
||||
core/su/connect.cpp \
|
||||
core/su/pts.cpp \
|
||||
core/su/su_daemon.cpp \
|
||||
zygisk/entry.cpp \
|
||||
zygisk/main.cpp \
|
||||
zygisk/utils.cpp \
|
||||
zygisk/hook.cpp \
|
||||
zygisk/memory.cpp \
|
||||
zygisk/deny/cli.cpp \
|
||||
zygisk/deny/utils.cpp \
|
||||
zygisk/deny/revert.cpp
|
||||
core/zygisk/entry.cpp \
|
||||
core/zygisk/main.cpp \
|
||||
core/zygisk/module.cpp \
|
||||
core/zygisk/hook.cpp \
|
||||
core/deny/cli.cpp \
|
||||
core/deny/utils.cpp \
|
||||
core/deny/logcat.cpp
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
LOCAL_LDFLAGS := -Wl,--dynamic-list=src/exported_sym.txt
|
||||
|
@ -57,12 +55,6 @@ LOCAL_SRC_FILES := init/preload.c
|
|||
LOCAL_STRIP_MODE := --strip-all
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := zygisk-ld
|
||||
LOCAL_SRC_FILES := zygisk/loader.c
|
||||
LOCAL_STRIP_MODE := --strip-all
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
endif
|
||||
|
||||
ifdef B_INIT
|
||||
|
@ -71,7 +63,6 @@ include $(CLEAR_VARS)
|
|||
LOCAL_MODULE := magiskinit
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libcompat \
|
||||
libpolicy \
|
||||
libxz \
|
||||
libinit-rs
|
||||
|
@ -85,6 +76,12 @@ LOCAL_SRC_FILES := \
|
|||
init/selinux.cpp \
|
||||
init/init-rs.cpp
|
||||
|
||||
LOCAL_LDFLAGS := -static
|
||||
|
||||
ifdef B_CRT0
|
||||
LOCAL_STATIC_LIBRARIES += crt0
|
||||
endif
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
||||
|
@ -95,7 +92,6 @@ include $(CLEAR_VARS)
|
|||
LOCAL_MODULE := magiskboot
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libcompat \
|
||||
liblzma \
|
||||
liblz4 \
|
||||
libbz2 \
|
||||
|
@ -110,6 +106,13 @@ LOCAL_SRC_FILES := \
|
|||
boot/format.cpp \
|
||||
boot/boot-rs.cpp
|
||||
|
||||
LOCAL_LDFLAGS := -static
|
||||
|
||||
ifdef B_CRT0
|
||||
LOCAL_STATIC_LIBRARIES += crt0
|
||||
LOCAL_LDFLAGS += -lm
|
||||
endif
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
||||
|
@ -162,9 +165,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
|||
LOCAL_SRC_FILES := \
|
||||
sepolicy/api.cpp \
|
||||
sepolicy/sepolicy.cpp \
|
||||
sepolicy/rules.cpp \
|
||||
sepolicy/policydb.cpp \
|
||||
sepolicy/statement.cpp \
|
||||
sepolicy/policy-rs.cpp
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
|
|
@ -8,10 +8,18 @@ APP_PLATFORM := android-23
|
|||
APP_THIN_ARCHIVE := true
|
||||
APP_STRIP_MODE := none
|
||||
|
||||
# Busybox should use stock libc.a
|
||||
ifdef B_CRT0
|
||||
|
||||
# Disable all security and debugging features
|
||||
APP_CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -U_FORTIFY_SOURCE
|
||||
# Override output folder to make sure all dependencies are rebuilt with new CFLAGS
|
||||
NDK_APP_OUT := ./obj/nolibc
|
||||
|
||||
endif
|
||||
|
||||
# Busybox should use a newer libc.a
|
||||
ifdef B_BB
|
||||
APP_PLATFORM := android-26
|
||||
APP_LDFLAGS += -T src/lto_fix.lds
|
||||
ifeq ($(OS),Windows_NT)
|
||||
APP_SHORT_COMMANDS := true
|
||||
endif
|
||||
|
|
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.0"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -61,9 +61,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||
|
||||
[[package]]
|
||||
name = "base"
|
||||
|
@ -72,6 +72,7 @@ dependencies = [
|
|||
"argh",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"const_format",
|
||||
"cxx",
|
||||
"cxx-gen",
|
||||
"libc",
|
||||
|
@ -100,27 +101,27 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
version = "0.11.0-pre.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
checksum = "3ded684142010808eb980d9974ef794da2bcf97d13396143b1515e9f0fb4a10e"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.5.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
|
||||
checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -129,18 +130,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -175,26 +173,47 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.5"
|
||||
version = "0.10.0-pre.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||
checksum = "f7e3352a27098ba6b09546e5f13b15165e6a88b5c2723afecb3ea9576b27e3ea"
|
||||
|
||||
[[package]]
|
||||
name = "const_format"
|
||||
version = "0.2.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
|
||||
dependencies = [
|
||||
"const_format_proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_format_proc_macros"
|
||||
version = "0.2.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0-pre.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
|
||||
checksum = "1943d7beadd9ce2b25f3bae73b9e9336fccc1edf38bdec1ed58d3aa183989e11"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"hybrid-array",
|
||||
"num-traits",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
|
@ -202,17 +221,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
version = "0.2.0-pre.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
checksum = "b7aa2ec04f5120b830272a481e8d9d8ba4dda140d2cda59b0f1110d5eb93c38e"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
"getrandom",
|
||||
"hybrid-array",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.105"
|
||||
version = "1.0.115"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
|
@ -221,7 +241,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxx-gen"
|
||||
version = "0.7.105"
|
||||
version = "0.7.115"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
|
@ -231,11 +251,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.105"
|
||||
version = "1.0.115"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.105"
|
||||
version = "1.0.115"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -244,9 +264,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.8"
|
||||
version = "0.8.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
|
||||
checksum = "b489fd2221710c1dd46637d66b984161fb66134f81437a8489800306bcc2ecea"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"der_derive",
|
||||
|
@ -257,9 +277,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "der_derive"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049"
|
||||
checksum = "dd1ee9778ac378876dc78f546d2821fae40a1b69ec8d82f3745392d69ff89ce6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -268,9 +288,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
version = "0.11.0-pre.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
checksum = "065d93ead7c220b85d5b4be4795d8398eac4ff68b5ee63895de0a3c1fb6edf25"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"const-oid",
|
||||
|
@ -280,9 +300,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.16.8"
|
||||
version = "0.17.0-pre.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
|
||||
checksum = "d7e045ee5c360512162782f3d4cb07d2f4ce8c4ef9bf7c77ec16d1cf60b3d5ca"
|
||||
dependencies = [
|
||||
"der",
|
||||
"digest",
|
||||
|
@ -294,17 +314,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.5"
|
||||
version = "0.14.0-pre.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
|
||||
checksum = "4a1775af172997a40c14854c3a9fde9e03e5772084b334b6a0bb18bf7f93ac16"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
"digest",
|
||||
"ff",
|
||||
"generic-array",
|
||||
"group",
|
||||
"hkdf",
|
||||
"hybrid-array",
|
||||
"pem-rfc7468",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
|
@ -344,26 +364,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flagset"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
checksum = "cdeb3aa5e95cf9aabc17f060cfa0ced7b83f042390760ca53bf09df9968acaa1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
@ -392,18 +401,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.3"
|
||||
version = "0.13.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||
checksum = "fd5d615ab5c462f96c309b3a00b19f373025a4981312f717f9df5bbd0201530c"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
version = "0.13.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
checksum = "ffd790a0795ee332ed3e8959e5b177beb70d7112eb7d345428ec17427897d5ce"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
@ -417,6 +426,16 @@ dependencies = [
|
|||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.2.0-rc.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53668f5da5a41d9eaf4bf7064be46d1ebe6a4e1ceed817f387587b18f2b51047"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -428,21 +447,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.148"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "magisk"
|
||||
|
@ -474,6 +493,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"p256",
|
||||
"p384",
|
||||
"p521",
|
||||
"pb-rs",
|
||||
"quick-protobuf",
|
||||
"rsa",
|
||||
|
@ -504,9 +524,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
|
@ -543,9 +563,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -554,19 +574,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
|
@ -575,9 +594,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.16"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
|
@ -585,9 +604,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "p256"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
|
||||
version = "0.14.0-pre.0"
|
||||
source = "git+https://github.com/RustCrypto/elliptic-curves.git?rev=5d1c252c2defb5808f55329f3e2955ca72d7f8b5#5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
dependencies = [
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
|
@ -597,9 +615,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "p384"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209"
|
||||
version = "0.14.0-pre"
|
||||
source = "git+https://github.com/RustCrypto/elliptic-curves.git?rev=5d1c252c2defb5808f55329f3e2955ca72d7f8b5#5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
dependencies = [
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
|
@ -607,6 +624,20 @@ dependencies = [
|
|||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p521"
|
||||
version = "0.14.0-pre"
|
||||
source = "git+https://github.com/RustCrypto/elliptic-curves.git?rev=5d1c252c2defb5808f55329f3e2955ca72d7f8b5#5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"primefield",
|
||||
"primeorder",
|
||||
"rand_core",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pb-rs"
|
||||
version = "0.10.0"
|
||||
|
@ -620,18 +651,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
version = "1.0.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
checksum = "76a65e1c27d1680f8805b3f8c9949f08d6aa5d6cbd088c9896e64a53821dc27d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
version = "0.8.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||
checksum = "4f6af6e88ac39402f67488e22faa9eb15cf065f520cf4a09419393691a6d0133"
|
||||
dependencies = [
|
||||
"der",
|
||||
"pkcs8",
|
||||
|
@ -640,9 +671,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
version = "0.11.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
checksum = "935c09e0aecb0cb8f8907b57438b19a068cb74a25189b06724f061170b2465ff"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
|
@ -654,20 +685,24 @@ version = "0.2.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "primefield"
|
||||
version = "0.14.0-pre"
|
||||
source = "git+https://github.com/RustCrypto/elliptic-curves.git?rev=5d1c252c2defb5808f55329f3e2955ca72d7f8b5#5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
|
||||
[[package]]
|
||||
name = "primeorder"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3"
|
||||
version = "0.14.0-pre.0"
|
||||
source = "git+https://github.com/RustCrypto/elliptic-curves.git?rev=5d1c252c2defb5808f55329f3e2955ca72d7f8b5#5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
dependencies = [
|
||||
"elliptic-curve",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.67"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -688,9 +723,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -726,9 +761,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.5"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -738,9 +773,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.8"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -749,15 +784,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
||||
checksum = "045972f2f66b9467a2f6834b7fd0f9b23ca214b4a8700b880c36edb726e96da6"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
"subtle",
|
||||
|
@ -765,16 +800,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.2"
|
||||
version = "0.10.0-pre.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8"
|
||||
checksum = "43e0089f12e510517c97e1adc17d0f8374efbabdd021dfb7645d6619f85633e9"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"const-oid",
|
||||
"digest",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
|
@ -788,13 +821,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.7.3"
|
||||
version = "0.8.0-pre.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
||||
checksum = "02dc081ed777a3bab68583b52ffb8221677b6e90d483b320963a247e2c07f328"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"der",
|
||||
"generic-array",
|
||||
"hybrid-array",
|
||||
"pkcs8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
|
@ -802,18 +835,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -822,9 +855,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
version = "0.11.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
checksum = "3885de8cb916f223718c1ccd47a840b91f806333e76002dc5cb3862154b4fed3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -833,9 +866,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.7"
|
||||
version = "0.11.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
checksum = "8f33549bf3064b62478926aa89cbfc7c109aab66ae8f0d5d2ef839e482cc30d6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -844,9 +877,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.1.0"
|
||||
version = "2.3.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
|
||||
checksum = "1700c22ba9ce32c7b0a1495068a906c3552e7db386af7cf865162e0dea498523"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
|
@ -860,9 +893,9 @@ checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
|
@ -872,9 +905,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
|||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
|
||||
checksum = "cb2b56670f5ef52934c97efad30bf42585de0c33ec3e2a886e38b80d2db67243"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
|
@ -894,9 +927,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.37"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -905,9 +938,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.3.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
@ -923,18 +956,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.48"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.48"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tls_codec"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a"
|
||||
dependencies = [
|
||||
"tls_codec_derive",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tls_codec_derive"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -955,9 +1009,15 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
|
@ -965,12 +1025,6 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -995,9 +1049,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -1010,17 +1064,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|||
|
||||
[[package]]
|
||||
name = "x509-cert"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25eefca1d99701da3a57feb07e5079fc62abba059fc139e98c13bbb250f3ef29"
|
||||
version = "0.3.0-pre"
|
||||
source = "git+https://github.com/RustCrypto/formats.git?rev=809df65b20d61e88afb7f514b5cfdd3d1958a40f#809df65b20d61e88afb7f514b5cfdd3d1958a40f"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"der",
|
||||
"spki",
|
||||
"tls_codec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -13,16 +13,18 @@ num-derive = "0.4"
|
|||
thiserror = "1.0"
|
||||
byteorder = "1"
|
||||
size = "0.4"
|
||||
sha1 = "0.10"
|
||||
sha2 = "0.10"
|
||||
digest = "0.10"
|
||||
p256 = "0.13"
|
||||
p384 = "0.13"
|
||||
rsa = "0.9"
|
||||
x509-cert = "0.2"
|
||||
der = "0.7"
|
||||
sha1 = "0.11.0-pre.3"
|
||||
sha2 = "=0.11.0-pre.3"
|
||||
digest = "0.11.0-pre.8"
|
||||
#p256 = "0.14"
|
||||
#p384 = "0.14"
|
||||
#p521 = "0.14"
|
||||
rsa = "0.10.0-pre.1"
|
||||
#x509-cert = "0.3"
|
||||
der = "0.8.0-pre.0"
|
||||
bytemuck = "1.14"
|
||||
fdt = "0.1"
|
||||
const_format = "0.2"
|
||||
|
||||
[workspace.dependencies.argh]
|
||||
git = "https://github.com/google/argh.git"
|
||||
|
@ -37,6 +39,22 @@ rev = "2f37d5a65504de7d716b5b28fd82219501a901a9"
|
|||
git = "https://github.com/tafia/quick-protobuf.git"
|
||||
rev = "2f37d5a65504de7d716b5b28fd82219501a901a9"
|
||||
|
||||
[workspace.dependencies.p256]
|
||||
git = "https://github.com/RustCrypto/elliptic-curves.git"
|
||||
rev = "5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
|
||||
[workspace.dependencies.p384]
|
||||
git = "https://github.com/RustCrypto/elliptic-curves.git"
|
||||
rev = "5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
|
||||
[workspace.dependencies.p521]
|
||||
git = "https://github.com/RustCrypto/elliptic-curves.git"
|
||||
rev = "5d1c252c2defb5808f55329f3e2955ca72d7f8b5"
|
||||
|
||||
[workspace.dependencies.x509-cert]
|
||||
git = "https://github.com/RustCrypto/formats.git"
|
||||
rev = "809df65b20d61e88afb7f514b5cfdd3d1958a40f"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
|
|
|
@ -22,18 +22,3 @@ LOCAL_SRC_FILES := \
|
|||
base-rs.cpp \
|
||||
../external/cxx-rs/src/cxx.cc
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# All static executables should link with libcompat
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcompat
|
||||
LOCAL_SRC_FILES := compat/compat.cpp
|
||||
# Fix static variables' ctor/dtor when using LTO
|
||||
# See: https://github.com/android/ndk/issues/1461
|
||||
LOCAL_EXPORT_LDFLAGS := -static -T src/lto_fix.lds -Wl,--wrap=rename -Wl,--wrap=renameat
|
||||
# For some reason, using the hacky libc.a with x86 will trigger stack protection violation
|
||||
# when mixing Rust and C++ code. Disable stack protector to bypass this issue.
|
||||
ifeq ($(TARGET_ARCH), x86)
|
||||
LOCAL_EXPORT_CFLAGS := -fno-stack-protector
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
|
|
@ -22,3 +22,4 @@ argh = { workspace = true }
|
|||
bytemuck = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
num-derive = { workspace = true }
|
||||
const_format = { workspace = true }
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
// This file implements all missing symbols that should exist in normal API 23
|
||||
// libc.a but missing in our extremely lean libc.a replacements.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if !defined(__LP64__)
|
||||
|
||||
// Add "hacky" libc.a missing symbols back
|
||||
// All symbols in this file are weak, so a vanilla NDK should still link properly
|
||||
|
||||
#include "fortify.hpp"
|
||||
|
||||
// Original source: https://github.com/freebsd/freebsd/blob/master/contrib/file/src/getline.c
|
||||
// License: BSD, full copyright notice please check original source
|
||||
|
||||
[[gnu::weak]]
|
||||
ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) {
|
||||
char *ptr, *eptr;
|
||||
|
||||
if (*buf == nullptr || *bufsiz == 0) {
|
||||
*bufsiz = BUFSIZ;
|
||||
if ((*buf = (char *) malloc(*bufsiz)) == nullptr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
|
||||
int c = fgetc(fp);
|
||||
if (c == -1) {
|
||||
if (feof(fp))
|
||||
return ptr == *buf ? -1 : ptr - *buf;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
*ptr++ = c;
|
||||
if (c == delimiter) {
|
||||
*ptr = '\0';
|
||||
return ptr - *buf;
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
ssize_t d = ptr - *buf;
|
||||
if ((nbuf = (char *) realloc(*buf, nbufsiz)) == nullptr)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
*bufsiz = nbufsiz;
|
||||
eptr = nbuf + nbufsiz;
|
||||
ptr = nbuf + d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) {
|
||||
return getdelim(buf, bufsiz, '\n', fp);
|
||||
}
|
||||
|
||||
// Missing system call wrappers
|
||||
|
||||
[[gnu::weak]]
|
||||
ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
|
||||
return syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int symlinkat(const char *target, int newdirfd, const char *linkpath) {
|
||||
return syscall(__NR_symlinkat, target, newdirfd, linkpath);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int linkat(int olddirfd, const char *oldpath,
|
||||
int newdirfd, const char *newpath, int flags) {
|
||||
return syscall(__NR_linkat, olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int faccessat(int dirfd, const char *pathname, int mode, int flags) {
|
||||
return syscall(__NR_faccessat, dirfd, pathname, mode, flags);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int mkfifo(const char *path, mode_t mode) {
|
||||
return mknod(path, (mode & ~S_IFMT) | S_IFIFO, 0);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) {
|
||||
return syscall(__NR_fsetxattr, fd, name, value, size, flags);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) {
|
||||
return syscall(__NR_lsetxattr, path, name, value, size, flags);
|
||||
}
|
||||
|
||||
#define SPLIT_64(v) (unsigned)((v) & 0xFFFFFFFF), (unsigned)((v) >> 32)
|
||||
|
||||
#if defined(__arm__)
|
||||
// Why the additional 0 is required: https://man7.org/linux/man-pages/man2/syscall.2.html
|
||||
[[gnu::weak]]
|
||||
int ftruncate64(int fd, off64_t length) {
|
||||
return syscall(__NR_ftruncate64, fd, 0, SPLIT_64(length));
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
[[gnu::weak]]
|
||||
int ftruncate64(int fd, off64_t length) {
|
||||
return syscall(__NR_ftruncate64, fd, SPLIT_64(length));
|
||||
}
|
||||
#endif
|
||||
|
||||
[[gnu::weak]]
|
||||
void android_set_abort_message(const char *) {}
|
||||
|
||||
extern FILE __sF[];
|
||||
|
||||
[[gnu::weak]] FILE* stdin = &__sF[0];
|
||||
[[gnu::weak]] FILE* stdout = &__sF[1];
|
||||
[[gnu::weak]] FILE* stderr = &__sF[2];
|
||||
|
||||
#endif // !defined(__LP64__)
|
||||
|
||||
[[maybe_unused]]
|
||||
int __wrap_renameat(int old_dir_fd, const char *old_path, int new_dir_fd, const char *new_path) {
|
||||
long out = syscall(__NR_renameat, old_dir_fd, old_path, new_dir_fd, new_path);
|
||||
if (out == -1 && errno == ENOSYS) {
|
||||
out = syscall(__NR_renameat2, old_dir_fd, old_path, new_dir_fd, new_path, 0);
|
||||
}
|
||||
return static_cast<int>(out);
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
int __wrap_rename(const char *old_path, const char *new_path) {
|
||||
return __wrap_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path);
|
||||
}
|
||||
|
||||
} // extern "C"
|
|
@ -1,144 +0,0 @@
|
|||
// Original source: https://android.googlesource.com/platform/bionic/+/master/libc/bionic/fortify.cpp
|
||||
// License: AOSP, full copyright notice please check original source
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
|
||||
extern void __vloge(const char* fmt, va_list ap);
|
||||
|
||||
static inline __noreturn __printflike(1, 2) void __fortify_fatal(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
__vloge(fmt, args);
|
||||
va_end(args);
|
||||
abort();
|
||||
}
|
||||
static inline void __check_count(const char* fn, const char* identifier, size_t value) {
|
||||
if (__predict_false(value > SSIZE_MAX)) {
|
||||
__fortify_fatal("%s: %s %zu > SSIZE_MAX", fn, identifier, value);
|
||||
}
|
||||
}
|
||||
static inline void __check_buffer_access(const char* fn, const char* action,
|
||||
size_t claim, size_t actual) {
|
||||
if (__predict_false(claim > actual)) {
|
||||
__fortify_fatal("%s: prevented %zu-byte %s %zu-byte buffer", fn, claim, action, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
|
||||
__check_count("memcpy", "count", count);
|
||||
__check_buffer_access("memcpy", "write into", count, dst_len);
|
||||
return __call_bypassing_fortify(memcpy)(dst, src, count);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
char* __strcpy_chk(char* dst, const char* src, size_t dst_len) {
|
||||
// TODO: optimize so we don't scan src twice.
|
||||
size_t src_len = __builtin_strlen(src) + 1;
|
||||
__check_buffer_access("strcpy", "write into", src_len, dst_len);
|
||||
return __builtin_strcpy(dst, src);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
size_t __strlcpy_chk(char* dst, const char* src,
|
||||
size_t supplied_size, size_t dst_len_from_compiler) {
|
||||
__check_buffer_access("strlcpy", "write into", supplied_size, dst_len_from_compiler);
|
||||
return __call_bypassing_fortify(strlcpy)(dst, src, supplied_size);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
char* __strchr_chk(const char* p, int ch, size_t s_len) {
|
||||
for (;; ++p, s_len--) {
|
||||
if (__predict_false(s_len == 0)) {
|
||||
__fortify_fatal("strchr: prevented read past end of buffer");
|
||||
}
|
||||
if (*p == static_cast<char>(ch)) {
|
||||
return const_cast<char*>(p);
|
||||
}
|
||||
if (*p == '\0') {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
char* __strcat_chk(char* dst, const char* src, size_t dst_buf_size) {
|
||||
char* save = dst;
|
||||
size_t dst_len = __strlen_chk(dst, dst_buf_size);
|
||||
dst += dst_len;
|
||||
dst_buf_size -= dst_len;
|
||||
while ((*dst++ = *src++) != '\0') {
|
||||
dst_buf_size--;
|
||||
if (__predict_false(dst_buf_size == 0)) {
|
||||
__fortify_fatal("strcat: prevented write past end of %zu-byte buffer", dst_buf_size);
|
||||
}
|
||||
}
|
||||
return save;
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
size_t __strlen_chk(const char* s, size_t s_len) {
|
||||
// TODO: "prevented" here would be a lie because this strlen can run off the end.
|
||||
// strlen is too important to be expensive, so we wanted to be able to call the optimized
|
||||
// implementation, but I think we need to implement optimized assembler __strlen_chk routines.
|
||||
size_t ret = __builtin_strlen(s);
|
||||
if (__predict_false(ret >= s_len)) {
|
||||
__fortify_fatal("strlen: detected read past end of buffer");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int __vsprintf_chk(char* dst, int /*flags*/,
|
||||
size_t dst_len_from_compiler, const char* format, va_list va) {
|
||||
// The compiler uses SIZE_MAX to mean "no idea", but our vsnprintf rejects sizes that large.
|
||||
int result = __call_bypassing_fortify(vsnprintf)(dst,
|
||||
dst_len_from_compiler == SIZE_MAX ? SSIZE_MAX : dst_len_from_compiler,
|
||||
format, va);
|
||||
// Try to catch failures after the fact...
|
||||
__check_buffer_access("vsprintf", "write into", result + 1, dst_len_from_compiler);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
mode_t __umask_chk(mode_t mode) {
|
||||
if (__predict_false((mode & 0777) != mode)) {
|
||||
__fortify_fatal("umask: called with invalid mask %o", mode);
|
||||
}
|
||||
return __umask_real(mode);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
ssize_t __read_chk(int fd, void* buf, size_t count, size_t buf_size) {
|
||||
__check_count("read", "count", count);
|
||||
__check_buffer_access("read", "write into", count, buf_size);
|
||||
return __call_bypassing_fortify(read)(fd, buf, count);
|
||||
}
|
||||
static inline bool needs_mode(int flags) {
|
||||
return ((flags & O_CREAT) == O_CREAT) || ((flags & O_TMPFILE) == O_TMPFILE);
|
||||
}
|
||||
static inline int force_O_LARGEFILE(int flags) {
|
||||
return flags | O_LARGEFILE;
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int __open_2(const char* pathname, int flags) {
|
||||
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
|
||||
return __openat_real(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int __openat_2(int fd, const char* pathname, int flags) {
|
||||
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
|
||||
return __openat_real(fd, pathname, force_O_LARGEFILE(flags), 0);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int __vsnprintf_chk(char* dst, size_t supplied_size, int /*flags*/,
|
||||
size_t dst_len_from_compiler, const char* format, va_list va) {
|
||||
__check_buffer_access("vsnprintf", "write into", supplied_size, dst_len_from_compiler);
|
||||
return __call_bypassing_fortify(vsnprintf)(dst, supplied_size, format, va);
|
||||
}
|
|
@ -2,14 +2,17 @@ use std::cmp::min;
|
|||
use std::ffi::{CStr, FromBytesWithNulError, OsStr};
|
||||
use std::fmt::{Arguments, Debug, Display, Formatter, Write};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::Path;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::{Utf8Chunks, Utf8Error};
|
||||
use std::{fmt, mem, slice, str};
|
||||
|
||||
use crate::slice_from_ptr_mut;
|
||||
use cxx::{type_id, ExternType};
|
||||
use libc::c_char;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::slice_from_ptr_mut;
|
||||
|
||||
// Utf8CStr types are UTF-8 validated and null terminated strings.
|
||||
//
|
||||
// Several Utf8CStr types:
|
||||
|
@ -31,13 +34,6 @@ use thiserror::Error;
|
|||
// Utf8CString, Utf8CStrBufRef, and Utf8CStrBufArr<N> implements Utf8CStrWrite.
|
||||
// Utf8CStrBufRef and Utf8CStrBufArr<N> implements Utf8CStrBuf.
|
||||
|
||||
pub fn copy_cstr<T: AsRef<CStr> + ?Sized>(dest: &mut [u8], src: &T) -> usize {
|
||||
let src = src.as_ref().to_bytes_with_nul();
|
||||
let len = min(src.len(), dest.len());
|
||||
dest[..len].copy_from_slice(&src[..len]);
|
||||
len - 1
|
||||
}
|
||||
|
||||
fn utf8_cstr_buf_append(buf: &mut dyn Utf8CStrBuf, s: &[u8]) -> usize {
|
||||
let mut used = buf.len();
|
||||
if used >= buf.capacity() - 1 {
|
||||
|
@ -46,7 +42,9 @@ fn utf8_cstr_buf_append(buf: &mut dyn Utf8CStrBuf, s: &[u8]) -> usize {
|
|||
}
|
||||
let dest = unsafe { &mut buf.mut_buf()[used..] };
|
||||
let len = min(s.len(), dest.len() - 1);
|
||||
dest[..len].copy_from_slice(&s[..len]);
|
||||
if len > 0 {
|
||||
dest[..len].copy_from_slice(&s[..len]);
|
||||
}
|
||||
dest[len] = b'\0';
|
||||
used += len;
|
||||
unsafe { buf.set_len(used) };
|
||||
|
@ -103,7 +101,7 @@ trait AsUtf8CStr {
|
|||
|
||||
// Implementation for Utf8CString
|
||||
|
||||
trait StringExt {
|
||||
pub trait StringExt {
|
||||
fn nul_terminate(&mut self) -> &mut [u8];
|
||||
}
|
||||
|
||||
|
@ -120,6 +118,21 @@ impl StringExt for String {
|
|||
}
|
||||
}
|
||||
|
||||
impl StringExt for PathBuf {
|
||||
#[allow(mutable_transmutes)]
|
||||
fn nul_terminate(&mut self) -> &mut [u8] {
|
||||
self.reserve(1);
|
||||
// SAFETY: the PathBuf is reserved to have enough capacity to fit in the null byte
|
||||
// SAFETY: the null byte is explicitly added outside of the PathBuf's length
|
||||
unsafe {
|
||||
let bytes: &mut [u8] = mem::transmute(self.as_mut_os_str().as_bytes());
|
||||
let buf = slice::from_raw_parts_mut(bytes.as_mut_ptr(), bytes.len() + 1);
|
||||
*buf.get_unchecked_mut(bytes.len()) = b'\0';
|
||||
buf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Utf8CString(String);
|
||||
|
||||
|
@ -380,6 +393,22 @@ impl DerefMut for Utf8CStr {
|
|||
}
|
||||
}
|
||||
|
||||
// Notice that we only implement ExternType on Utf8CStr *reference*
|
||||
unsafe impl ExternType for &Utf8CStr {
|
||||
type Id = type_id!("rust::Utf8CStr");
|
||||
type Kind = cxx::kind::Trivial;
|
||||
}
|
||||
|
||||
macro_rules! const_assert_eq {
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
const _: [(); $left] = [(); $right];
|
||||
};
|
||||
}
|
||||
|
||||
// Assert ABI layout
|
||||
const_assert_eq!(mem::size_of::<&Utf8CStr>(), mem::size_of::<[usize; 2]>());
|
||||
const_assert_eq!(mem::align_of::<&Utf8CStr>(), mem::align_of::<[usize; 2]>());
|
||||
|
||||
// File system path extensions types
|
||||
|
||||
#[repr(transparent)]
|
||||
|
@ -417,6 +446,7 @@ pub struct FsPathBuf<'a>(&'a mut dyn Utf8CStrWrite);
|
|||
|
||||
impl<'a> FsPathBuf<'a> {
|
||||
pub fn new(value: &'a mut dyn Utf8CStrWrite) -> Self {
|
||||
value.clear();
|
||||
FsPathBuf(value)
|
||||
}
|
||||
|
||||
|
@ -622,7 +652,8 @@ macro_rules! cstr {
|
|||
);
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
$crate::Utf8CStr::from_bytes_unchecked(concat!($($str)*, "\0").as_bytes())
|
||||
$crate::Utf8CStr::from_bytes_unchecked($crate::const_format::concatcp!($($str)*, "\0")
|
||||
.as_bytes())
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -630,6 +661,6 @@ macro_rules! cstr {
|
|||
#[macro_export]
|
||||
macro_rules! raw_cstr {
|
||||
($($str:tt)*) => {{
|
||||
cstr!($($str)*).as_ptr()
|
||||
$crate::cstr!($($str)*).as_ptr()
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ use cfg_if::cfg_if;
|
|||
use cxx::private::c_char;
|
||||
use libc::mode_t;
|
||||
|
||||
use crate::logging::CxxResultExt;
|
||||
pub(crate) use crate::xwrap::*;
|
||||
use crate::{
|
||||
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrBufRef,
|
||||
clone_attr, cstr, fclone_attr, fd_path, map_fd, map_file, slice_from_ptr, CxxResultExt,
|
||||
Directory, FsPath, Utf8CStr, Utf8CStrBufRef,
|
||||
};
|
||||
|
||||
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||
|
@ -57,12 +57,8 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
|
|||
inner(fd).is_ok()
|
||||
}
|
||||
|
||||
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
|
||||
unsafe {
|
||||
map_file(Utf8CStr::from_bytes_unchecked(path), rw)
|
||||
.log_cxx()
|
||||
.unwrap_or(&mut [])
|
||||
}
|
||||
pub(crate) fn map_file_for_cxx(path: &Utf8CStr, rw: bool) -> &'static mut [u8] {
|
||||
map_file(path, rw).log_cxx().unwrap_or(&mut [])
|
||||
}
|
||||
|
||||
pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8] {
|
||||
|
@ -171,3 +167,18 @@ unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
|
|||
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$new"]
|
||||
unsafe extern "C" fn str_new(this: &mut &Utf8CStr, s: *const u8, len: usize) {
|
||||
*this = Utf8CStr::from_bytes(slice_from_ptr(s, len)).unwrap_or(cstr!(""));
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$ptr"]
|
||||
unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
|
||||
this.as_ptr().cast()
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$len"]
|
||||
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
|
||||
this.len()
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ void file_readline(bool trim, const char *file, const function<bool(string_view)
|
|||
if (auto fp = open_file(file, "re"))
|
||||
file_readline(trim, fp.get(), fn);
|
||||
}
|
||||
|
||||
void file_readline(const char *file, const function<bool(string_view)> &fn) {
|
||||
file_readline(false, file, fn);
|
||||
}
|
||||
|
@ -100,86 +101,6 @@ void parse_prop_file(const char *file, const function<bool(string_view, string_v
|
|||
parse_prop_file(fp.get(), fn);
|
||||
}
|
||||
|
||||
std::vector<mount_info> parse_mount_info(const char *pid) {
|
||||
char buf[PATH_MAX] = {};
|
||||
ssprintf(buf, sizeof(buf), "/proc/%s/mountinfo", pid);
|
||||
std::vector<mount_info> result;
|
||||
|
||||
file_readline(buf, [&result](string_view line) -> bool {
|
||||
int root_start = 0, root_end = 0;
|
||||
int target_start = 0, target_end = 0;
|
||||
int vfs_option_start = 0, vfs_option_end = 0;
|
||||
int type_start = 0, type_end = 0;
|
||||
int source_start = 0, source_end = 0;
|
||||
int fs_option_start = 0, fs_option_end = 0;
|
||||
int optional_start = 0, optional_end = 0;
|
||||
unsigned int id, parent, maj, min;
|
||||
sscanf(line.data(),
|
||||
"%u " // (1) id
|
||||
"%u " // (2) parent
|
||||
"%u:%u " // (3) maj:min
|
||||
"%n%*s%n " // (4) mountroot
|
||||
"%n%*s%n " // (5) target
|
||||
"%n%*s%n" // (6) vfs options (fs-independent)
|
||||
"%n%*[^-]%n - " // (7) optional fields
|
||||
"%n%*s%n " // (8) FS type
|
||||
"%n%*s%n " // (9) source
|
||||
"%n%*s%n", // (10) fs options (fs specific)
|
||||
&id, &parent, &maj, &min, &root_start, &root_end, &target_start,
|
||||
&target_end, &vfs_option_start, &vfs_option_end,
|
||||
&optional_start, &optional_end, &type_start, &type_end,
|
||||
&source_start, &source_end, &fs_option_start, &fs_option_end);
|
||||
|
||||
auto root = line.substr(root_start, root_end - root_start);
|
||||
auto target = line.substr(target_start, target_end - target_start);
|
||||
auto vfs_option =
|
||||
line.substr(vfs_option_start, vfs_option_end - vfs_option_start);
|
||||
++optional_start;
|
||||
--optional_end;
|
||||
auto optional = line.substr(
|
||||
optional_start,
|
||||
optional_end - optional_start > 0 ? optional_end - optional_start : 0);
|
||||
|
||||
auto type = line.substr(type_start, type_end - type_start);
|
||||
auto source = line.substr(source_start, source_end - source_start);
|
||||
auto fs_option =
|
||||
line.substr(fs_option_start, fs_option_end - fs_option_start);
|
||||
|
||||
unsigned int shared = 0;
|
||||
unsigned int master = 0;
|
||||
unsigned int propagate_from = 0;
|
||||
if (auto pos = optional.find("shared:"); pos != std::string_view::npos) {
|
||||
shared = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("master:"); pos != std::string_view::npos) {
|
||||
master = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("propagate_from:");
|
||||
pos != std::string_view::npos) {
|
||||
propagate_from = parse_int(optional.substr(pos + 15));
|
||||
}
|
||||
|
||||
result.emplace_back(mount_info {
|
||||
.id = id,
|
||||
.parent = parent,
|
||||
.device = static_cast<dev_t>(makedev(maj, min)),
|
||||
.root {root},
|
||||
.target {target},
|
||||
.vfs_option {vfs_option},
|
||||
.optional {
|
||||
.shared = shared,
|
||||
.master = master,
|
||||
.propagate_from = propagate_from,
|
||||
},
|
||||
.type {type},
|
||||
.source {source},
|
||||
.fs_option {fs_option},
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
sDIR make_dir(DIR *dp) {
|
||||
return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; });
|
||||
}
|
||||
|
@ -189,7 +110,7 @@ sFILE make_file(FILE *fp) {
|
|||
}
|
||||
|
||||
mmap_data::mmap_data(const char *name, bool rw) {
|
||||
auto slice = rust::map_file(byte_view(name), rw);
|
||||
auto slice = rust::map_file(name, rw);
|
||||
if (!slice.empty()) {
|
||||
_buf = slice.data();
|
||||
_sz = slice.size();
|
||||
|
|
|
@ -20,23 +20,6 @@ static inline T align_padding(T v, int a) {
|
|||
return align_to(v, a) - v;
|
||||
}
|
||||
|
||||
struct mount_info {
|
||||
unsigned int id;
|
||||
unsigned int parent;
|
||||
dev_t device;
|
||||
std::string root;
|
||||
std::string target;
|
||||
std::string vfs_option;
|
||||
struct {
|
||||
unsigned int shared;
|
||||
unsigned int master;
|
||||
unsigned int propagate_from;
|
||||
} optional;
|
||||
std::string type;
|
||||
std::string source;
|
||||
std::string fs_option;
|
||||
};
|
||||
|
||||
struct mmap_data : public byte_data {
|
||||
static_assert((sizeof(void *) == 8 && BLKGETSIZE64 == 0x80081272) ||
|
||||
(sizeof(void *) == 4 && BLKGETSIZE64 == 0x80041272));
|
||||
|
@ -77,7 +60,6 @@ void file_readline(const char *file, const std::function<bool(std::string_view)>
|
|||
void parse_prop_file(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
void parse_prop_file(const char *file,
|
||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
std::vector<mount_info> parse_mount_info(const char *pid);
|
||||
std::string resolve_preinit_dir(const char *base_dir);
|
||||
|
||||
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
|
||||
|
|
|
@ -2,25 +2,25 @@ use mem::MaybeUninit;
|
|||
use std::cmp::min;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, Read, Seek, SeekFrom, Write};
|
||||
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write};
|
||||
use std::ops::Deref;
|
||||
use std::os::android::fs::MetadataExt;
|
||||
use std::os::fd::{AsFd, BorrowedFd, IntoRawFd};
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::path::Path;
|
||||
use std::{io, mem, ptr, slice};
|
||||
|
||||
use bytemuck::{bytes_of_mut, Pod};
|
||||
use libc::{
|
||||
c_uint, dirent, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY, O_RDWR,
|
||||
O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFREG,
|
||||
c_uint, dirent, makedev, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY,
|
||||
O_RDWR, O_TRUNC, O_WRONLY,
|
||||
};
|
||||
use num_traits::AsPrimitive;
|
||||
|
||||
use crate::cxx_extern::readlinkat_for_cxx;
|
||||
use crate::{
|
||||
copy_cstr, cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrBuf,
|
||||
Utf8CStrBufArr,
|
||||
cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrBuf, Utf8CStrBufArr,
|
||||
Utf8CStrWrite,
|
||||
};
|
||||
|
||||
pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> io::Result<OwnedFd> {
|
||||
|
@ -151,6 +151,40 @@ impl FileAttr {
|
|||
con: Utf8CStrBufArr::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn is(&self, mode: mode_t) -> bool {
|
||||
(self.st.st_mode & libc::S_IFMT as c_uint) as mode_t == mode
|
||||
}
|
||||
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.is(libc::S_IFDIR)
|
||||
}
|
||||
|
||||
pub fn is_file(&self) -> bool {
|
||||
self.is(libc::S_IFREG)
|
||||
}
|
||||
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.is(libc::S_IFLNK)
|
||||
}
|
||||
|
||||
pub fn is_block_device(&self) -> bool {
|
||||
self.is(libc::S_IFBLK)
|
||||
}
|
||||
|
||||
pub fn is_char_device(&self) -> bool {
|
||||
self.is(libc::S_IFCHR)
|
||||
}
|
||||
|
||||
pub fn is_fifo(&self) -> bool {
|
||||
self.is(libc::S_IFIFO)
|
||||
}
|
||||
|
||||
pub fn is_socket(&self) -> bool {
|
||||
self.is(libc::S_IFSOCK)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
|
@ -187,10 +221,26 @@ impl DirEntry<'_> {
|
|||
self.d_type == libc::DT_REG
|
||||
}
|
||||
|
||||
pub fn is_lnk(&self) -> bool {
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.d_type == libc::DT_LNK
|
||||
}
|
||||
|
||||
pub fn is_block_device(&self) -> bool {
|
||||
self.d_type == libc::DT_BLK
|
||||
}
|
||||
|
||||
pub fn is_char_device(&self) -> bool {
|
||||
self.d_type == libc::DT_CHR
|
||||
}
|
||||
|
||||
pub fn is_fifo(&self) -> bool {
|
||||
self.d_type == libc::DT_FIFO
|
||||
}
|
||||
|
||||
pub fn is_socket(&self) -> bool {
|
||||
self.d_type == libc::DT_SOCK
|
||||
}
|
||||
|
||||
pub fn unlink(&self) -> io::Result<()> {
|
||||
let flag = if self.is_dir() { libc::AT_REMOVEDIR } else { 0 };
|
||||
unsafe {
|
||||
|
@ -372,7 +422,7 @@ impl Directory {
|
|||
};
|
||||
std::io::copy(&mut src, &mut dest)?;
|
||||
fd_set_attr(dest.as_raw_fd(), &attr)?;
|
||||
} else if e.is_lnk() {
|
||||
} else if e.is_symlink() {
|
||||
let mut path = Utf8CStrBufArr::default();
|
||||
e.read_link(&mut path)?;
|
||||
unsafe {
|
||||
|
@ -550,10 +600,9 @@ impl FsPath {
|
|||
}
|
||||
|
||||
pub fn remove_all(&self) -> io::Result<()> {
|
||||
let f = self.open(O_RDONLY | O_CLOEXEC)?;
|
||||
let st = f.metadata()?;
|
||||
if st.is_dir() {
|
||||
let mut dir = Directory::try_from(OwnedFd::from(f))?;
|
||||
let attr = self.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
let mut dir = Directory::try_from(open_fd!(self, O_RDONLY | O_CLOEXEC)?)?;
|
||||
dir.remove_all()?;
|
||||
}
|
||||
self.remove()
|
||||
|
@ -584,11 +633,14 @@ impl FsPath {
|
|||
}
|
||||
|
||||
pub fn mkdirs(&self, mode: mode_t) -> io::Result<()> {
|
||||
let mut buf = [0_u8; 4096];
|
||||
let len = copy_cstr(&mut buf, self);
|
||||
let buf = &mut buf[..len];
|
||||
if self.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut arr = Utf8CStrBufArr::default();
|
||||
arr.push_str(self);
|
||||
let mut off = 1;
|
||||
unsafe {
|
||||
let buf = arr.as_bytes_mut();
|
||||
while let Some(p) = buf[off..].iter().position(|c| *c == b'/') {
|
||||
buf[off + p] = b'\0';
|
||||
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
|
||||
|
@ -652,7 +704,7 @@ impl FsPath {
|
|||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
unsafe {
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) != S_IFLNK.as_() {
|
||||
if !attr.is_symlink() {
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?;
|
||||
}
|
||||
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?;
|
||||
|
@ -674,7 +726,7 @@ impl FsPath {
|
|||
|
||||
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
if attr.is_dir() {
|
||||
path.mkdir(0o777)?;
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
|
@ -682,11 +734,11 @@ impl FsPath {
|
|||
} else {
|
||||
// It's OK if remove failed
|
||||
path.remove().ok();
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFREG.as_() {
|
||||
if attr.is_file() {
|
||||
let mut src = self.open(O_RDONLY | O_CLOEXEC)?;
|
||||
let mut dest = path.create(O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0o777)?;
|
||||
std::io::copy(&mut src, &mut dest)?;
|
||||
} else if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFLNK.as_() {
|
||||
} else if attr.is_symlink() {
|
||||
let mut buf = Utf8CStrBufArr::default();
|
||||
self.read_link(&mut buf)?;
|
||||
unsafe {
|
||||
|
@ -701,7 +753,7 @@ impl FsPath {
|
|||
pub fn move_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
if path.exists() {
|
||||
let attr = path.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
if attr.is_dir() {
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
return src.move_into(&dest);
|
||||
|
@ -714,7 +766,7 @@ impl FsPath {
|
|||
|
||||
pub fn link_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
if attr.is_dir() {
|
||||
path.mkdir(0o777)?;
|
||||
path.set_attr(&attr)?;
|
||||
let mut src = Directory::open(self)?;
|
||||
|
@ -724,6 +776,23 @@ impl FsPath {
|
|||
unsafe { libc::link(self.as_ptr(), path.as_ptr()).as_os_err() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symlink_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
unsafe { libc::symlink(self.as_ptr(), path.as_ptr()).as_os_err() }
|
||||
}
|
||||
|
||||
pub fn parent(&self, buf: &mut dyn Utf8CStrWrite) -> bool {
|
||||
buf.clear();
|
||||
if let Some(parent) = Path::new(self.as_str()).parent() {
|
||||
let bytes = parent.as_os_str().as_bytes();
|
||||
// SAFETY: all substring of self is valid UTF-8
|
||||
let parent = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||
buf.push_str(parent);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fd_get_attr(fd: RawFd) -> io::Result<FileAttr> {
|
||||
|
@ -826,18 +895,18 @@ pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8
|
|||
const BLKGETSIZE64: u32 = 0x80041272;
|
||||
|
||||
let flag = if rw { O_RDWR } else { O_RDONLY };
|
||||
let f = File::from(open_fd!(path, flag | O_CLOEXEC)?);
|
||||
let file = FsPath::from(path).open(flag | O_CLOEXEC)?;
|
||||
|
||||
let st = f.metadata()?;
|
||||
let sz = if st.file_type().is_block_device() {
|
||||
let attr = fd_get_attr(file.as_raw_fd())?;
|
||||
let sz = if attr.is_block_device() {
|
||||
let mut sz = 0_u64;
|
||||
unsafe { ioctl(f.as_raw_fd(), BLKGETSIZE64, &mut sz) }.as_os_err()?;
|
||||
unsafe { ioctl(file.as_raw_fd(), BLKGETSIZE64, &mut sz) }.as_os_err()?;
|
||||
sz
|
||||
} else {
|
||||
st.st_size()
|
||||
attr.st.st_size as u64
|
||||
};
|
||||
|
||||
map_fd(f.as_fd(), sz as usize, rw)
|
||||
map_fd(file.as_fd(), sz as usize, rw)
|
||||
}
|
||||
|
||||
pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> io::Result<&'static mut [u8]> {
|
||||
|
@ -861,3 +930,83 @@ pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> io::Result<&'static
|
|||
Ok(slice::from_raw_parts_mut(ptr.cast(), sz))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct MountInfo {
|
||||
pub id: u32,
|
||||
pub parent: u32,
|
||||
pub device: u64,
|
||||
pub root: String,
|
||||
pub target: String,
|
||||
pub vfs_option: String,
|
||||
pub shared: u32,
|
||||
pub master: u32,
|
||||
pub propagation_from: u32,
|
||||
pub unbindable: bool,
|
||||
pub fs_type: String,
|
||||
pub source: String,
|
||||
pub fs_option: String,
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn parse_mount_info_line(line: &str) -> Option<MountInfo> {
|
||||
let mut iter = line.split_whitespace();
|
||||
let id = iter.next()?.parse().ok()?;
|
||||
let parent = iter.next()?.parse().ok()?;
|
||||
let (maj, min) = iter.next()?.split_once(':')?;
|
||||
let maj = maj.parse().ok()?;
|
||||
let min = min.parse().ok()?;
|
||||
let device = makedev(maj, min).into();
|
||||
let root = iter.next()?.to_string();
|
||||
let target = iter.next()?.to_string();
|
||||
let vfs_option = iter.next()?.to_string();
|
||||
let mut optional = iter.next()?;
|
||||
let mut shared = 0;
|
||||
let mut master = 0;
|
||||
let mut propagation_from = 0;
|
||||
let mut unbindable = false;
|
||||
while optional != "-" {
|
||||
if let Some(peer) = optional.strip_prefix("master:") {
|
||||
master = peer.parse().ok()?;
|
||||
} else if let Some(peer) = optional.strip_prefix("shared:") {
|
||||
shared = peer.parse().ok()?;
|
||||
} else if let Some(peer) = optional.strip_prefix("propagate_from:") {
|
||||
propagation_from = peer.parse().ok()?;
|
||||
} else if optional == "unbindable" {
|
||||
unbindable = true;
|
||||
}
|
||||
optional = iter.next()?;
|
||||
}
|
||||
let fs_type = iter.next()?.to_string();
|
||||
let source = iter.next()?.to_string();
|
||||
let fs_option = iter.next()?.to_string();
|
||||
Some(MountInfo {
|
||||
id,
|
||||
parent,
|
||||
device,
|
||||
root,
|
||||
target,
|
||||
vfs_option,
|
||||
shared,
|
||||
master,
|
||||
propagation_from,
|
||||
unbindable,
|
||||
fs_type,
|
||||
source,
|
||||
fs_option,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
|
||||
let mut res = vec![];
|
||||
let mut path = format!("/proc/{}/mountinfo", pid);
|
||||
if let Ok(fd) = open_fd!(Utf8CStr::from_string(&mut path), O_RDONLY | O_CLOEXEC) {
|
||||
let file = File::from(fd);
|
||||
BufReader::new(file).foreach_lines(|line| {
|
||||
parse_mount_info_line(line)
|
||||
.map(|info| res.push(info))
|
||||
.is_some()
|
||||
});
|
||||
}
|
||||
res
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "../files.hpp"
|
||||
#include "../misc.hpp"
|
||||
#include "../logging.hpp"
|
||||
#include "../missing.hpp"
|
||||
#include "../base-rs.hpp"
|
||||
|
||||
using rust::xpipe2;
|
||||
|
|
|
@ -6,9 +6,13 @@
|
|||
|
||||
#include "../files.hpp"
|
||||
|
||||
#define ENABLE_IOV 0
|
||||
|
||||
struct out_stream {
|
||||
virtual bool write(const void *buf, size_t len) = 0;
|
||||
#if ENABLE_IOV
|
||||
virtual ssize_t writev(const iovec *iov, int iovcnt);
|
||||
#endif
|
||||
virtual ~out_stream() = default;
|
||||
};
|
||||
|
||||
|
@ -48,27 +52,25 @@ private:
|
|||
|
||||
struct in_stream {
|
||||
virtual ssize_t read(void *buf, size_t len) = 0;
|
||||
virtual ssize_t readFully(void *buf, size_t len);
|
||||
ssize_t readFully(void *buf, size_t len);
|
||||
#if ENABLE_IOV
|
||||
virtual ssize_t readv(const iovec *iov, int iovcnt);
|
||||
#endif
|
||||
virtual ~in_stream() = default;
|
||||
};
|
||||
|
||||
// A channel is something that is writable, readable, and seekable
|
||||
struct channel : public out_stream, public in_stream {
|
||||
virtual off_t seek(off_t off, int whence) = 0;
|
||||
virtual ~channel() = default;
|
||||
};
|
||||
// A stream is something that is writable and readable
|
||||
struct stream : public out_stream, public in_stream {};
|
||||
|
||||
using channel_ptr = std::unique_ptr<channel>;
|
||||
using stream_ptr = std::unique_ptr<stream>;
|
||||
|
||||
// Byte channel that dynamically allocates memory
|
||||
class byte_channel : public channel {
|
||||
// Byte stream that dynamically allocates memory
|
||||
class byte_stream : public stream {
|
||||
public:
|
||||
byte_channel(heap_data &data) : _data(data) {}
|
||||
byte_stream(heap_data &data) : _data(data) {}
|
||||
|
||||
ssize_t read(void *buf, size_t len) override;
|
||||
bool write(const void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
|
||||
private:
|
||||
heap_data &_data;
|
||||
|
@ -78,21 +80,36 @@ private:
|
|||
void resize(size_t new_sz, bool zero = false);
|
||||
};
|
||||
|
||||
class file_channel : public channel {
|
||||
class rust_vec_stream : public stream {
|
||||
public:
|
||||
rust_vec_stream(rust::Vec<uint8_t> &data) : _data(data) {}
|
||||
|
||||
ssize_t read(void *buf, size_t len) override;
|
||||
bool write(const void *buf, size_t len) override;
|
||||
|
||||
private:
|
||||
rust::Vec<uint8_t> &_data;
|
||||
size_t _pos = 0;
|
||||
|
||||
void ensure_size(size_t sz, bool zero = false);
|
||||
};
|
||||
|
||||
class file_stream : public stream {
|
||||
public:
|
||||
bool write(const void *buf, size_t len) final;
|
||||
protected:
|
||||
virtual ssize_t do_write(const void *buf, size_t len) = 0;
|
||||
};
|
||||
|
||||
// File channel but does not close the file descriptor at any time
|
||||
class fd_channel : public file_channel {
|
||||
// File stream but does not close the file descriptor at any time
|
||||
class fd_stream : public file_stream {
|
||||
public:
|
||||
fd_channel(int fd) : fd(fd) {}
|
||||
fd_stream(int fd) : fd(fd) {}
|
||||
ssize_t read(void *buf, size_t len) override;
|
||||
#if ENABLE_IOV
|
||||
ssize_t readv(const iovec *iov, int iovcnt) override;
|
||||
ssize_t writev(const iovec *iov, int iovcnt) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
#endif
|
||||
protected:
|
||||
ssize_t do_write(const void *buf, size_t len) override;
|
||||
private:
|
||||
|
@ -100,26 +117,13 @@ private:
|
|||
};
|
||||
|
||||
/* ****************************************
|
||||
* Bridge between channel class and C stdio
|
||||
* Bridge between stream class and C stdio
|
||||
* ****************************************/
|
||||
|
||||
// sFILE -> channel_ptr
|
||||
class fp_channel final : public file_channel {
|
||||
public:
|
||||
fp_channel(FILE *fp = nullptr) : fp(fp, fclose) {}
|
||||
fp_channel(sFILE &&fp) : fp(std::move(fp)) {}
|
||||
ssize_t read(void *buf, size_t len) override;
|
||||
off_t seek(off_t off, int whence) override;
|
||||
protected:
|
||||
ssize_t do_write(const void *buf, size_t len) override;
|
||||
private:
|
||||
sFILE fp;
|
||||
};
|
||||
|
||||
// channel_ptr -> sFILE
|
||||
sFILE make_channel_fp(channel_ptr &&strm);
|
||||
// stream_ptr -> sFILE
|
||||
sFILE make_stream_fp(stream_ptr &&strm);
|
||||
|
||||
template <class T, class... Args>
|
||||
sFILE make_channel_fp(Args &&... args) {
|
||||
return make_channel_fp(channel_ptr(new T(std::forward<Args>(args)...)));
|
||||
sFILE make_stream_fp(Args &&... args) {
|
||||
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(io_error_more)]
|
||||
#![feature(utf8_chunks)]
|
||||
|
||||
pub use const_format;
|
||||
pub use libc;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
|
@ -11,12 +12,14 @@ use cxx_extern::*;
|
|||
pub use files::*;
|
||||
pub use logging::*;
|
||||
pub use misc::*;
|
||||
pub use result::*;
|
||||
|
||||
mod cstr;
|
||||
mod cxx_extern;
|
||||
mod files;
|
||||
mod logging;
|
||||
mod misc;
|
||||
mod result;
|
||||
mod xwrap;
|
||||
|
||||
#[cxx::bridge]
|
||||
|
@ -34,16 +37,22 @@ pub mod ffi {
|
|||
|
||||
unsafe extern "C++" {
|
||||
include!("misc.hpp");
|
||||
|
||||
#[namespace = "rust"]
|
||||
#[cxx_name = "Utf8CStr"]
|
||||
type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
|
||||
|
||||
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
#[cxx_name = "log_with_rs"]
|
||||
fn log_from_cxx(level: LogLevelCxx, msg: &[u8]);
|
||||
fn log_from_cxx(level: LogLevelCxx, msg: Utf8CStrRef);
|
||||
#[cxx_name = "set_log_level_state"]
|
||||
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
||||
fn exit_on_error(b: bool);
|
||||
fn cmdline_logging();
|
||||
fn resize_vec(vec: &mut Vec<u8>, size: usize);
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
|
@ -52,7 +61,7 @@ pub mod ffi {
|
|||
#[cxx_name = "fd_path"]
|
||||
fn fd_path_for_cxx(fd: i32, buf: &mut [u8]) -> isize;
|
||||
#[cxx_name = "map_file"]
|
||||
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
|
||||
fn map_file_for_cxx(path: Utf8CStrRef, rw: bool) -> &'static mut [u8];
|
||||
#[cxx_name = "map_fd"]
|
||||
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
|
||||
}
|
||||
|
@ -63,3 +72,12 @@ fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
|
|||
set_log_level_state(level, enabled)
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_vec(vec: &mut Vec<u8>, size: usize) {
|
||||
if size > vec.len() {
|
||||
vec.reserve(size - vec.len());
|
||||
}
|
||||
unsafe {
|
||||
vec.set_len(size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#ifndef __call_bypassing_fortify
|
||||
#define __call_bypassing_fortify(fn) (&fn)
|
||||
#endif
|
||||
|
||||
#undef vsnprintf
|
||||
static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
|
||||
constexpr int sz = 4096;
|
||||
|
@ -15,7 +19,7 @@ static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
|
|||
buf[0] = '\0';
|
||||
// Fortify logs when a fatal error occurs. Do not run through fortify again
|
||||
int len = std::min(__call_bypassing_fortify(vsnprintf)(buf, sz, fmt, ap), sz - 1);
|
||||
log_with_rs(level, byte_view(buf, len + 1));
|
||||
log_with_rs(level, rust::Utf8CStr(buf, len + 1));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,14 @@
|
|||
use std::fmt;
|
||||
use std::fmt::Arguments;
|
||||
use std::io::{stderr, stdout, Write};
|
||||
use std::process::exit;
|
||||
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::FromPrimitive;
|
||||
use std::fmt;
|
||||
use std::fmt::{Arguments, Display};
|
||||
use std::io::{stderr, stdout, Write};
|
||||
use std::panic::Location;
|
||||
use std::process::exit;
|
||||
|
||||
use crate::ffi::LogLevelCxx;
|
||||
use crate::{Utf8CStr, Utf8CStrBufArr};
|
||||
|
||||
// Error handling and logging throughout the Rust codebase in Magisk:
|
||||
//
|
||||
// All errors should be logged and consumed as soon as possible and converted into LoggedError.
|
||||
// For `Result` with errors that implement the `Display` trait, use the `?` operator to
|
||||
// log and convert to LoggedResult.
|
||||
//
|
||||
// To log an error with more information, use `ResultExt::log_with_msg()`.
|
||||
//
|
||||
// The "cxx" method variants in `CxxResultExt` are only used for C++ interop and
|
||||
// should not be used directly in any Rust code.
|
||||
//
|
||||
// For general logging, use the <level>!(...) macros.
|
||||
|
||||
// Ugly hack to avoid using enum
|
||||
#[allow(non_snake_case, non_upper_case_globals)]
|
||||
mod LogFlag {
|
||||
|
@ -50,7 +37,7 @@ pub static mut LOGGER: Logger = Logger {
|
|||
};
|
||||
|
||||
type LogWriter = fn(level: LogLevel, msg: &Utf8CStr);
|
||||
type Formatter<'a> = &'a mut dyn fmt::Write;
|
||||
pub(crate) type Formatter<'a> = &'a mut dyn fmt::Write;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Logger {
|
||||
|
@ -101,10 +88,8 @@ fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn log_from_cxx(level: LogLevelCxx, msg: &[u8]) {
|
||||
pub fn log_from_cxx(level: LogLevelCxx, msg: &Utf8CStr) {
|
||||
if let Some(level) = LogLevel::from_i32(level.repr) {
|
||||
// SAFETY: The null termination is handled on the C++ side
|
||||
let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) };
|
||||
log_with_writer(level, |write| write(level, msg));
|
||||
}
|
||||
}
|
||||
|
@ -173,188 +158,3 @@ macro_rules! debug {
|
|||
macro_rules! debug {
|
||||
($($args:tt)+) => {};
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LoggedError {}
|
||||
|
||||
// Automatically handle all printable errors
|
||||
impl<T: Display> From<T> for LoggedError {
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn from(e: T) -> Self {
|
||||
log_with_args(LogLevel::Error, format_args_nl!("{:#}", e));
|
||||
LoggedError::default()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn from(e: T) -> Self {
|
||||
let caller = Location::caller();
|
||||
log_with_args(
|
||||
LogLevel::Error,
|
||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
||||
);
|
||||
LoggedError::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub type LoggedResult<T> = Result<T, LoggedError>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_err {
|
||||
($msg:literal $(,)?) => {{
|
||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!($msg));
|
||||
$crate::LoggedError::default()
|
||||
}};
|
||||
($err:expr $(,)?) => {{
|
||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!("{}", $err));
|
||||
$crate::LoggedError::default()
|
||||
}};
|
||||
($($args:tt)+) => {{
|
||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+));
|
||||
$crate::LoggedError::default()
|
||||
}};
|
||||
}
|
||||
|
||||
pub trait ResultExt<T> {
|
||||
fn log(self) -> LoggedResult<T>;
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
pub trait ResultNoLog<T> {
|
||||
fn no_log(self) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
// Internal C++ bridging logging routines
|
||||
pub(crate) trait CxxResultExt<T> {
|
||||
fn log_cxx(self) -> LoggedResult<T>;
|
||||
fn log_cxx_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
trait LogImpl<T> {
|
||||
fn log_impl(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T>;
|
||||
fn log_with_msg_impl<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
impl<T, E> ResultNoLog<T> for Result<T, E> {
|
||||
fn no_log(self) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => Err(LoggedError::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ResultNoLog<T> for Option<T> {
|
||||
fn no_log(self) -> LoggedResult<T> {
|
||||
match self {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(LoggedError::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R: LogImpl<T>> CxxResultExt<T> for R {
|
||||
fn log_cxx(self) -> LoggedResult<T> {
|
||||
self.log_impl(LogLevel::ErrorCxx, None)
|
||||
}
|
||||
|
||||
fn log_cxx_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.log_with_msg_impl(LogLevel::ErrorCxx, None, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R: LogImpl<T>> ResultExt<T> for R {
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn log(self) -> LoggedResult<T> {
|
||||
self.log_impl(LogLevel::Error, None)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn log(self) -> LoggedResult<T> {
|
||||
self.log_impl(LogLevel::Error, Some(Location::caller()))
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.log_with_msg_impl(LogLevel::Error, None, f)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.log_with_msg_impl(LogLevel::Error, Some(Location::caller()), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LogImpl<T> for LoggedResult<T> {
|
||||
fn log_impl(self, _: LogLevel, _: Option<&'static Location>) -> LoggedResult<T> {
|
||||
self
|
||||
}
|
||||
|
||||
fn log_with_msg_impl<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => {
|
||||
log_with_formatter(level, |w| {
|
||||
if let Some(caller) = caller {
|
||||
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
||||
}
|
||||
f(w)?;
|
||||
w.write_char('\n')
|
||||
});
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E: Display> LogImpl<T> for Result<T, E> {
|
||||
fn log_impl(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
if let Some(caller) = caller {
|
||||
log_with_args(
|
||||
level,
|
||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
||||
);
|
||||
} else {
|
||||
log_with_args(level, format_args_nl!("{:#}", e));
|
||||
}
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log_with_msg_impl<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
log_with_formatter(level, |w| {
|
||||
if let Some(caller) = caller {
|
||||
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
||||
}
|
||||
f(w)?;
|
||||
writeln!(w, ": {:#}", e)
|
||||
});
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,3 +274,19 @@ int ssprintf(char *dest, size_t size, const char *fmt, ...) {
|
|||
size_t strscpy(char *dest, const char *src, size_t size) {
|
||||
return std::min(strlcpy(dest, src, size), size - 1);
|
||||
}
|
||||
|
||||
extern "C" void cxx$utf8str$new(rust::Utf8CStr *self, const void *s, size_t len);
|
||||
extern "C" const char *cxx$utf8str$ptr(const rust::Utf8CStr *self);
|
||||
extern "C" size_t cxx$utf8str$len(const rust::Utf8CStr *self);
|
||||
|
||||
rust::Utf8CStr::Utf8CStr(const char *s, size_t len) {
|
||||
cxx$utf8str$new(this, s, len);
|
||||
}
|
||||
|
||||
const char *rust::Utf8CStr::data() const {
|
||||
return cxx$utf8str$ptr(this);
|
||||
}
|
||||
|
||||
size_t rust::Utf8CStr::length() const {
|
||||
return cxx$utf8str$len(this);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,10 @@
|
|||
#include "xwrap.hpp"
|
||||
|
||||
#define DISALLOW_COPY_AND_MOVE(clazz) \
|
||||
clazz(const clazz &) = delete; \
|
||||
clazz(const clazz&) = delete; \
|
||||
clazz(clazz &&) = delete;
|
||||
|
||||
#define ALLOW_MOVE_ONLY(clazz) \
|
||||
clazz() = default; \
|
||||
clazz(const clazz&) = delete; \
|
||||
clazz(clazz &&o) { swap(o); } \
|
||||
clazz& operator=(clazz &&o) { swap(o); return *this; }
|
||||
|
@ -206,16 +205,32 @@ private:
|
|||
uint8_t arr[N];
|
||||
};
|
||||
|
||||
class byte_channel;
|
||||
class byte_stream;
|
||||
|
||||
struct heap_data : public byte_data {
|
||||
ALLOW_MOVE_ONLY(heap_data)
|
||||
|
||||
heap_data() = default;
|
||||
explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {}
|
||||
~heap_data() { free(_buf); }
|
||||
|
||||
// byte_channel needs to reallocate the internal buffer
|
||||
friend byte_channel;
|
||||
// byte_stream needs to reallocate the internal buffer
|
||||
friend byte_stream;
|
||||
};
|
||||
|
||||
struct owned_fd {
|
||||
ALLOW_MOVE_ONLY(owned_fd)
|
||||
|
||||
owned_fd() : fd(-1) {}
|
||||
owned_fd(int fd) : fd(fd) {}
|
||||
~owned_fd() { close(fd); fd = -1; }
|
||||
|
||||
operator int() { return fd; }
|
||||
int release() { int f = fd; fd = -1; return f; }
|
||||
void swap(owned_fd &owned) { std::swap(fd, owned.fd); }
|
||||
|
||||
private:
|
||||
int fd;
|
||||
};
|
||||
|
||||
rust::Vec<size_t> mut_u8_patch(
|
||||
|
@ -310,3 +325,36 @@ void exec_command_async(Args &&...args) {
|
|||
};
|
||||
exec_command(exec);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr auto operator+(T e) noexcept ->
|
||||
std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> {
|
||||
return static_cast<std::underlying_type_t<T>>(e);
|
||||
}
|
||||
|
||||
namespace rust {
|
||||
|
||||
struct Utf8CStr {
|
||||
const char *data() const;
|
||||
size_t length() const;
|
||||
Utf8CStr(const char *s, size_t len);
|
||||
|
||||
Utf8CStr() : Utf8CStr("", 1) {};
|
||||
Utf8CStr(const Utf8CStr &o) = default;
|
||||
Utf8CStr(Utf8CStr &&o) = default;
|
||||
Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {};
|
||||
Utf8CStr(std::string_view s) : Utf8CStr(s.data(), s.length() + 1) {};
|
||||
Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {};
|
||||
const char *c_str() const { return this->data(); }
|
||||
size_t size() const { return this->length(); }
|
||||
bool empty() const { return this->length() == 0 ; }
|
||||
operator std::string_view() { return {data(), length()}; }
|
||||
|
||||
private:
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-private-field"
|
||||
std::array<std::uintptr_t, 2> repr;
|
||||
#pragma clang diagnostic pop
|
||||
};
|
||||
|
||||
} // namespace rust
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::fmt::Arguments;
|
||||
use std::io::Write;
|
||||
use std::process::exit;
|
||||
use std::{io, slice, str};
|
||||
use std::{fmt, io, slice, str};
|
||||
|
||||
use argh::EarlyExit;
|
||||
use libc::c_char;
|
||||
|
@ -76,11 +78,40 @@ impl<T> LibcReturn for *mut T {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait BytesExt {
|
||||
fn find(&self, needle: &[u8]) -> Option<usize>;
|
||||
fn contains(&self, needle: &[u8]) -> bool {
|
||||
self.find(needle).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]> + ?Sized> BytesExt for T {
|
||||
fn find(&self, needle: &[u8]) -> Option<usize> {
|
||||
fn inner(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||
unsafe {
|
||||
let ptr: *const u8 = libc::memmem(
|
||||
haystack.as_ptr().cast(),
|
||||
haystack.len(),
|
||||
needle.as_ptr().cast(),
|
||||
needle.len(),
|
||||
)
|
||||
.cast();
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(ptr.offset_from(haystack.as_ptr()) as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
inner(self.as_ref(), needle)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MutBytesExt {
|
||||
fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize>;
|
||||
}
|
||||
|
||||
impl<T: AsMut<[u8]>> MutBytesExt for T {
|
||||
impl<T: AsMut<[u8]> + ?Sized> MutBytesExt for T {
|
||||
fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize> {
|
||||
ffi::mut_u8_patch(self.as_mut(), from, to)
|
||||
}
|
||||
|
@ -117,3 +148,16 @@ impl<T> EarlyExitExt<T> for Result<T, EarlyExit> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FmtAdaptor<'a, T>(pub &'a mut T)
|
||||
where
|
||||
T: Write;
|
||||
|
||||
impl<T: Write> fmt::Write for FmtAdaptor<'_, T> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.0.write_all(s.as_bytes()).map_err(|_| fmt::Error)
|
||||
}
|
||||
fn write_fmt(&mut self, args: Arguments<'_>) -> fmt::Result {
|
||||
self.0.write_fmt(args).map_err(|_| fmt::Error)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
|
||||
static inline int fexecve(int fd, char* const* argv, char* const* envp) {
|
||||
syscall(__NR_execveat, fd, "", argv, envp, AT_EMPTY_PATH);
|
||||
if (errno == ENOSYS) {
|
||||
char buf[256];
|
||||
ssprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
execve(buf, argv, envp);
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
use std::panic::Location;
|
||||
|
||||
use crate::logging::Formatter;
|
||||
use crate::{log_with_args, log_with_formatter, LogLevel};
|
||||
|
||||
// Error handling throughout the Rust codebase in Magisk:
|
||||
//
|
||||
// All errors should be logged and consumed as soon as possible and converted into LoggedError.
|
||||
// For `Result` with errors that implement the `Display` trait, use the `?` operator to
|
||||
// log and convert to LoggedResult.
|
||||
//
|
||||
// To log an error with more information, use `ResultExt::log_with_msg()`.
|
||||
//
|
||||
// The "cxx" method variants in `CxxResultExt` are only used for C++ interop and
|
||||
// should not be used directly in any Rust code.
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LoggedError {}
|
||||
pub type LoggedResult<T> = Result<T, LoggedError>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log_err {
|
||||
($($args:tt)+) => {{
|
||||
$crate::log_with_args($crate::LogLevel::Error, format_args_nl!($($args)+));
|
||||
$crate::LoggedError::default()
|
||||
}};
|
||||
}
|
||||
|
||||
// Any result or option can be silenced
|
||||
pub trait SilentResultExt<T> {
|
||||
fn silent(self) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
impl<T, E> SilentResultExt<T> for Result<T, E> {
|
||||
fn silent(self) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => Err(LoggedError::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SilentResultExt<T> for Option<T> {
|
||||
fn silent(self) -> LoggedResult<T> {
|
||||
match self {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(LoggedError::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public API for logging results
|
||||
pub trait ResultExt<T> {
|
||||
fn log(self) -> LoggedResult<T>;
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
// Internal C++ bridging logging routines
|
||||
pub(crate) trait CxxResultExt<T> {
|
||||
fn log_cxx(self) -> LoggedResult<T>;
|
||||
fn log_cxx_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
trait Loggable<T> {
|
||||
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T>;
|
||||
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T>;
|
||||
}
|
||||
|
||||
impl<T, R: Loggable<T>> CxxResultExt<T> for R {
|
||||
fn log_cxx(self) -> LoggedResult<T> {
|
||||
self.do_log(LogLevel::ErrorCxx, None)
|
||||
}
|
||||
|
||||
fn log_cxx_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.do_log_msg(LogLevel::ErrorCxx, None, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R: Loggable<T>> ResultExt<T> for R {
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn log(self) -> LoggedResult<T> {
|
||||
self.do_log(LogLevel::Error, None)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn log(self) -> LoggedResult<T> {
|
||||
self.do_log(LogLevel::Error, Some(Location::caller()))
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.do_log_msg(LogLevel::Error, None, f)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
|
||||
self.do_log_msg(LogLevel::Error, Some(Location::caller()), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Loggable<T> for LoggedResult<T> {
|
||||
fn do_log(self, _: LogLevel, _: Option<&'static Location>) -> LoggedResult<T> {
|
||||
self
|
||||
}
|
||||
|
||||
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => {
|
||||
log_with_formatter(level, |w| {
|
||||
if let Some(caller) = caller {
|
||||
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
||||
}
|
||||
f(w)?;
|
||||
w.write_char('\n')
|
||||
});
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E: Display> Loggable<T> for Result<T, E> {
|
||||
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
if let Some(caller) = caller {
|
||||
log_with_args(
|
||||
level,
|
||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
||||
);
|
||||
} else {
|
||||
log_with_args(level, format_args_nl!("{:#}", e));
|
||||
}
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
|
||||
self,
|
||||
level: LogLevel,
|
||||
caller: Option<&'static Location>,
|
||||
f: F,
|
||||
) -> LoggedResult<T> {
|
||||
match self {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
log_with_formatter(level, |w| {
|
||||
if let Some(caller) = caller {
|
||||
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
|
||||
}
|
||||
f(w)?;
|
||||
writeln!(w, ": {:#}", e)
|
||||
});
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically convert all printable errors to LoggedError to support `?` operator
|
||||
impl<T: Display> From<T> for LoggedError {
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn from(e: T) -> Self {
|
||||
log_with_args(LogLevel::Error, format_args_nl!("{:#}", e));
|
||||
LoggedError::default()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(debug_assertions)]
|
||||
fn from(e: T) -> Self {
|
||||
let caller = Location::caller();
|
||||
log_with_args(
|
||||
LogLevel::Error,
|
||||
format_args_nl!("[{}:{}] {:#}", caller.file(), caller.line(), e),
|
||||
);
|
||||
LoggedError::default()
|
||||
}
|
||||
}
|
|
@ -7,30 +7,25 @@
|
|||
using namespace std;
|
||||
|
||||
static int strm_read(void *v, char *buf, int len) {
|
||||
auto strm = static_cast<channel *>(v);
|
||||
auto strm = static_cast<stream *>(v);
|
||||
return strm->read(buf, len);
|
||||
}
|
||||
|
||||
static int strm_write(void *v, const char *buf, int len) {
|
||||
auto strm = static_cast<channel *>(v);
|
||||
auto strm = static_cast<stream *>(v);
|
||||
if (!strm->write(buf, len))
|
||||
return -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
static fpos_t strm_seek(void *v, fpos_t off, int whence) {
|
||||
auto strm = static_cast<channel *>(v);
|
||||
return strm->seek(off, whence);
|
||||
}
|
||||
|
||||
static int strm_close(void *v) {
|
||||
auto strm = static_cast<channel *>(v);
|
||||
auto strm = static_cast<stream *>(v);
|
||||
delete strm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sFILE make_channel_fp(channel_ptr &&strm) {
|
||||
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, strm_seek, strm_close));
|
||||
sFILE make_stream_fp(stream_ptr &&strm) {
|
||||
auto fp = make_file(funopen(strm.release(), strm_read, strm_write, nullptr, strm_close));
|
||||
setbuf(fp.get(), nullptr);
|
||||
return fp;
|
||||
}
|
||||
|
@ -50,40 +45,6 @@ ssize_t in_stream::readFully(void *buf, size_t len) {
|
|||
return read_sz;
|
||||
}
|
||||
|
||||
ssize_t in_stream::readv(const iovec *iov, int iovcnt) {
|
||||
size_t read_sz = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
auto ret = readFully(iov[i].iov_base, iov[i].iov_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read_sz += ret;
|
||||
}
|
||||
return read_sz;
|
||||
}
|
||||
|
||||
ssize_t out_stream::writev(const iovec *iov, int iovcnt) {
|
||||
size_t write_sz = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
if (!write(iov[i].iov_base, iov[i].iov_len))
|
||||
return write_sz;
|
||||
write_sz += iov[i].iov_len;
|
||||
}
|
||||
return write_sz;
|
||||
}
|
||||
|
||||
ssize_t fp_channel::read(void *buf, size_t len) {
|
||||
auto ret = fread(buf, 1, len, fp.get());
|
||||
return ret ? ret : (ferror(fp.get()) ? -1 : 0);
|
||||
}
|
||||
|
||||
ssize_t fp_channel::do_write(const void *buf, size_t len) {
|
||||
return fwrite(buf, 1, len, fp.get());
|
||||
}
|
||||
|
||||
off_t fp_channel::seek(off_t off, int whence) {
|
||||
return fseek(fp.get(), off, whence);
|
||||
}
|
||||
|
||||
bool filter_out_stream::write(const void *buf, size_t len) {
|
||||
return base->write(buf, len);
|
||||
}
|
||||
|
@ -131,14 +92,14 @@ void chunk_out_stream::finalize() {
|
|||
}
|
||||
}
|
||||
|
||||
ssize_t byte_channel::read(void *buf, size_t len) {
|
||||
ssize_t byte_stream::read(void *buf, size_t len) {
|
||||
len = std::min((size_t) len, _data._sz- _pos);
|
||||
memcpy(buf, _data.buf() + _pos, len);
|
||||
_pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
bool byte_channel::write(const void *buf, size_t len) {
|
||||
bool byte_stream::write(const void *buf, size_t len) {
|
||||
resize(_pos + len);
|
||||
memcpy(_data.buf() + _pos, buf, len);
|
||||
_pos += len;
|
||||
|
@ -146,27 +107,7 @@ bool byte_channel::write(const void *buf, size_t len) {
|
|||
return true;
|
||||
}
|
||||
|
||||
off_t byte_channel::seek(off_t off, int whence) {
|
||||
off_t np;
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
np = _pos + off;
|
||||
break;
|
||||
case SEEK_END:
|
||||
np = _data._sz+ off;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
np = off;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
resize(np, true);
|
||||
_pos = np;
|
||||
return np;
|
||||
}
|
||||
|
||||
void byte_channel::resize(size_t new_sz, bool zero) {
|
||||
void byte_stream::resize(size_t new_sz, bool zero) {
|
||||
bool resize = false;
|
||||
size_t old_cap = _cap;
|
||||
while (new_sz > _cap) {
|
||||
|
@ -180,27 +121,38 @@ void byte_channel::resize(size_t new_sz, bool zero) {
|
|||
}
|
||||
}
|
||||
|
||||
ssize_t fd_channel::read(void *buf, size_t len) {
|
||||
ssize_t rust_vec_stream::read(void *buf, size_t len) {
|
||||
len = std::min<size_t>(len, _data.size() - _pos);
|
||||
memcpy(buf, _data.data() + _pos, len);
|
||||
_pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
bool rust_vec_stream::write(const void *buf, size_t len) {
|
||||
ensure_size(_pos + len);
|
||||
memcpy(_data.data() + _pos, buf, len);
|
||||
_pos += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void rust_vec_stream::ensure_size(size_t sz, bool zero) {
|
||||
size_t old_sz = _data.size();
|
||||
if (sz > old_sz) {
|
||||
resize_vec(_data, sz);
|
||||
if (zero)
|
||||
memset(_data.data() + old_sz, 0, sz - old_sz);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t fd_stream::read(void *buf, size_t len) {
|
||||
return ::read(fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t fd_channel::readv(const iovec *iov, int iovcnt) {
|
||||
return ::readv(fd, iov, iovcnt);
|
||||
}
|
||||
|
||||
ssize_t fd_channel::do_write(const void *buf, size_t len) {
|
||||
ssize_t fd_stream::do_write(const void *buf, size_t len) {
|
||||
return ::write(fd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t fd_channel::writev(const iovec *iov, int iovcnt) {
|
||||
return ::writev(fd, iov, iovcnt);
|
||||
}
|
||||
|
||||
off_t fd_channel::seek(off_t off, int whence) {
|
||||
return lseek(fd, off, whence);
|
||||
}
|
||||
|
||||
bool file_channel::write(const void *buf, size_t len) {
|
||||
bool file_stream::write(const void *buf, size_t len) {
|
||||
size_t write_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
|
@ -214,3 +166,36 @@ bool file_channel::write(const void *buf, size_t len) {
|
|||
} while (write_sz != len && ret != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_IOV
|
||||
|
||||
ssize_t in_stream::readv(const iovec *iov, int iovcnt) {
|
||||
size_t read_sz = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
auto ret = readFully(iov[i].iov_base, iov[i].iov_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read_sz += ret;
|
||||
}
|
||||
return read_sz;
|
||||
}
|
||||
|
||||
ssize_t out_stream::writev(const iovec *iov, int iovcnt) {
|
||||
size_t write_sz = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
if (!write(iov[i].iov_base, iov[i].iov_len))
|
||||
return write_sz;
|
||||
write_sz += iov[i].iov_len;
|
||||
}
|
||||
return write_sz;
|
||||
}
|
||||
|
||||
ssize_t fd_stream::readv(const iovec *iov, int iovcnt) {
|
||||
return ::readv(fd, iov, iovcnt);
|
||||
}
|
||||
|
||||
ssize_t fd_stream::writev(const iovec *iov, int iovcnt) {
|
||||
return ::writev(fd, iov, iovcnt);
|
||||
}
|
||||
|
||||
#endif // ENABLE_IOV
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue