├── .gitattributes
├── .github
└── workflows
│ └── module.yml
├── .gitignore
├── .gitmodules
├── .idea
└── copyright
│ ├── GPL_v3.xml
│ └── profiles_settings.xml
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── module.gradle
├── module
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── cpp
│ ├── CMakeLists.txt
│ ├── adbd
│ │ ├── adbd_preload.cpp
│ │ └── adbd_wrapper_main.cpp
│ ├── core
│ │ ├── binder_hook.cpp
│ │ ├── binder_hook.h
│ │ ├── bridge_service.cpp
│ │ ├── bridge_service.h
│ │ ├── main.cpp
│ │ ├── main.h
│ │ ├── main_riru.cpp
│ │ ├── main_zygisk.cpp
│ │ ├── manager_process.cpp
│ │ ├── manager_process.h
│ │ ├── settings_process.cpp
│ │ ├── settings_process.h
│ │ ├── system_server.cpp
│ │ └── system_server.h
│ ├── include
│ │ ├── config.h
│ │ ├── logging.h
│ │ └── zygisk.hpp
│ ├── main
│ │ ├── adb_root.hpp
│ │ ├── main.cpp
│ │ ├── sui_main.hpp
│ │ └── uninstall_main.hpp
│ └── util
│ │ ├── android.cpp
│ │ ├── app_process.cpp
│ │ ├── dex_file.cpp
│ │ ├── include
│ │ ├── android.h
│ │ ├── app_process.h
│ │ ├── dex_file.h
│ │ ├── memory.h
│ │ ├── misc.h
│ │ ├── plt.h
│ │ ├── selinux.h
│ │ └── socket.h
│ │ ├── memory.cpp
│ │ ├── misc.cpp
│ │ ├── plt.c
│ │ ├── selinux.cpp
│ │ └── socket.cpp
│ └── java
│ └── rikka
│ └── sui
│ ├── binder
│ ├── HookedBinderProxy.java
│ ├── IBinderWrapper.java
│ ├── Transaction.java
│ └── TransactionCodeExporter.java
│ ├── installer
│ ├── Installer.java
│ └── Uninstaller.java
│ ├── manager
│ ├── ManagerConstants.java
│ ├── ManagerProcess.java
│ └── WorkerHandler.java
│ ├── model
│ └── AppInfo.java
│ ├── resource
│ └── SuiApk.java
│ ├── server
│ ├── ServerConstants.java
│ ├── Starter.java
│ ├── SuiClientManager.java
│ ├── SuiConfig.java
│ ├── SuiConfigManager.java
│ ├── SuiDatabase.java
│ ├── SuiService.java
│ ├── SuiUserServiceManager.java
│ ├── bridge
│ │ └── BridgeServiceClient.java
│ └── userservice
│ │ └── Starter.java
│ ├── settings
│ ├── ActivityThreadUtil.java
│ ├── HandlerUtil.java
│ ├── SettingsConstants.java
│ ├── SettingsInstrumentation.java
│ ├── SettingsProcess.java
│ └── WorkerHandler.java
│ ├── shell
│ └── Shell.java
│ ├── shortcut
│ ├── ShortcutConstants.java
│ └── SuiShortcut.java
│ ├── systemserver
│ ├── Bridge.java
│ ├── BridgeService.java
│ ├── PackageReceiver.java
│ ├── SystemProcess.java
│ └── SystemServerConstants.java
│ └── util
│ ├── AppNameComparator.java
│ ├── BridgeServiceClient.java
│ ├── BuildUtils.java
│ ├── InstrumentationUtil.java
│ ├── LabelComparator.java
│ ├── Logger.java
│ ├── MapUtil.java
│ ├── OsUtils.java
│ ├── ParcelFileDescriptorUtil.java
│ ├── ParcelUtils.java
│ ├── Preconditions.java
│ ├── SQLiteDataBaseRemoteCompat.java
│ ├── Unsafe.java
│ └── UserHandleCompat.java
├── settings.gradle
├── template
└── magisk_module
│ ├── .gitattributes
│ ├── CHANGELOG.md
│ ├── META-INF
│ └── com
│ │ └── google
│ │ └── android
│ │ ├── update-binary
│ │ └── updater-script
│ ├── customize.sh
│ ├── module.prop
│ ├── post-fs-data.sh
│ ├── post-install.example.sh
│ ├── riru.sh
│ ├── rish
│ ├── sepolicy.rule
│ ├── uninstall.sh
│ ├── util_functions.sh
│ └── verify.sh
└── ui
├── .gitignore
├── aapt2-resources.cfg
├── build.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── rikka
│ └── sui
│ ├── SuiActivity.java
│ ├── SuiRequestPermissionDialog.java
│ ├── app
│ ├── AppActivity.java
│ └── AppFragment.java
│ ├── ktx
│ ├── Drawable.kt
│ ├── Handler.kt
│ ├── LayoutInflater.kt
│ ├── Resources.kt
│ ├── TextView.kt
│ └── Window.kt
│ ├── management
│ ├── ManagementAdapter.kt
│ ├── ManagementAppItemViewHolder.kt
│ ├── ManagementFragment.kt
│ └── ManagementViewModel.kt
│ ├── model
│ └── AppInfo.java
│ ├── permission
│ ├── ConfirmationDialog.java
│ └── SystemDialogRootView.java
│ ├── server
│ └── SuiConfig.java
│ └── util
│ ├── AppIconCache.kt
│ ├── AppIconUtil.java
│ ├── AppInfoComparator.java
│ ├── AppLabel.java
│ ├── AppNameComparator.java
│ ├── BridgeServiceClient.java
│ ├── LabelComparator.java
│ ├── Logger.java
│ ├── Preconditions.java
│ ├── TextUtilsCompat.java
│ ├── Unsafe.java
│ └── UserHandleCompat.java
└── res
├── anim
└── stagger_layout_animation.xml
├── animator
└── alpha_animator.xml
├── color
└── confirmation_dialog_button_text.xml
├── drawable
├── confirmation_dialog_background.xml
├── ic_close_24.xml
├── ic_shortcut_24.xml
└── ic_su_24.xml
├── layout
├── appbar.xml
├── appbar_fragment_activity.xml
├── confirmation_dialog.xml
├── main.xml
├── management.xml
└── management_app_item.xml
├── raw
└── keep.xml
├── values-night
└── styles.xml
├── values-v31
└── colors.xml
├── values-zh-rCN
└── strings.xml
├── values-zh-rTW
└── strings.xml
└── values
├── colors.xml
├── dimens.xml
├── strings.xml
├── styles.xml
└── themes.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
3 | *.bat text eol=crlf
4 | *.jar binary
--------------------------------------------------------------------------------
/.github/workflows/module.yml:
--------------------------------------------------------------------------------
1 | name: Module
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - '**/README.md'
9 | jobs:
10 | build:
11 | runs-on: ubuntu-20.04
12 | if: ${{ !startsWith(github.event.head_commit.message, '[skip ci]') }}
13 |
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v3
17 | with:
18 | submodules: 'recursive'
19 | fetch-depth: 0
20 | - name: Setup Java
21 | uses: actions/setup-java@v3
22 | with:
23 | distribution: 'temurin'
24 | java-version: '17'
25 | cache: 'gradle'
26 | - name: Cache Gradle Dependencies
27 | uses: actions/cache@v2
28 | with:
29 | path: |
30 | ~/.gradle/caches
31 | ~/.gradle/wrapper
32 | !~/.gradle/caches/build-cache-*
33 | key: gradle-deps-module-${{ hashFiles('**/build.gradle') }}
34 | restore-keys: |
35 | gradle-deps
36 | - name: Cache Gradle Dependencies
37 | uses: actions/cache@v3
38 | with:
39 | path: |
40 | ~/.gradle/caches
41 | ~/.gradle/wrapper
42 | !~/.gradle/caches/build-cache-*
43 | key: gradle-deps-module-${{ hashFiles('**/build.gradle') }}
44 | restore-keys: |
45 | gradle-deps
46 | - name: Cache Ccache
47 | uses: actions/cache@v3
48 | with:
49 | path: ~/.ccache
50 | key: ${{ runner.os }}-ccache-cache-${{ github.sha }}
51 | restore-keys: ${{ runner.os }}-ccache-cache-
52 | - name: Install ccache
53 | run: |
54 | sudo apt-get install -y ccache
55 | ccache -o max_size=2G
56 | ccache -o hash_dir=false
57 | - name: Build with Gradle
58 | run: |
59 | mkdir -p ~/.gradle/wrapper
60 | mkdir -p ~/.gradle/caches
61 | [ $(du -s ~/.gradle/wrapper | awk '{ print $1 }') -gt 250000 ] && rm -rf ~/.gradle/wrapper/* || true
62 | find ~/.gradle/caches -exec touch -d "2 days ago" {} + || true
63 | echo 'org.gradle.caching=true' >> gradle.properties
64 | echo 'org.gradle.parallel=true' >> gradle.properties
65 | echo 'org.gradle.vfs.watch=true' >> gradle.properties
66 | echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties
67 | ./gradlew zipRiruDebug zipRiruRelease zipZygiskDebug zipZygiskRelease
68 | - name: Prepare artifact
69 | if: success()
70 | id: prepareArtifact
71 | run: |
72 | riruReleaseName=`ls out/sui-riru-*-release.zip | awk -F '(/|.zip)' '{print $2}'` && echo "::set-output name=riruReleaseName::$riruReleaseName"
73 | riruDebugName=`ls out/sui-riru-*-debug.zip | awk -F '(/|.zip)' '{print $2}'` && echo "::set-output name=riruDebugName::$riruDebugName"
74 | zygiskReleaseName=`ls out/sui-zygisk-*-release.zip | awk -F '(/|.zip)' '{print $2}'` && echo "::set-output name=zygiskReleaseName::$zygiskReleaseName"
75 | zygiskDebugName=`ls out/sui-zygisk-*-debug.zip | awk -F '(/|.zip)' '{print $2}'` && echo "::set-output name=zygiskDebugName::$zygiskDebugName"
76 | unzip out/sui-riru-*-release.zip -d sui-riru-release
77 | unzip out/sui-riru-*-debug.zip -d sui-riru-debug
78 | unzip out/sui-zygisk-*-release.zip -d sui-zygisk-release
79 | unzip out/sui-zygisk-*-debug.zip -d sui-zygisk-debug
80 | - name: Upload Riru release
81 | uses: actions/upload-artifact@v3
82 | with:
83 | name: ${{ steps.prepareArtifact.outputs.riruReleaseName }}
84 | path: './sui-riru-release/*'
85 | - name: Upload Riru debug
86 | uses: actions/upload-artifact@v3
87 | with:
88 | name: ${{ steps.prepareArtifact.outputs.riruDebugName }}
89 | path: './sui-riru-debug/*'
90 | - name: Upload Zygisk release
91 | uses: actions/upload-artifact@v3
92 | with:
93 | name: ${{ steps.prepareArtifact.outputs.zygiskReleaseName }}
94 | path: './sui-zygisk-release/*'
95 | - name: Upload Zygisk debug
96 | uses: actions/upload-artifact@v3
97 | with:
98 | name: ${{ steps.prepareArtifact.outputs.zygiskDebugName }}
99 | path: './sui-zygisk-debug/*'
100 | - name: Upload mappings
101 | uses: actions/upload-artifact@v3
102 | with:
103 | name: mappings
104 | path: |
105 | "module/build/outputs/mapping/release"
106 | "ui/build/outputs/mapping/release"
107 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | /.idea/caches/build_file_checksums.ser
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | .DS_Store
10 | /build
11 | /captures
12 | /out
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "api"]
2 | path = api
3 | url = git@github.com:RikkaApps/Shizuku-API.git
4 | branch = master
5 |
--------------------------------------------------------------------------------
/.idea/copyright/GPL_v3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application' version '8.0.2' apply false
3 | id 'com.android.library' version '8.0.2' apply false
4 | id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false
5 | alias libs.plugins.refine apply false
6 | }
7 |
8 | apply plugin: 'idea'
9 |
10 | idea.module {
11 | excludeDirs += file('out')
12 | resourceDirs += file('template')
13 | resourceDirs += file('scripts')
14 | }
15 |
16 | subprojects {
17 | plugins.withId("com.android.base") {
18 | plugins.apply('dev.rikka.tools.refine')
19 |
20 | android {
21 | compileSdk = 33
22 | defaultConfig {
23 | minSdk = 23
24 | targetSdk = 33
25 | }
26 | compileOptions {
27 | sourceCompatibility = JavaVersion.VERSION_17
28 | targetCompatibility = JavaVersion.VERSION_17
29 | }
30 | buildFeatures {
31 | aidl true
32 | }
33 | }
34 | }
35 | }
36 |
37 |
38 | tasks.register('clean', Delete) {
39 | delete rootProject.buildDir
40 | }
41 |
42 | ext {
43 | minSdkVersion = 23
44 | targetSdkVersion = 33
45 | api_min_sdk = 23
46 | api_target_sdk = 33
47 | }
48 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2028M"
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | android.enableResourceOptimizations=false
19 | android.enableParallelJsonGen=true
20 | android.enableNewResourceShrinker=true
21 | #android.experimental.enableNewResourceShrinker.preciseShrinking=true
22 | android.enableR8.fullMode=false
23 | android.nonTransitiveRClass=false
24 | android.nonFinalResIds=false
25 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RikkaApps/Sui/2f5fd2a04bc061eb2a8431cc3ede9066954f5a7c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jul 10 01:01:45 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/module.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | apply from: "$rootDir/api/manifest.gradle"
3 |
4 | gitCommitId = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
5 | gitCommitCount = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim())
6 |
7 | moduleLibraryName = "sui"
8 | moduleMinRiruApiVersion = 25
9 | moduleMinRiruVersionName = "v25.0.0"
10 | moduleRiruApiVersion = 25
11 |
12 | riruModuleId = "riru-sui"
13 | zygiskModuleId = "zygisk-sui"
14 |
15 | moduleName = "Sui"
16 | moduleAuthor = "Rikka"
17 | moduleDescription = "Modern superuser interface implementation."
18 | moduleVersionMinor = 5
19 | moduleVersionPatch = 1
20 | moduleVersion = "v${api_version_major}.${moduleVersionMinor}.${moduleVersionPatch}"
21 | moduleVersionCode = gitCommitCount
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/module/.gitignore:
--------------------------------------------------------------------------------
1 | /.externalNativeBuild
2 | /build
3 | /release
--------------------------------------------------------------------------------
/module/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -repackageclasses rikka.sui
2 |
3 | -keep class rikka.sui.server.Starter {
4 | public static void main(java.lang.String[]);
5 | }
6 |
7 | -keep class rikka.sui.server.userservice.Starter {
8 | public static void main(java.lang.String[]);
9 | }
10 |
11 | -keep class rikka.sui.systemserver.SystemProcess {
12 | public static void main(java.lang.String[]);
13 | public static boolean execTransact(android.os.Binder, int, long, long, int);
14 | }
15 |
16 | -keep class rikka.sui.manager.ManagerProcess {
17 | public static void main(java.lang.String[]);
18 | }
19 |
20 | -keep class rikka.sui.settings.SettingsProcess {
21 | public static void main(java.lang.String[]);
22 | public static boolean execTransact(android.os.Binder, int, long, long, int);
23 | }
24 |
25 | -keep class rikka.sui.installer.Installer {
26 | public static void main(java.lang.String[]);
27 | }
28 |
29 | -keep class rikka.sui.installer.Uninstaller {
30 | public static void main(java.lang.String[]);
31 | }
32 |
33 | -keep class rikka.sui.shell.Shell {
34 | public static void main(java.lang.String[]);
35 | }
36 |
37 | -keepnames class * implements android.os.Parcelable
38 |
39 | -keepclassmembers class * implements android.os.Parcelable {
40 | public static final android.os.Parcelable$Creator CREATOR;
41 | }
42 |
43 | -assumenosideeffects class android.util.Log {
44 | public static *** d(...);
45 | }
46 |
47 | -assumenosideeffects class rikka.sui.util.Logger {
48 | public *** d(...);
49 | }
50 |
51 | -assumenosideeffects class rikka.shizuku.server.util.Logger {
52 | public *** d(...);
53 | }
54 |
55 | -keepattributes SourceFile,LineNumberTable
56 | -renamesourcefileattribute SourceFile
57 |
58 | -dontwarn android.**
59 | -dontwarn com.android.**
60 |
--------------------------------------------------------------------------------
/module/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/module/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | project("sui")
4 |
5 | message("Build type: ${CMAKE_BUILD_TYPE} ${FLAVOR}")
6 |
7 | set(CMAKE_CXX_STANDARD 17)
8 |
9 | set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both")
10 | set(C_FLAGS "-Werror=format -fdata-sections -ffunction-sections -fno-exceptions -fno-rtti -fno-threadsafe-statics")
11 |
12 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
13 | set(C_FLAGS "${C_FLAGS} -O2 -fvisibility=hidden -fvisibility-inlines-hidden")
14 | set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections")
15 | else ()
16 | add_definitions(-DDEBUG)
17 | set(C_FLAGS "${C_FLAGS} -O0")
18 | endif ()
19 |
20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}")
21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS}")
22 |
23 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
24 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
25 |
26 | find_package(cxx REQUIRED CONFIG)
27 | find_package(riru REQUIRED CONFIG)
28 | find_package(nativehelper REQUIRED CONFIG)
29 |
30 | include_directories(".")
31 | include_directories("include")
32 | include_directories("util/include")
33 |
34 | add_library(util STATIC
35 | util/misc.cpp
36 | util/dex_file.cpp
37 | util/android.cpp
38 | util/plt.c
39 | util/selinux.cpp
40 | util/memory.cpp
41 | util/app_process.cpp
42 | util/socket.cpp)
43 | target_link_libraries(util cxx::cxx log nativehelper::nativehelper_header_only)
44 |
45 | if (FLAVOR STREQUAL "riru")
46 | set(CORE_MAIN_SOURCE "main_riru.cpp")
47 | add_definitions(-DRIRU_MODULE)
48 | add_definitions(-DRIRU_MODULE_API_VERSION=${RIRU_MODULE_API_VERSION})
49 | add_definitions(-DRIRU_MODULE_VERSION=${RIRU_MODULE_VERSION})
50 | add_definitions(-DRIRU_MODULE_VERSION_NAME=${RIRU_MODULE_VERSION_NAME})
51 | elseif (FLAVOR STREQUAL "zygisk")
52 | set(CORE_MAIN_SOURCE "main_zygisk.cpp")
53 | add_definitions(-DZYGISK_MODULE_ID=${ZYGISK_MODULE_ID})
54 | else ()
55 | message(FATAL_ERROR "Unknown flavor ${FLAVOR}")
56 | endif ()
57 |
58 | add_library(sui SHARED
59 | core/${CORE_MAIN_SOURCE}
60 | core/main.cpp
61 | core/system_server.cpp
62 | core/binder_hook.cpp
63 | core/bridge_service.cpp
64 | core/manager_process.cpp
65 | core/settings_process.cpp)
66 | target_link_libraries(sui util cxx::cxx log riru::riru nativehelper::nativehelper_header_only)
67 | set_target_properties(sui PROPERTIES LINK_FLAGS_RELEASE -s)
68 |
69 | add_executable(libmain.so main/main.cpp)
70 | target_link_libraries(libmain.so util cxx::cxx log riru::riru nativehelper::nativehelper_header_only)
71 | set_target_properties(libmain.so PROPERTIES LINK_FLAGS_RELEASE -s)
72 |
73 | add_executable(libadbd_wrapper.so
74 | adbd/adbd_wrapper_main.cpp)
75 | target_link_libraries(libadbd_wrapper.so cxx::cxx log)
76 | set_target_properties(libadbd_wrapper.so PROPERTIES LINK_FLAGS_RELEASE -s)
77 |
78 | add_library(adbd_preload SHARED
79 | adbd/adbd_preload.cpp)
80 | target_link_libraries(adbd_preload cxx::cxx log)
81 | set_target_properties(adbd_preload PROPERTIES LINK_FLAGS_RELEASE -s)
82 |
83 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
84 | add_custom_command(TARGET sui POST_BUILD
85 | COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libsui.so")
86 |
87 | add_custom_command(TARGET libmain.so POST_BUILD
88 | COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libmain.so")
89 |
90 | add_custom_command(TARGET libadbd_wrapper.so POST_BUILD
91 | COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libadbd_wrapper.so")
92 |
93 | add_custom_command(TARGET adbd_preload POST_BUILD
94 | COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libadbd_preload.so")
95 | endif ()
96 |
--------------------------------------------------------------------------------
/module/src/main/cpp/adbd/adbd_preload.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | extern "C" {
8 | [[gnu::constructor]] void constructor() {
9 | LOGD("preload constructor");
10 |
11 | auto ld_preload = getenv("SUI_LD_PRELOAD_BACKUP");
12 | if (ld_preload) {
13 | setenv("LD_PRELOAD", ld_preload, 1);
14 | } else {
15 | unsetenv("LD_PRELOAD");
16 | }
17 | }
18 |
19 | [[gnu::visibility("default")]] [[maybe_unused]]
20 | int __android_log_is_debuggable() { // NOLINT(bugprone-reserved-identifier)
21 | return 1;
22 | }
23 |
24 | using property_get_t = int(const char *, char *, const char *);
25 |
26 | [[gnu::visibility("default")]] [[maybe_unused]]
27 | int property_get(const char *key, char *value, const char *default_value) { // NOLINT(bugprone-reserved-identifier)
28 | if (key && value && strcmp("ro.debuggable", key) == 0) {
29 | value[0] = '1';
30 | value[1] = '\0';
31 | return 1;
32 | }
33 |
34 | static property_get_t * original = nullptr;
35 | if (!original) {
36 | original = (property_get_t *) dlsym(RTLD_NEXT, "property_get");
37 | }
38 | if (original) {
39 | return original(key, value, default_value);
40 | }
41 | return -1;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/module/src/main/cpp/adbd/adbd_wrapper_main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | using namespace std::literals::string_view_literals;
29 |
30 | int main(int argc, char **argv) {
31 | const char *adbd_ld_preload;
32 | const char *adbd_real;
33 |
34 | auto apex = "/apex/"sv;
35 | std::string_view argv0{argv[0]};
36 | if (argv0.length() > apex.length() && argv0.substr(0, apex.length()) == apex) {
37 | adbd_real = "/apex/com.android.adbd/bin/adbd_real";
38 | #ifdef __LP64__
39 | adbd_ld_preload = "/apex/com.android.adbd/lib64/libsui_adbd_preload.so";
40 | #else
41 | adbd_ld_preload = "/apex/com.android.adbd/lib/libsui_adbd_preload.so";
42 | #endif
43 | } else {
44 | adbd_real = "/system/bin/adbd_real";
45 | #ifdef __LP64__
46 | adbd_ld_preload = "/system/lib64/libsui_adbd_preload.so";
47 | #else
48 | adbd_ld_preload = "/system/lib/libsui_adbd_preload.so";
49 | #endif
50 | }
51 |
52 | LOGI("adbd_main");
53 | LOGD("adbd_real=%s", adbd_real);
54 | LOGD("adbd_ld_preload=%s", adbd_ld_preload);
55 |
56 | auto ld_preload = getenv("LD_PRELOAD");
57 | char new_ld_preload[PATH_MAX]{};
58 | if (ld_preload) {
59 | setenv("SUI_LD_PRELOAD_BACKUP", ld_preload, 1);
60 | snprintf(new_ld_preload, PATH_MAX, "%s:%s", adbd_ld_preload, ld_preload);
61 | } else {
62 | strcpy(new_ld_preload, adbd_ld_preload);
63 | }
64 | setenv("LD_PRELOAD", new_ld_preload, 1);
65 | LOGD("LD_PRELOAD=%s", new_ld_preload);
66 |
67 | auto root_seclabel = "--root_seclabel"sv;
68 | for (int i = 1; i < argc; ++i) {
69 | std::string_view argv_i{argv[i]};
70 | if (argv_i.length() > root_seclabel.length() && argv_i.substr(0, root_seclabel.length()) == root_seclabel) {
71 | argv[i] = strdup("--root_seclabel=u:r:magisk:s0");
72 | LOGD("root_seclabel -> u:r:magisk:s0");
73 | }
74 | }
75 |
76 | return execv(adbd_real, argv);
77 | }
78 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/binder_hook.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "binder_hook.h"
26 | #include "logging.h"
27 | #include
28 | #include
29 |
30 | static jmethodID original_execTransactMethodID;
31 |
32 | static const JNIInvokeInterface *old_JNIInvokeInterface = nullptr;
33 | static const JNINativeInterface *old_JNINativeInterface = nullptr;
34 |
35 | static JNIInvokeInterface *new_JNIInvokeInterface = nullptr;
36 | static JNINativeInterface *new_JNINativeInterface = nullptr;
37 |
38 | using CallBooleanMethodV_t = jboolean(JNIEnv *, jobject, jmethodID, va_list);
39 | using GetEnv_t = jint(JavaVM *, void **, jint);
40 |
41 | static GetEnv_t *old_GetEnv;
42 | static CallBooleanMethodV_t *old_CallBooleanMethodV;
43 | static BinderHook::ExecTransact_t *my_ExecTransact;
44 |
45 | using SetTableOverride_t = void(JNINativeInterface *);
46 |
47 | static jboolean new_CallBooleanMethodV(JNIEnv *env, jobject obj, jmethodID methodId, va_list args) {
48 | if (methodId == original_execTransactMethodID) {
49 | jboolean res = false;
50 | if (my_ExecTransact(&res, env, obj, args)) return res;
51 | }
52 |
53 | return old_CallBooleanMethodV(env, obj, methodId, args);
54 | }
55 |
56 | static jint new_GetEnv(JavaVM *vm, void **env, jint version) {
57 | jint res = old_GetEnv(vm, env, version);
58 | if (res == JNI_OK && env && *env) {
59 | ((JNIEnv *) *env)->functions = new_JNINativeInterface;
60 | }
61 | return res;
62 | }
63 |
64 | static void InstallDirectly(JavaVM *javaVm, JNIEnv *env) {
65 | // JavaVM
66 | old_JNIInvokeInterface = javaVm->functions;
67 | old_GetEnv = javaVm->functions->GetEnv;
68 | new_JNIInvokeInterface = new JNIInvokeInterface();
69 | memcpy(new_JNIInvokeInterface, javaVm->functions, sizeof(JNIInvokeInterface));
70 | new_JNIInvokeInterface->GetEnv = new_GetEnv;
71 |
72 | javaVm->functions = new_JNIInvokeInterface;
73 |
74 | // JNIEnv
75 | env->functions = new_JNINativeInterface;
76 | }
77 |
78 | static bool InstallOverrideTable() {
79 | if (android::GetApiLevel() < 26) return false;
80 |
81 | auto setTableOverride = (SetTableOverride_t *) plt_dlsym("_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface", nullptr);
82 | if (setTableOverride != nullptr) {
83 | setTableOverride(new_JNINativeInterface);
84 | return true;
85 | }
86 | return false;
87 | }
88 |
89 | void BinderHook::Install(JavaVM *javaVm, JNIEnv *env, ExecTransact_t *callback) {
90 | my_ExecTransact = callback;
91 |
92 | // Binder
93 | ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder"));
94 | original_execTransactMethodID = env->GetMethodID(binderClass.get(), "execTransact", "(IJJI)Z");
95 |
96 | // JNIEnv
97 | old_JNINativeInterface = env->functions;
98 | old_CallBooleanMethodV = env->functions->CallBooleanMethodV;
99 | new_JNINativeInterface = new JNINativeInterface();
100 | memcpy(new_JNINativeInterface, env->functions, sizeof(JNINativeInterface));
101 | new_JNINativeInterface->CallBooleanMethodV = new_CallBooleanMethodV;
102 |
103 | if (InstallOverrideTable()) {
104 | LOGI("installed override table");
105 | } else {
106 | LOGW("can't install override table");
107 | InstallDirectly(javaVm, env);
108 | }
109 | }
110 |
111 | void BinderHook::Uninstall(JavaVM *javaVm) {
112 | javaVm->functions = old_JNIInvokeInterface;
113 | }
114 |
115 | void BinderHook::Uninstall(JNIEnv *env) {
116 | env->functions = old_JNINativeInterface;
117 | }
118 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/binder_hook.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace BinderHook {
25 |
26 | using ExecTransact_t = bool(jboolean *, JNIEnv *, jobject, va_list);
27 |
28 | void Install(JavaVM *javaVm, JNIEnv *env, ExecTransact_t *callback);
29 |
30 | void Uninstall(JavaVM *javaVm);
31 |
32 | void Uninstall(JNIEnv *env);
33 | }
--------------------------------------------------------------------------------
/module/src/main/cpp/core/bridge_service.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 |
24 | namespace BridgeService {
25 |
26 | const jint BRIDGE_TRANSACTION_CODE = 1599296841; // ('_' << 24) | ('S' << 16) | ('U' << 8) | 'I'
27 |
28 | void init(JNIEnv *env);
29 | void insertFileMonitor(JNIEnv *env, const char* packageName, const char *func, const char *path);
30 | jobjectArray requestCheckProcess(JNIEnv *env, const char* packageName);
31 | }
--------------------------------------------------------------------------------
/module/src/main/cpp/core/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | void UmountApexAdbd() {
9 | static bool called = false;
10 | if (called) return;
11 |
12 | if (android::GetApiLevel() >= __ANDROID_API_R__) {
13 | called = true;
14 |
15 | umount2("/apex/com.android.adbd/bin", MNT_DETACH);
16 | if (android::Has32Bit() && !android::Has64Bit()) {
17 | umount2("/apex/com.android.adbd/lib", MNT_DETACH);
18 | }
19 | if (android::Has64Bit()) {
20 | umount2("/apex/com.android.adbd/lib64", MNT_DETACH);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/main.h:
--------------------------------------------------------------------------------
1 | #ifndef MAIN_H
2 | #define MAIN_H
3 |
4 | void UmountApexAdbd();
5 |
6 | #endif //MAIN_H
7 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/manager_process.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | #include "android.h"
40 | #include "logging.h"
41 | #include "riru.h"
42 | #include "misc.h"
43 | #include "dex_file.h"
44 | #include "bridge_service.h"
45 | #include "binder_hook.h"
46 | #include "config.h"
47 |
48 | namespace Manager {
49 |
50 | static jclass mainClass = nullptr;
51 |
52 | static bool installDex(JNIEnv *env, const char *appDataDir, Dex *dexFile) {
53 | if (android::GetApiLevel() < 26) {
54 | char dexPath[PATH_MAX], oatDir[PATH_MAX];
55 | snprintf(dexPath, PATH_MAX, "%s/sui/%s", appDataDir, DEX_NAME);
56 | snprintf(oatDir, PATH_MAX, "%s/sui/oat", appDataDir);
57 | dexFile->setPre26Paths(dexPath, oatDir);
58 | }
59 | dexFile->createClassLoader(env);
60 |
61 | mainClass = dexFile->findClass(env, MANAGER_PROCESS_CLASSNAME);
62 | if (!mainClass) {
63 | LOGE("unable to find main class");
64 | return false;
65 | }
66 | mainClass = (jclass) env->NewGlobalRef(mainClass);
67 |
68 | auto mainMethod = env->GetStaticMethodID(mainClass, "main", "([Ljava/lang/String;)V");
69 | if (!mainMethod) {
70 | LOGE("unable to find main method");
71 | env->ExceptionDescribe();
72 | env->ExceptionClear();
73 | return false;
74 | }
75 |
76 | auto args = env->NewObjectArray(0, env->FindClass("java/lang/String"), nullptr);
77 |
78 | env->CallStaticVoidMethod(mainClass, mainMethod, args);
79 | if (env->ExceptionCheck()) {
80 | LOGE("unable to call main method");
81 | env->ExceptionDescribe();
82 | env->ExceptionClear();
83 | return false;
84 | }
85 |
86 | return true;
87 | }
88 |
89 | void main(JNIEnv *env, const char *appDataDir, Dex *dexFile) {
90 | if (!dexFile->valid()) {
91 | LOGE("no dex");
92 | return;
93 | }
94 |
95 | LOGV("main: manager");
96 |
97 | LOGV("install dex");
98 |
99 | if (!installDex(env, appDataDir, dexFile)) {
100 | LOGE("can't install dex");
101 | return;
102 | }
103 |
104 | LOGV("install dex finished");
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/manager_process.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 | #include "dex_file.h"
24 |
25 | namespace Manager {
26 | void main(JNIEnv *env, const char *appDataDir, Dex *dexFile);
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/settings_process.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 | #include "dex_file.h"
24 |
25 | namespace Settings {
26 | void main(JNIEnv *env, const char *appDataDir, Dex *dexFile);
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/cpp/core/system_server.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #include
23 | #include "dex_file.h"
24 |
25 | namespace SystemServer {
26 | void main(JNIEnv *env, Dex *dexFile);
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/cpp/include/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | #define MANAGER_APPLICATION_ID "com.android.systemui"
23 | #define SETTINGS_APPLICATION_ID "com.android.settings"
24 |
25 | #define DEX_NAME "sui.dex"
26 | #define SYSTEM_PROCESS_CLASSNAME "rikka/sui/systemserver/SystemProcess"
27 | #define MANAGER_PROCESS_CLASSNAME "rikka/sui/manager/ManagerProcess"
28 | #define SETTINGS_PROCESS_CLASSNAME "rikka/sui/settings/SettingsProcess"
29 |
--------------------------------------------------------------------------------
/module/src/main/cpp/include/logging.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #ifndef _LOGGING_H
21 | #define _LOGGING_H
22 |
23 | #include
24 | #include "android/log.h"
25 |
26 | #ifndef LOG_TAG
27 | #define LOG_TAG "Sui"
28 | #endif
29 |
30 | #ifdef DEBUG
31 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
32 | #else
33 | #define LOGD(...)
34 | #endif
35 | #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
36 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
37 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
38 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
39 | #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
40 |
41 | #endif // _LOGGING_H
42 |
--------------------------------------------------------------------------------
/module/src/main/cpp/main/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "sui_main.hpp"
5 | #include "adb_root.hpp"
6 | #include "uninstall_main.hpp"
7 |
8 | using main_func = int (*)(int, char **);
9 |
10 | static main_func applet_func[] = {sui_main, adb_root_main, uninstall_main, nullptr };
11 |
12 | static const char* applet_names[] = {"sui", "adb_root", "uninstall", nullptr };
13 |
14 | int main(int argc, char **argv) {
15 | auto uid = getuid();
16 | if (uid != 0) {
17 | exit(EXIT_FAILURE);
18 | }
19 |
20 | auto base = basename(argv[0]);
21 | for (int i = 0; applet_names[i]; ++i) {
22 | if (strcmp(base, applet_names[i]) == 0) {
23 | return applet_func[i](argc, argv);
24 | }
25 | }
26 | return 1;
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/cpp/main/sui_main.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | /*
29 | * argv[1]: path of the module, such as /data/adb/modules/zygisk-sui
30 | */
31 | static int sui_main(int argc, char **argv) {
32 | LOGI("Sui starter begin: %s", argv[1]);
33 |
34 | if (daemon(false, false) != 0) {
35 | PLOGE("daemon");
36 | return EXIT_FAILURE;
37 | }
38 |
39 | wait_for_zygote();
40 |
41 | if (access("/data/adb/sui", F_OK) != 0) {
42 | mkdir("/data/adb/sui", 0600);
43 | }
44 | chmod("/data/adb/sui", 0600);
45 | chown("/data/adb/sui", 0, 0);
46 |
47 | auto root_path = argv[1];
48 |
49 | char dex_path[PATH_MAX]{0};
50 | strcpy(dex_path, root_path);
51 | strcat(dex_path, "/sui.dex");
52 |
53 | app_process(dex_path, root_path, "rikka.sui.server.Starter", "sui");
54 |
55 | return EXIT_SUCCESS;
56 | }
57 |
--------------------------------------------------------------------------------
/module/src/main/cpp/main/uninstall_main.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | /*
28 | * argv[1]: path of the module, such as /data/adb/modules/zygisk-sui
29 | */
30 | static int uninstall_main(int argc, char **argv) {
31 | LOGI("Sui uninstaller begin: %s", argv[1]);
32 |
33 | auto root_path = argv[1];
34 |
35 | char dex_path[PATH_MAX]{0};
36 | strcpy(dex_path, root_path);
37 | strcat(dex_path, "/sui.dex");
38 |
39 | if (copyfile(dex_path, "/dev/sui.dex") != 0) {
40 | PLOGE("copyfile");
41 | return EXIT_FAILURE;
42 | }
43 |
44 | if (daemon(false, false) != 0) {
45 | PLOGE("daemon");
46 | return EXIT_FAILURE;
47 | }
48 |
49 | wait_for_zygote();
50 |
51 | app_process("/dev/sui.dex", "/dev", "rikka.sui.installer.Uninstaller", "sui_uninstaller");
52 | unlink("/dev/sui.dex");
53 |
54 | return EXIT_SUCCESS;
55 | }
56 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/android.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #include
21 |
22 | namespace android {
23 |
24 | static int apiLevel = 0;
25 | static int previewApiLevel = 0;
26 | static int8_t has32Bit = -1;
27 | static int8_t has64Bit = -1;
28 |
29 | int GetApiLevel() {
30 | if (apiLevel > 0) return apiLevel;
31 |
32 | char buf[PROP_VALUE_MAX + 1];
33 | if (__system_property_get("ro.build.version.sdk", buf) > 0)
34 | apiLevel = atoi(buf);
35 |
36 | return apiLevel;
37 | }
38 |
39 | int GetPreviewApiLevel() {
40 | if (previewApiLevel > 0) return previewApiLevel;
41 |
42 | char buf[PROP_VALUE_MAX + 1];
43 | if (__system_property_get("ro.build.version.preview_sdk", buf) > 0)
44 | previewApiLevel = atoi(buf);
45 |
46 | return previewApiLevel;
47 | }
48 |
49 | bool Has32Bit() {
50 | if (has32Bit != -1) return has32Bit == 1;
51 |
52 | char buf[PROP_VALUE_MAX + 1];
53 | has32Bit = __system_property_get("ro.product.cpu.abilist32", buf) > 0 ? 1 : 0;
54 | return has32Bit;
55 | }
56 |
57 | bool Has64Bit() {
58 | if (has64Bit != -1) return has64Bit == 1;
59 |
60 | char buf[PROP_VALUE_MAX + 1];
61 | has64Bit = __system_property_get("ro.product.cpu.abilist64", buf) > 0 ? 1 : 0;
62 | return has64Bit;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/android.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | namespace android {
23 |
24 | int GetApiLevel();
25 |
26 | int GetPreviewApiLevel();
27 |
28 | bool Has32Bit();
29 |
30 | bool Has64Bit();
31 | }
32 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/app_process.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2022 Sui Contributors
18 | */
19 |
20 | #ifndef APP_PROCESS_H
21 | #define APP_PROCESS_H
22 |
23 | void app_process(const char *dex_path, const char *files_path, const char *main_class, const char *process_name);
24 |
25 | void wait_for_zygote();
26 |
27 | #endif //APP_PROCESS_H
28 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/dex_file.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #pragma once
21 |
22 | class Buffer {
23 |
24 | protected:
25 | uint8_t *bytes_ = nullptr;
26 | size_t size_ = 0;
27 | private:
28 | bool is_mmap_ = 0;
29 |
30 | public:
31 | Buffer() = default;
32 |
33 | Buffer(const char *path);
34 |
35 | Buffer(int fd, size_t size);
36 |
37 | ~Buffer();
38 |
39 | uint8_t *data() const;
40 |
41 | size_t size() const;
42 |
43 | int writeToFile(const char *path, mode_t mode);
44 | };
45 |
46 | class Dex {
47 |
48 | private:
49 | Buffer buffer_;
50 | char *pre26DexPath_ = nullptr;
51 | char *pre26OptDir_ = nullptr;
52 |
53 | jclass dexClassLoaderClass = nullptr;
54 | jmethodID findClassMethod = nullptr;
55 | jobject dexClassLoader = nullptr;
56 |
57 | public:
58 | Dex(int fd, size_t size);
59 |
60 | Dex(const char *path);
61 |
62 | ~Dex();
63 |
64 | void destroy(JNIEnv *env);
65 |
66 | void createClassLoader(JNIEnv *env);
67 |
68 | jclass findClass(JNIEnv *env, const char *name);
69 |
70 | void setPre26Paths(const char *dexPath, const char *optDir);
71 |
72 | bool valid();
73 |
74 | private:
75 |
76 | void createInMemoryDexClassLoader(JNIEnv *env);
77 |
78 | void createDexClassLoader(JNIEnv *env, const char *path, const char *optDir);
79 |
80 | void copyDexToFile(const char *dexPath);
81 |
82 | };
83 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/memory.h:
--------------------------------------------------------------------------------
1 | #ifndef MEMORY_H
2 | #define MEMORY_H
3 |
4 | int CreateSharedMem(const char *name, size_t size);
5 | int SetSharedMemProt(int fd, int prot);
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/misc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | #ifndef _MISC_H
21 | #define _MISC_H
22 |
23 | #include
24 | #include
25 |
26 | int mkdirs(const char *pathname, mode_t mode);
27 | int ensure_dir(const char *path, mode_t mode);
28 | int copyfileat(int src_path_fd, const char *src_path, int dst_path_fd, const char *dst_path);
29 | int copyfile(const char *src_path, const char *dst_path);
30 | ssize_t read_eintr(int fd, void *out, size_t len);
31 | int read_full(int fd, void *buf, size_t count);
32 | int write_full(int fd, const void *buf, size_t count);
33 |
34 | using foreach_proc_function = bool(pid_t);
35 | void foreach_proc(foreach_proc_function *func);
36 |
37 | #endif // _MISC_H
38 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/plt.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | #define PLT_CHECK_PLT_APP ((unsigned short) 0x1u)
12 | #define PLT_CHECK_PLT_ALL ((unsigned short) 0x2u)
13 | #define PLT_CHECK_NAME ((unsigned short) 0x4u)
14 | #define PLT_CHECK_SYM_ONE ((unsigned short) 0x8u)
15 |
16 | typedef struct Symbol {
17 | unsigned short check;
18 | unsigned short size;
19 | size_t total;
20 | ElfW(Addr) *symbol_plt;
21 | ElfW(Addr) *symbol_sym;
22 | const char *symbol_name;
23 | char **names;
24 | } Symbol;
25 |
26 | int dl_iterate_phdr_symbol(Symbol *symbol);
27 |
28 | void *plt_dlsym(const char *name, size_t *total);
29 |
30 | #ifdef __cplusplus
31 | }
32 | #endif
33 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/selinux.h:
--------------------------------------------------------------------------------
1 | #ifndef _SELINUX_H
2 | #define _SELINUX_H
3 |
4 | bool init_selinux();
5 | void freecon(char *con);
6 | int getfilecon_raw(const char *path, char **con);
7 | int setfilecon_raw(const char *path, const char *context);
8 | int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata);
9 |
10 | #endif // _SELINUX_H
11 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/include/socket.h:
--------------------------------------------------------------------------------
1 | #ifndef SOCKET_H
2 | #define SOCKET_H
3 |
4 | socklen_t setup_sockaddr(struct sockaddr_un *sun, const char *name);
5 | int set_socket_timeout(int fd, long sec);
6 | int send_fd(int sockfd, int fd);
7 | int recv_fd(int sockfd);
8 | int read_int(int fd);
9 | void write_int(int fd, int val);
10 | #endif // SOCKET_H
11 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/memory.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | /*
8 | * ashmem_create_region - creates a new ashmem region and returns the file
9 | * descriptor, or <0 on error
10 | *
11 | * `name' is an optional label to give the region (visible in /proc/pid/maps)
12 | * `size' is the size of the region, in page-aligned bytes
13 | */
14 | using ashmem_create_region_t = int(const char *name, size_t size);
15 |
16 | static ashmem_create_region_t *ashmem_create_region = nullptr;
17 |
18 | using ashmem_set_prot_region_t = int(int fd, int prot);
19 |
20 | static ashmem_set_prot_region_t *ashmem_set_prot_region = nullptr;
21 |
22 | static void Init() {
23 | static bool init = false;
24 | if (init) return;
25 |
26 | #ifdef __LP64__
27 | auto handle = dlopen("/system/lib64/libcutils.so", 0);
28 | #else
29 | auto handle = dlopen("/system/lib/libcutils.so", 0);
30 | #endif
31 |
32 | if (handle) {
33 | ashmem_create_region = (ashmem_create_region_t *) dlsym(handle, "ashmem_create_region");
34 | ashmem_set_prot_region = (ashmem_set_prot_region_t *) dlsym(handle, "ashmem_set_prot_region");
35 | }
36 |
37 | init = true;
38 | }
39 |
40 | int CreateSharedMem(const char *name, size_t size) {
41 | Init();
42 | if (!ashmem_create_region) return -1;
43 |
44 | int ret;
45 | if ((ret = ashmem_create_region(name, size)) >= 0) {
46 | return ret;
47 | }
48 | PLOGE("ashmem_create_region %s", name);
49 | return ret;
50 | }
51 |
52 | int SetSharedMemProt(int fd, int prot) {
53 | Init();
54 | if (!ashmem_create_region) return 0;
55 |
56 | int ret;
57 | if ((ret = ashmem_set_prot_region(fd, prot)) == -1) {
58 | PLOGE("ashmem_set_prot_region");
59 | }
60 | return ret;
61 | }
62 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/selinux.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #define INITCONTEXTLEN 255
12 |
13 | void freecon(char *con) {
14 | free(con);
15 | }
16 |
17 | int getfilecon_raw(const char *path, char **context) {
18 | char *buf;
19 | ssize_t size;
20 | ssize_t ret;
21 |
22 | size = INITCONTEXTLEN + 1;
23 | buf = static_cast(malloc(size));
24 | if (!buf)
25 | return -1;
26 | memset(buf, 0, size);
27 |
28 | ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
29 | if (ret < 0 && errno == ERANGE) {
30 | char *newbuf;
31 |
32 | size = getxattr(path, XATTR_NAME_SELINUX, nullptr, 0);
33 | if (size < 0)
34 | goto out;
35 |
36 | size++;
37 | newbuf = static_cast(realloc(buf, size));
38 | if (!newbuf)
39 | goto out;
40 |
41 | buf = newbuf;
42 | memset(buf, 0, size);
43 | ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
44 | }
45 | out:
46 | if (ret == 0) {
47 | /* Re-map empty attribute values to errors. */
48 | errno = ENOTSUP;
49 | ret = -1;
50 | }
51 | if (ret < 0)
52 | free(buf);
53 | else
54 | *context = buf;
55 | return ret;
56 | }
57 |
58 | int setfilecon_raw(const char *path, const char *context) {
59 | int rc = setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0);
60 | if (rc < 0 && errno == ENOTSUP) {
61 | char *ccontext = nullptr;
62 | int err = errno;
63 | if ((getfilecon_raw(path, &ccontext) >= 0) &&
64 | (strcmp(context, ccontext) == 0)) {
65 | rc = 0;
66 | } else {
67 | errno = err;
68 | }
69 | freecon(ccontext);
70 | }
71 | return rc;
72 | }
73 |
74 | using selinux_check_access_t = int(const char *, const char *, const char *, const char *, void *);
75 | selinux_check_access_t *selinux_check_access_func = nullptr;
76 |
77 | int selinux_check_access(const char *scon, const char *tcon, const char *tclass, const char *perm, void *auditdata) {
78 | if (selinux_check_access_func) {
79 | return selinux_check_access_func(scon, tcon, tclass, perm, auditdata);
80 | }
81 | return 0;
82 | }
83 |
84 | #ifdef __LP64__
85 | static constexpr const char *libselinux = "/system/lib64/libselinux.so";
86 | #else
87 | static constexpr const char *libselinux = "/system/lib/libselinux.so";
88 | #endif
89 |
90 | bool init_selinux() {
91 | if (access(libselinux, F_OK) != 0) {
92 | return false;
93 | }
94 |
95 | void *handle = dlopen(libselinux, RTLD_LAZY | RTLD_LOCAL);
96 | if (!handle) return false;
97 |
98 | selinux_check_access_func = (selinux_check_access_t *) dlsym(handle, "selinux_check_access");
99 | return selinux_check_access_func != nullptr;
100 | }
101 |
--------------------------------------------------------------------------------
/module/src/main/cpp/util/socket.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | static size_t socket_len(sockaddr_un *sun) {
14 | if (sun->sun_path[0])
15 | return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
16 | else
17 | return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
18 | }
19 |
20 | socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
21 | memset(sun, 0, sizeof(*sun));
22 | sun->sun_family = AF_UNIX;
23 | strcpy(sun->sun_path + 1, name);
24 | return socket_len(sun);
25 | }
26 |
27 | int set_socket_timeout(int fd, long sec) {
28 | struct timeval timeout{};
29 | timeout.tv_sec = sec;
30 | timeout.tv_usec = 0;
31 |
32 | if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)) < 0) {
33 | return -1;
34 | }
35 |
36 | if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)) < 0) {
37 | return -1;
38 | }
39 | return 0;
40 | }
41 |
42 | ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
43 | int sent = sendmsg(sockfd, msg, flags);
44 | if (sent < 0) {
45 | PLOGE("sendmsg");
46 | }
47 | return sent;
48 | }
49 |
50 | ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
51 | int rec = recvmsg(sockfd, msg, flags);
52 | if (rec < 0) {
53 | PLOGE("recvmsg");
54 | }
55 | return rec;
56 | }
57 |
58 | int send_fds(int sockfd, void *cmsgbuf, size_t bufsz, const int *fds, int cnt) {
59 | iovec iov = {
60 | .iov_base = &cnt,
61 | .iov_len = sizeof(cnt),
62 | };
63 | msghdr msg = {
64 | .msg_iov = &iov,
65 | .msg_iovlen = 1,
66 | };
67 |
68 | if (cnt) {
69 | msg.msg_control = cmsgbuf;
70 | msg.msg_controllen = bufsz;
71 | cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
72 | cmsg->cmsg_len = CMSG_LEN(sizeof(int) * cnt);
73 | cmsg->cmsg_level = SOL_SOCKET;
74 | cmsg->cmsg_type = SCM_RIGHTS;
75 |
76 | memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * cnt);
77 | }
78 |
79 | return xsendmsg(sockfd, &msg, 0);
80 | }
81 |
82 | int send_fd(int sockfd, int fd) {
83 | if (fd < 0) {
84 | return send_fds(sockfd, nullptr, 0, nullptr, 0);
85 | }
86 | char cmsgbuf[CMSG_SPACE(sizeof(int))];
87 | return send_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), &fd, 1);
88 | }
89 |
90 | void *recv_fds(int sockfd, char *cmsgbuf, size_t bufsz, int cnt) {
91 | iovec iov = {
92 | .iov_base = &cnt,
93 | .iov_len = sizeof(cnt),
94 | };
95 | msghdr msg = {
96 | .msg_iov = &iov,
97 | .msg_iovlen = 1,
98 | .msg_control = cmsgbuf,
99 | .msg_controllen = bufsz
100 | };
101 |
102 | xrecvmsg(sockfd, &msg, MSG_WAITALL);
103 | cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
104 |
105 | if (msg.msg_controllen != bufsz ||
106 | cmsg == nullptr ||
107 | cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
108 | cmsg->cmsg_level != SOL_SOCKET ||
109 | cmsg->cmsg_type != SCM_RIGHTS) {
110 | return nullptr;
111 | }
112 |
113 | return CMSG_DATA(cmsg);
114 | }
115 |
116 | int recv_fd(int sockfd) {
117 | char cmsgbuf[CMSG_SPACE(sizeof(int))];
118 |
119 | void *data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
120 | if (data == nullptr)
121 | return -1;
122 |
123 | int result;
124 | memcpy(&result, data, sizeof(int));
125 | return result;
126 | }
127 |
128 | int read_int(int fd) {
129 | int val;
130 | if (read_full(fd, &val, sizeof(val)) != 0)
131 | return -1;
132 | return val;
133 | }
134 |
135 | void write_int(int fd, int val) {
136 | if (fd < 0) return;
137 | write_full(fd, &val, sizeof(val));
138 | }
139 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/binder/HookedBinderProxy.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.binder;
2 |
3 | import android.os.IBinder;
4 |
5 | public interface HookedBinderProxy extends IBinder {
6 |
7 | T getOriginal();
8 |
9 | boolean isTransactionReplaced(int code);
10 | }
11 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/binder/IBinderWrapper.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.binder;
2 |
3 | import android.os.IBinder;
4 | import android.os.IInterface;
5 | import android.os.Parcel;
6 | import android.os.RemoteException;
7 |
8 | import androidx.annotation.NonNull;
9 |
10 | import java.io.FileDescriptor;
11 |
12 | public class IBinderWrapper implements IBinder {
13 |
14 | private final IBinder mOriginal;
15 |
16 | public IBinderWrapper(IBinder original) {
17 | this.mOriginal = original;
18 | }
19 |
20 | public IBinder getOriginal() {
21 | return mOriginal;
22 | }
23 |
24 | @Override
25 | public boolean transact(int code, @NonNull Parcel data, Parcel reply, int flags) throws RemoteException {
26 | return mOriginal.transact(code, data, reply, flags);
27 | }
28 |
29 | @Override
30 | public String getInterfaceDescriptor() throws RemoteException {
31 | return mOriginal.getInterfaceDescriptor();
32 | }
33 |
34 | @Override
35 | public boolean pingBinder() {
36 | return mOriginal.pingBinder();
37 | }
38 |
39 | @Override
40 | public boolean isBinderAlive() {
41 | return mOriginal.isBinderAlive();
42 | }
43 |
44 | @Override
45 | public IInterface queryLocalInterface(@NonNull String descriptor) {
46 | return mOriginal.queryLocalInterface(descriptor);
47 | }
48 |
49 | @Override
50 | public void dump(@NonNull FileDescriptor fd, String[] args) throws RemoteException {
51 | mOriginal.dump(fd, args);
52 | }
53 |
54 | @Override
55 | public void dumpAsync(@NonNull FileDescriptor fd, String[] args) throws RemoteException {
56 | mOriginal.dumpAsync(fd, args);
57 | }
58 |
59 | @Override
60 | public void linkToDeath(@NonNull DeathRecipient recipient, int flags) throws RemoteException {
61 | mOriginal.linkToDeath(recipient, flags);
62 | }
63 |
64 | @Override
65 | public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
66 | return mOriginal.unlinkToDeath(recipient, flags);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/binder/Transaction.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.binder;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.METHOD)
10 | public @interface Transaction {
11 | }
12 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/installer/Installer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.installer;
21 |
22 | import android.content.pm.ApplicationInfo;
23 |
24 | import java.io.File;
25 | import java.io.FileWriter;
26 | import java.io.IOException;
27 | import java.util.Locale;
28 |
29 | import rikka.hidden.compat.PackageManagerApis;
30 |
31 | public class Installer {
32 |
33 | private static void saveApplicationInfoToFile(String path, String packageName, String name) throws IOException {
34 | ApplicationInfo ai = PackageManagerApis.getApplicationInfoNoThrow(packageName, 0, 0);
35 | if (ai == null) {
36 | System.out.println("! Can't fetch application info for package " + packageName);
37 | return;
38 | }
39 | int uid = ai.uid;
40 | String processName = ai.processName != null ? ai.processName : packageName;
41 | System.out.println("- " + name + ": uid=" + uid + ", processName=" + processName);
42 |
43 | File file = new File(path, packageName);
44 | if (!file.exists() && !file.createNewFile()) {
45 | System.out.println("! Can't create " + file);
46 | return;
47 | }
48 |
49 | FileWriter writer = new FileWriter(file);
50 | writer.write(String.format(Locale.ENGLISH, "%d\n%s", uid, processName));
51 | writer.flush();
52 | writer.close();
53 | }
54 |
55 | public static void main(String[] args) throws IOException {
56 | System.out.println("- AppProcess: main");
57 | saveApplicationInfoToFile(args[0], "com.android.systemui", "SystemUI");
58 | saveApplicationInfoToFile(args[0], "com.android.settings", "Settings");
59 | System.out.println("- AppProcess: exit");
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/installer/Uninstaller.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2022 Sui Contributors
18 | */
19 |
20 | package rikka.sui.installer;
21 |
22 | import android.annotation.TargetApi;
23 | import android.content.pm.IPackageManager;
24 | import android.content.pm.IShortcutService;
25 | import android.content.pm.IShortcutServiceV31;
26 | import android.os.Build;
27 | import android.os.Handler;
28 | import android.os.IUserManager;
29 | import android.os.Looper;
30 | import android.os.RemoteException;
31 | import android.os.ServiceManager;
32 | import android.system.ErrnoException;
33 | import android.system.Os;
34 | import android.util.Log;
35 |
36 | import java.io.IOException;
37 | import java.util.ArrayList;
38 | import java.util.List;
39 |
40 | import dev.rikka.tools.refine.Refine;
41 | import rikka.sui.shortcut.ShortcutConstants;
42 |
43 | @TargetApi(Build.VERSION_CODES.O)
44 | public class Uninstaller {
45 |
46 | private static final String TAG = "SuiUninstaller";
47 |
48 | private static void removeShortcuts() throws InterruptedException, RemoteException {
49 | IShortcutService shortcutService = null;
50 | IUserManager userManager = null;
51 |
52 | while (true) {
53 | //noinspection ConstantConditions
54 | if (shortcutService == null) {
55 | shortcutService = IShortcutService.Stub.asInterface(ServiceManager.getService("shortcut"));
56 | }
57 | if (userManager == null) {
58 | userManager = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
59 | }
60 | if (shortcutService != null
61 | && userManager != null
62 | && userManager.isUserUnlocked(0)) {
63 | break;
64 | }
65 |
66 | //noinspection BusyWait
67 | Thread.sleep(1000);
68 | Log.v(TAG, "wait 1s");
69 | }
70 |
71 | List list = new ArrayList<>();
72 | list.add(ShortcutConstants.SHORTCUT_ID);
73 |
74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
75 | Refine.unsafeCast(shortcutService).removeDynamicShortcuts(
76 | "com.android.settings", list, 0);
77 | } else {
78 | shortcutService.removeDynamicShortcuts(
79 | "com.android.settings", list, 0);
80 | }
81 | }
82 |
83 | public static void main(String[] args) throws IOException, ErrnoException {
84 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
85 | return;
86 | }
87 |
88 | Log.i(TAG, "main");
89 |
90 | //noinspection deprecation
91 | Os.setuid(1000);
92 |
93 | if (Looper.getMainLooper() == null) {
94 | Looper.prepareMainLooper();
95 | }
96 |
97 | new Handler(Looper.getMainLooper()).post(() -> {
98 | try {
99 | removeShortcuts();
100 | } catch (Throwable e) {
101 | Log.e(TAG, Log.getStackTraceString(e));
102 | }
103 |
104 | Log.i(TAG, "exit");
105 | System.exit(0);
106 | });
107 |
108 | Looper.loop();
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/manager/ManagerConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.manager;
21 |
22 | import rikka.sui.util.Logger;
23 |
24 | public class ManagerConstants {
25 |
26 | public static final Logger LOGGER = new Logger("SuiManager");
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/manager/WorkerHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.manager;
21 |
22 | import android.os.Handler;
23 | import android.os.HandlerThread;
24 |
25 | public class WorkerHandler {
26 |
27 | private static final HandlerThread HANDLER_THREAD;
28 | private static final Handler HANDLER;
29 |
30 | static {
31 | HANDLER_THREAD = new HandlerThread("SuiManager");
32 | HANDLER_THREAD.start();
33 | HANDLER = new Handler(HANDLER_THREAD.getLooper());
34 | }
35 |
36 | public static Handler get() {
37 | return HANDLER;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/model/AppInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.model;
21 |
22 | import android.content.pm.PackageInfo;
23 | import android.os.Parcel;
24 | import android.os.Parcelable;
25 | import android.util.Log;
26 |
27 | public class AppInfo implements Parcelable {
28 |
29 | public PackageInfo packageInfo;
30 | public int flags;
31 | public CharSequence label = null;
32 |
33 | public AppInfo() {
34 | }
35 |
36 | protected AppInfo(Parcel in) {
37 | packageInfo = in.readParcelable(PackageInfo.class.getClassLoader());
38 | flags = in.readInt();
39 | }
40 |
41 | public static final Creator CREATOR = new Creator() {
42 | @Override
43 | public AppInfo createFromParcel(Parcel in) {
44 | return new AppInfo(in);
45 | }
46 |
47 | @Override
48 | public AppInfo[] newArray(int size) {
49 | return new AppInfo[size];
50 | }
51 | };
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeParcelable(packageInfo, flags);
61 | dest.writeInt(this.flags);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/ServerConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import rikka.sui.util.Logger;
23 |
24 | public class ServerConstants {
25 |
26 | public static final Logger LOGGER = new Logger("SuiServer");
27 |
28 | public static final int BINDER_TRANSACTION_getApplications = 10001;
29 | public static final int BINDER_TRANSACTION_showManagement = 10002;
30 | public static final int BINDER_TRANSACTION_openApk = 10003;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/Starter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import static rikka.sui.server.ServerConstants.LOGGER;
23 |
24 | import android.content.Context;
25 | import android.ddm.DdmHandleAppName;
26 | import android.os.ServiceManager;
27 |
28 | import java.util.Objects;
29 |
30 | public class Starter {
31 |
32 | private static void waitSystemService(String name) {
33 | while (ServiceManager.getService(name) == null) {
34 | try {
35 | LOGGER.i("service " + name + " is not started, wait 1s.");
36 | Thread.sleep(1000);
37 | } catch (InterruptedException e) {
38 | LOGGER.w(e.getMessage(), e);
39 | }
40 | }
41 | }
42 |
43 | public static void main(String[] args) {
44 | String filesPath = null;
45 |
46 | for (String arg : args) {
47 | if (arg.equals("--debug")) {
48 | DdmHandleAppName.setAppName("sui", 0);
49 | } else if (arg.startsWith("--files-path=")) {
50 | filesPath = arg.substring("--files-path=".length());
51 | SuiUserServiceManager.setStartDex(filesPath + "/sui.dex");
52 | }
53 | }
54 |
55 | Objects.requireNonNull(filesPath, "--files-path not set");
56 |
57 | waitSystemService("package");
58 | waitSystemService("activity");
59 | waitSystemService(Context.USER_SERVICE);
60 | waitSystemService(Context.APP_OPS_SERVICE);
61 |
62 | SuiService.main(filesPath);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/SuiClientManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import rikka.shizuku.server.ClientManager;
23 |
24 | public class SuiClientManager extends ClientManager {
25 |
26 | public SuiClientManager(SuiConfigManager configManager) {
27 | super(configManager);
28 | }
29 | }
30 |
31 |
32 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/SuiConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import androidx.annotation.NonNull;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | import rikka.shizuku.server.ConfigPackageEntry;
28 |
29 | public class SuiConfig {
30 |
31 | public static final int LATEST_VERSION = 1;
32 |
33 | public static final int FLAG_ALLOWED = 1 << 1;
34 | public static final int FLAG_DENIED = 1 << 2;
35 | public static final int FLAG_HIDDEN = 1 << 3;
36 | public static final int MASK_PERMISSION = FLAG_ALLOWED | FLAG_DENIED | FLAG_HIDDEN;
37 |
38 | public int version = LATEST_VERSION;
39 |
40 | public List packages = new ArrayList<>();
41 |
42 | public static class PackageEntry extends ConfigPackageEntry {
43 |
44 | public final int uid;
45 |
46 | public int flags;
47 |
48 | public PackageEntry(int uid, int flags) {
49 | this.uid = uid;
50 | this.flags = flags;
51 | }
52 |
53 | public boolean isAllowed() {
54 | return (flags & FLAG_ALLOWED) != 0;
55 | }
56 |
57 | public boolean isDenied() {
58 | return (flags & FLAG_DENIED) != 0;
59 | }
60 |
61 | public boolean isHidden() {
62 | return (flags & FLAG_HIDDEN) != 0;
63 | }
64 | }
65 |
66 | public SuiConfig() {
67 | }
68 |
69 | public SuiConfig(@NonNull List packages) {
70 | this.version = LATEST_VERSION;
71 | this.packages = packages;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/SuiConfigManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import androidx.annotation.Nullable;
23 |
24 | import java.util.List;
25 |
26 | import rikka.shizuku.server.ConfigManager;
27 |
28 | public class SuiConfigManager extends ConfigManager {
29 |
30 | public static SuiConfig load() {
31 | SuiConfig config = SuiDatabase.readConfig();
32 | if (config == null) {
33 | LOGGER.i("failed to read database, starting empty");
34 | return new SuiConfig();
35 | }
36 | return config;
37 | }
38 |
39 | private static SuiConfigManager instance;
40 |
41 | public static SuiConfigManager getInstance() {
42 | if (instance == null) {
43 | instance = new SuiConfigManager();
44 | }
45 | return instance;
46 | }
47 |
48 |
49 | private final SuiConfig config;
50 |
51 | public SuiConfigManager() {
52 | this.config = load();
53 | }
54 |
55 | private SuiConfig.PackageEntry findLocked(int uid) {
56 | for (SuiConfig.PackageEntry entry : config.packages) {
57 | if (uid == entry.uid) {
58 | return entry;
59 | }
60 | }
61 | return null;
62 | }
63 |
64 | @Nullable
65 | public SuiConfig.PackageEntry find(int uid) {
66 | synchronized (this) {
67 | return findLocked(uid);
68 | }
69 | }
70 |
71 | @Override
72 | public void update(int uid, List packages, int mask, int values) {
73 | update(uid, mask, values);
74 | }
75 |
76 | public void update(int uid, int mask, int values) {
77 | synchronized (this) {
78 | SuiConfig.PackageEntry entry = findLocked(uid);
79 | if (entry == null) {
80 | entry = new SuiConfig.PackageEntry(uid, mask & values);
81 | config.packages.add(entry);
82 | } else {
83 | int newValue = (entry.flags & ~mask) | (mask & values);
84 | if (newValue == entry.flags) {
85 | return;
86 | }
87 | entry.flags = newValue;
88 | }
89 | SuiDatabase.updateUid(uid, entry.flags);
90 | }
91 | }
92 |
93 | @Override
94 | public void remove(int uid) {
95 | synchronized (this) {
96 | SuiConfig.PackageEntry entry = findLocked(uid);
97 | if (entry == null) {
98 | return;
99 | }
100 | config.packages.remove(entry);
101 | SuiDatabase.removeUid(uid);
102 | }
103 | }
104 |
105 | public boolean isHidden(int uid) {
106 | SuiConfig.PackageEntry entry = find(uid);
107 | if (entry == null) {
108 | return false;
109 | }
110 | return (entry.flags & SuiConfig.FLAG_HIDDEN) != 0;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/SuiDatabase.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.server;
2 |
3 | import android.content.ContentValues;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 |
7 | import androidx.annotation.Nullable;
8 |
9 | import java.io.File;
10 |
11 | import rikka.sui.server.SuiConfig.PackageEntry;
12 | import rikka.sui.util.SQLiteDataBaseRemoteCompat;
13 |
14 | public class SuiDatabase {
15 |
16 | private SuiDatabase() {
17 | }
18 |
19 | static {
20 | DATABASE_PATH = (new File("/data/adb/sui/sui.db")).getPath();
21 | }
22 |
23 | private static final String DATABASE_PATH;
24 | private static final String UID_CONFIG_TABLE = "uid_configs";
25 | private static SQLiteDatabase databaseInternal;
26 |
27 | private static SQLiteDatabase createDatabase(boolean allowRetry) {
28 | SQLiteDatabase database;
29 | try {
30 | database = SQLiteDataBaseRemoteCompat.openDatabase(DATABASE_PATH, null);
31 | database.execSQL("CREATE TABLE IF NOT EXISTS uid_configs(uid INTEGER PRIMARY KEY, flags INTEGER);");
32 | } catch (Throwable e) {
33 | ServerConstants.LOGGER.e(e, "create database");
34 | if (allowRetry && (new File(DATABASE_PATH)).delete()) {
35 | ServerConstants.LOGGER.i("delete database and retry");
36 | database = createDatabase(false);
37 | } else {
38 | database = null;
39 | }
40 | }
41 |
42 | return database;
43 | }
44 |
45 | private static SQLiteDatabase getDatabase() {
46 | if (databaseInternal == null) {
47 | databaseInternal = createDatabase(true);
48 | }
49 | return databaseInternal;
50 | }
51 |
52 | @Nullable
53 | public static SuiConfig readConfig() {
54 | SQLiteDatabase database = getDatabase();
55 | if (database == null) {
56 | return null;
57 | }
58 |
59 | try (Cursor cursor = database.query(UID_CONFIG_TABLE, (String[]) null, (String) null, (String[]) null, (String) null, (String) null, (String) null, (String) null)) {
60 | if (cursor == null) {
61 | return null;
62 | }
63 | SuiConfig res = new SuiConfig();
64 | int cursorIndexOfUid = cursor.getColumnIndexOrThrow("uid");
65 | int cursorIndexOfFlags = cursor.getColumnIndexOrThrow("flags");
66 | if (cursor.moveToFirst()) {
67 | do {
68 | res.packages.add(new PackageEntry(cursor.getInt(cursorIndexOfUid), cursor.getInt(cursorIndexOfFlags)));
69 | } while (cursor.moveToNext());
70 | }
71 | return res;
72 | }
73 | }
74 |
75 | public static void updateUid(int uid, int flags) {
76 | SQLiteDatabase database = getDatabase();
77 | if (database == null) {
78 | return;
79 | }
80 |
81 | ContentValues values = new ContentValues();
82 | values.put("uid", uid);
83 | values.put("flags", flags);
84 | String selection = "uid=?";
85 | String[] selectionArgs = new String[]{String.valueOf(uid)};
86 | if (database.update(UID_CONFIG_TABLE, values, selection, selectionArgs) <= 0) {
87 | database.insertWithOnConflict(UID_CONFIG_TABLE, (String) null, values, SQLiteDatabase.CONFLICT_IGNORE);
88 | }
89 | }
90 |
91 | public static void removeUid(int uid) {
92 | SQLiteDatabase database = getDatabase();
93 | if (database == null) {
94 | return;
95 | }
96 |
97 | String selection = "uid=?";
98 | String[] selectionArgs = new String[]{String.valueOf(uid)};
99 | database.delete(UID_CONFIG_TABLE, selection, selectionArgs);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/SuiUserServiceManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | import android.os.Build;
23 |
24 | import java.io.File;
25 | import java.util.Locale;
26 |
27 | import rikka.shizuku.server.UserServiceManager;
28 |
29 | public class SuiUserServiceManager extends UserServiceManager {
30 |
31 | public static final String USER_SERVICE_CMD_DEBUG;
32 |
33 | private static final String USER_SERVICE_CMD_FORMAT = "(CLASSPATH='%s' %s%s /system/bin " +
34 | "--nice-name='%s' %s " +
35 | "--token='%s' --package='%s' --class='%s' --uid=%d%s)&";
36 |
37 | static {
38 | int sdk = Build.VERSION.SDK_INT;
39 | if (sdk >= 30) {
40 | USER_SERVICE_CMD_DEBUG = "-Xcompiler-option" + " --debuggable" +
41 | " -XjdwpProvider:adbconnection" +
42 | " -XjdwpOptions:suspend=n,server=y";
43 | } else if (sdk >= 28) {
44 | USER_SERVICE_CMD_DEBUG = "-Xcompiler-option" + " --debuggable" +
45 | " -XjdwpProvider:internal" +
46 | " -XjdwpOptions:transport=dt_android_adb,suspend=n,server=y";
47 | } else {
48 | USER_SERVICE_CMD_DEBUG = "-Xcompiler-option" + " --debuggable" +
49 | " -agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
50 | }
51 | }
52 |
53 | private static String dexPath;
54 |
55 | public static void setStartDex(String path) {
56 | SuiUserServiceManager.dexPath = path;
57 | }
58 |
59 | @Override
60 | public String getUserServiceStartCmd(rikka.shizuku.server.UserServiceRecord record, String key, String token, String packageName, String classname, String processNameSuffix, int callingUid, boolean use32Bits, boolean debug) {
61 | String appProcess = "/system/bin/app_process";
62 | if (use32Bits && new File("/system/bin/app_process32").exists()) {
63 | appProcess = "/system/bin/app_process32";
64 | }
65 | String processName = String.format("%s:%s", packageName, processNameSuffix);
66 | return String.format(Locale.ENGLISH, USER_SERVICE_CMD_FORMAT, dexPath, appProcess,
67 | debug ? (" " + SuiUserServiceManager.USER_SERVICE_CMD_DEBUG) : "",
68 | processName, "rikka.sui.server.userservice.Starter",
69 | token, packageName, classname, callingUid, debug ? (" " + "--debug-name=" + processName) : "");
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/server/userservice/Starter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server.userservice;
21 |
22 | import static rikka.shizuku.ShizukuApiConstants.USER_SERVICE_ARG_TOKEN;
23 |
24 | import android.os.Bundle;
25 | import android.os.IBinder;
26 | import android.os.Looper;
27 | import android.os.Parcel;
28 | import android.os.ServiceManager;
29 | import android.util.Log;
30 | import android.util.Pair;
31 |
32 | import moe.shizuku.server.IShizukuService;
33 | import rikka.shizuku.server.UserService;
34 |
35 | public class Starter {
36 |
37 | private static final String TAG = "SuiUserServiceStarter";
38 | private static final int BRIDGE_TRANSACTION_CODE = ('_' << 24) | ('S' << 16) | ('U' << 8) | 'I';
39 | private static final String BRIDGE_SERVICE_DESCRIPTOR = "android.app.IActivityManager";
40 | private static final String BRIDGE_SERVICE_NAME = "activity";
41 | private static final int BRIDGE_ACTION_GET_BINDER = 2;
42 |
43 | public static void main(String[] args) {
44 | if (Looper.getMainLooper() == null) {
45 | Looper.prepareMainLooper();
46 | }
47 |
48 | IBinder service;
49 | String token;
50 |
51 | UserService.setTag(TAG);
52 | Pair result = UserService.create(args);
53 |
54 | if (result == null) {
55 | System.exit(1);
56 | return;
57 | }
58 |
59 | service = result.first;
60 | token = result.second;
61 |
62 | if (!sendBinder(service, token)) {
63 | System.exit(1);
64 | }
65 |
66 | Looper.loop();
67 | System.exit(0);
68 |
69 | Log.i(TAG, "service exited");
70 | }
71 |
72 | private static IBinder requestBinderFromBridge() {
73 | IBinder binder = ServiceManager.getService(BRIDGE_SERVICE_NAME);
74 | if (binder == null) return null;
75 |
76 | Parcel data = Parcel.obtain();
77 | Parcel reply = Parcel.obtain();
78 | try {
79 | data.writeInterfaceToken(BRIDGE_SERVICE_DESCRIPTOR);
80 | data.writeInt(BRIDGE_ACTION_GET_BINDER);
81 | binder.transact(BRIDGE_TRANSACTION_CODE, data, reply, 0);
82 | reply.readException();
83 | IBinder received = reply.readStrongBinder();
84 | if (received != null) {
85 | return received;
86 | }
87 | } catch (Throwable e) {
88 | e.printStackTrace();
89 | } finally {
90 | data.recycle();
91 | reply.recycle();
92 | }
93 | return null;
94 | }
95 |
96 | private static boolean sendBinder(IBinder binder, String token) {
97 | IShizukuService shizukuService = IShizukuService.Stub.asInterface(requestBinderFromBridge());
98 | if (shizukuService == null) {
99 | return false;
100 | }
101 |
102 | Bundle data = new Bundle();
103 | data.putString(USER_SERVICE_ARG_TOKEN, token);
104 | try {
105 | shizukuService.attachUserService(binder, data);
106 | } catch (Throwable e) {
107 | Log.w(TAG, Log.getStackTraceString(e));
108 | return false;
109 | }
110 | return true;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/settings/HandlerUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.settings;
21 |
22 | import android.annotation.SuppressLint;
23 | import android.os.Handler;
24 |
25 | import androidx.annotation.NonNull;
26 |
27 | import java.lang.reflect.Field;
28 |
29 | @SuppressWarnings("JavaReflectionMemberAccess")
30 | @SuppressLint("DiscouragedPrivateApi")
31 | public class HandlerUtil {
32 |
33 | private static Field callbackField;
34 |
35 | public static void init() throws ReflectiveOperationException {
36 | callbackField = Handler.class.getDeclaredField("mCallback");
37 | callbackField.setAccessible(true);
38 | }
39 |
40 | public static Handler.Callback getCallback(@NonNull Handler handler) {
41 | try {
42 | return (Handler.Callback) callbackField.get(handler);
43 | } catch (IllegalAccessException e) {
44 | return null;
45 | }
46 | }
47 |
48 | public static void setCallback(@NonNull Handler handler, Handler.Callback callback){
49 | try {
50 | callbackField.set(handler, callback);
51 | } catch (IllegalAccessException ignored) {
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/settings/SettingsConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.settings;
21 |
22 | import rikka.sui.util.Logger;
23 |
24 | public class SettingsConstants {
25 |
26 | public static final Logger LOGGER = new Logger("SuiSettings");
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/settings/WorkerHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.settings;
21 |
22 | import android.os.Handler;
23 | import android.os.HandlerThread;
24 |
25 | public class WorkerHandler {
26 |
27 | private static final HandlerThread HANDLER_THREAD;
28 | private static final Handler HANDLER;
29 |
30 | static {
31 | HANDLER_THREAD = new HandlerThread("SuiSettings");
32 | HANDLER_THREAD.start();
33 | HANDLER = new Handler(HANDLER_THREAD.getLooper());
34 | }
35 |
36 | public static Handler get() {
37 | return HANDLER;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/shell/Shell.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.shell;
2 |
3 | import android.content.pm.PackageManager;
4 | import android.os.Handler;
5 | import android.os.IBinder;
6 | import android.os.Looper;
7 | import android.system.Os;
8 | import android.text.TextUtils;
9 |
10 | import java.io.File;
11 |
12 | import rikka.rish.Rish;
13 | import rikka.rish.RishConfig;
14 | import rikka.shizuku.Shizuku;
15 | import rikka.shizuku.ShizukuApiConstants;
16 | import rikka.sui.Sui;
17 |
18 | public class Shell extends Rish {
19 |
20 | @Override
21 | public void requestPermission(Runnable onGrantedRunnable) {
22 | if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
23 | onGrantedRunnable.run();
24 | } else if (Shizuku.shouldShowRequestPermissionRationale()) {
25 | System.err.println("Permission denied");
26 | System.err.flush();
27 | System.exit(1);
28 | } else {
29 | Shizuku.addRequestPermissionResultListener(new Shizuku.OnRequestPermissionResultListener() {
30 | @Override
31 | public void onRequestPermissionResult(int requestCode, int grantResult) {
32 | Shizuku.removeRequestPermissionResultListener(this);
33 |
34 | if (grantResult == PackageManager.PERMISSION_GRANTED) {
35 | onGrantedRunnable.run();
36 | } else {
37 | System.err.println("Permission denied");
38 | System.err.flush();
39 | System.exit(1);
40 | }
41 | }
42 | });
43 | Shizuku.requestPermission(0);
44 | }
45 | }
46 |
47 | public static void main(String[] args) {
48 | String packageName;
49 | if (Os.getuid() == 2000) {
50 | packageName = "com.android.shell";
51 | } else {
52 | packageName = System.getenv("RISH_APPLICATION_ID");
53 | if (TextUtils.isEmpty(packageName) || "PKG".equals(packageName)) {
54 | System.err.println("RISH_APPLICATION_ID is not set, set this environment variable to the id of current application (package name)");
55 | System.err.flush();
56 | System.exit(1);
57 | }
58 | }
59 |
60 | String libPath = System.getProperty("sui.library.path");
61 | if (libPath != null) {
62 | RishConfig.setLibraryPath(new File(libPath).getAbsolutePath());
63 |
64 | }
65 |
66 | if (Looper.getMainLooper() == null) {
67 | Looper.prepareMainLooper();
68 | }
69 |
70 | Handler handler = new Handler(Looper.getMainLooper());
71 |
72 | try {
73 | if (!Sui.init(packageName)) {
74 | System.err.println("Unable to acquire the binder of Sui. Make sure Sui is installed and the current application is not hidden in Sui.");
75 | System.err.flush();
76 | System.exit(1);
77 | }
78 | } catch (Throwable tr) {
79 | tr.printStackTrace(System.err);
80 | System.err.flush();
81 | System.exit(1);
82 | }
83 |
84 | IBinder binder = Shizuku.getBinder();
85 |
86 | handler.post(() -> {
87 | RishConfig.init(binder, ShizukuApiConstants.BINDER_DESCRIPTOR, 30000);
88 | Shizuku.onBinderReceived(binder, packageName);
89 | Shizuku.addBinderReceivedListenerSticky(() -> {
90 | int version = Shizuku.getVersion();
91 | if (version < 12) {
92 | System.err.println("Rish requires server 12 (running " + version + ")");
93 | System.err.flush();
94 | System.exit(1);
95 | }
96 | new Shell().start(args);
97 | });
98 | });
99 |
100 | Looper.loop();
101 | System.exit(0);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/shortcut/ShortcutConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.shortcut;
21 |
22 | import rikka.sui.util.Logger;
23 |
24 | public class ShortcutConstants {
25 |
26 | public static final Logger LOGGER = new Logger("SuiShortcut");
27 |
28 | public static final String SHORTCUT_ID = "rikka.sui.shortcut.SUI";
29 | public static final String SHORTCUT_EXTRA = "rikka.sui.extra.SUI";
30 | }
31 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/systemserver/Bridge.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.systemserver;
21 |
22 | import android.content.Intent;
23 |
24 | import moe.shizuku.server.IShizukuService;
25 |
26 | import static rikka.sui.systemserver.SystemServerConstants.LOGGER;
27 |
28 | public class Bridge {
29 |
30 | public static void dispatchPackageChanged(Intent intent) {
31 | IShizukuService service = BridgeService.get();
32 | if (service == null) {
33 | LOGGER.d("binder is null");
34 | return;
35 | }
36 |
37 | try {
38 | service.dispatchPackageChanged(intent);
39 | } catch (Throwable e) {
40 | LOGGER.w(e, "dispatchPackageChanged");
41 | }
42 | }
43 |
44 | public static boolean isHidden(int uid) {
45 | IShizukuService service = BridgeService.get();
46 | if (service == null) {
47 | LOGGER.d("binder is null");
48 | return false;
49 | }
50 |
51 | try {
52 | return service.isHidden(uid);
53 | } catch (Throwable e) {
54 | LOGGER.w(e, "isHidden");
55 | return false;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/systemserver/PackageReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.systemserver;
21 |
22 | import static rikka.sui.systemserver.SystemServerConstants.LOGGER;
23 |
24 | import android.app.ActivityThread;
25 | import android.content.BroadcastReceiver;
26 | import android.content.Context;
27 | import android.content.ContextHidden;
28 | import android.content.Intent;
29 | import android.content.IntentFilter;
30 | import android.net.Uri;
31 | import android.os.Handler;
32 | import android.os.Looper;
33 | import android.os.UserHandleHidden;
34 |
35 | import dev.rikka.tools.refine.Refine;
36 |
37 | public class PackageReceiver {
38 |
39 | private static final BroadcastReceiver RECEIVER = new BroadcastReceiver() {
40 | @Override
41 | public void onReceive(Context context, Intent intent) {
42 | Uri uri = intent.getData();
43 | String pkgName = (uri != null) ? uri.getSchemeSpecificPart() : null;
44 | int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
45 | LOGGER.d("%s: %s (%d)", intent.getAction(), pkgName, uid);
46 | Bridge.dispatchPackageChanged(intent);
47 | }
48 | };
49 |
50 | public static void register() {
51 | ActivityThread activityThread = ActivityThread.currentActivityThread();
52 | if (activityThread == null) {
53 | LOGGER.w("ActivityThread is null");
54 | return;
55 | }
56 |
57 | IntentFilter intentFilter = new IntentFilter();
58 | intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
59 | intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
60 | intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
61 | intentFilter.addDataScheme("package");
62 |
63 | Handler handler = new Handler(Looper.getMainLooper());
64 |
65 | try {
66 | Refine.unsafeCast(ActivityThread.currentActivityThread().getSystemContext())
67 | .registerReceiverAsUser(
68 | RECEIVER,
69 | Refine.unsafeCast(UserHandleHidden.ALL),
70 | intentFilter,
71 | null,
72 | handler
73 | );
74 | LOGGER.d("register package receiver");
75 | } catch (Throwable e) {
76 | LOGGER.w("registerReceiver failed", e);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/systemserver/SystemProcess.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.systemserver;
21 |
22 | import static rikka.sui.systemserver.SystemServerConstants.LOGGER;
23 |
24 | import android.os.Binder;
25 | import android.os.IBinder;
26 | import android.os.Parcel;
27 |
28 | import androidx.annotation.NonNull;
29 |
30 | import java.util.Arrays;
31 |
32 | import rikka.sui.util.ParcelUtils;
33 |
34 | public final class SystemProcess {
35 |
36 | private static final BridgeService SERVICE = new BridgeService();
37 |
38 | private static boolean execActivityTransaction(@NonNull Binder binder, int code, Parcel data, Parcel reply, int flags) {
39 | return SERVICE.onTransact(code, data, reply, flags);
40 | }
41 |
42 | public static boolean execTransact(@NonNull Binder binder, int code, long dataObj, long replyObj, int flags) {
43 | if (!SERVICE.isServiceTransaction(code)) {
44 | return false;
45 | }
46 |
47 | Parcel data = ParcelUtils.fromNativePointer(dataObj);
48 | Parcel reply = ParcelUtils.fromNativePointer(replyObj);
49 |
50 | if (data == null) {
51 | return false;
52 | }
53 |
54 | boolean res;
55 | try {
56 | res = execActivityTransaction(binder, code, data, reply, flags);
57 | } catch (Exception e) {
58 | if ((flags & IBinder.FLAG_ONEWAY) != 0) {
59 | LOGGER.w(e, "Caught a Exception from the binder stub implementation.");
60 | } else {
61 | if (reply != null) {
62 | reply.setDataPosition(0);
63 | reply.writeException(e);
64 | }
65 | }
66 | res = false;
67 | } finally {
68 | data.setDataPosition(0);
69 | if (reply != null) reply.setDataPosition(0);
70 | }
71 |
72 | if (res) {
73 | data.recycle();
74 | if (reply != null) reply.recycle();
75 | }
76 |
77 | return res;
78 | }
79 |
80 | public static void main(String[] args) {
81 | LOGGER.d("main: %s", Arrays.toString(args));
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/systemserver/SystemServerConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.systemserver;
21 |
22 | import rikka.sui.util.Logger;
23 |
24 | public class SystemServerConstants {
25 |
26 | public static final Logger LOGGER = new Logger("SuiSystemServer");
27 | }
28 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/AppNameComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.Process;
23 |
24 | import java.util.Comparator;
25 |
26 | public class AppNameComparator implements Comparator {
27 |
28 | private final LabelComparator mLabelComparator;
29 | private final InfoProvider mInfoProvider;
30 |
31 | public interface InfoProvider {
32 | CharSequence getTitle(T item);
33 | String getPackageName(T item);
34 | int getUserId(T item);
35 | }
36 |
37 | public AppNameComparator(InfoProvider infoProvider) {
38 | mInfoProvider = infoProvider;
39 | mLabelComparator = new LabelComparator();
40 | }
41 |
42 | @Override
43 | public int compare(T a, T b) {
44 | // Order by the title in the current locale
45 | int result = mLabelComparator.compare(
46 | mInfoProvider.getTitle(a).toString(),
47 | mInfoProvider.getTitle(b).toString());
48 |
49 | if (result != 0) {
50 | return result;
51 | }
52 |
53 | // If labels are same, compare component names
54 | result = mInfoProvider.getPackageName(a).compareTo(mInfoProvider.getPackageName(b));
55 | if (result != 0) {
56 | return result;
57 | }
58 |
59 | if (Process.myUserHandle().hashCode() == mInfoProvider.getUserId(a)) {
60 | return -1;
61 | } else {
62 | int aUserId = mInfoProvider.getUserId(a);
63 | int bUserId = mInfoProvider.getUserId(b);
64 | return Integer.compare(aUserId, bUserId);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/BuildUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.Build;
23 |
24 | public class BuildUtils {
25 |
26 | private static final int SDK = Build.VERSION.SDK_INT;
27 |
28 | private static final int PREVIEW_SDK = SDK >= 23 ? Build.VERSION.PREVIEW_SDK_INT : 0;
29 |
30 | public static boolean atLeast31() {
31 | return SDK >= 31;
32 | }
33 |
34 | public static boolean atLeast30() {
35 | return SDK >= 30;
36 | }
37 |
38 | public static boolean atLeast29() {
39 | return SDK >= 29;
40 | }
41 |
42 | public static boolean atLeast28() {
43 | return SDK >= 28;
44 | }
45 |
46 | public static boolean atLeast26() {
47 | return SDK >= 26;
48 | }
49 |
50 | public static boolean atLeast24() {
51 | return SDK >= 24;
52 | }
53 |
54 | public static boolean atLeast23() {
55 | return SDK >= 23;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/LabelComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package rikka.sui.util;
17 |
18 | import java.text.Collator;
19 | import java.util.Comparator;
20 |
21 | /**
22 | * Extension of {@link java.text.Collator} with special handling for digits. Used for comparing
23 | * user visible labels.
24 | */
25 | public class LabelComparator implements Comparator {
26 |
27 | private final Collator mCollator = Collator.getInstance();
28 |
29 | @Override
30 | public int compare(String titleA, String titleB) {
31 | // Ensure that we de-prioritize any titles that don't start with a
32 | // linguistic letter or digit
33 | boolean aStartsWithLetter = (titleA.length() > 0) &&
34 | Character.isLetterOrDigit(titleA.codePointAt(0));
35 | boolean bStartsWithLetter = (titleB.length() > 0) &&
36 | Character.isLetterOrDigit(titleB.codePointAt(0));
37 | if (aStartsWithLetter && !bStartsWithLetter) {
38 | return -1;
39 | } else if (!aStartsWithLetter && bStartsWithLetter) {
40 | return 1;
41 | }
42 |
43 | // Order by the title in the current locale
44 | return mCollator.compare(titleA, titleB);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/MapUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import java.util.Map;
23 |
24 | public class MapUtil {
25 |
26 | public interface Func {
27 | V call();
28 | }
29 |
30 | public static V getOrPut(Map map, K key, Func func) {
31 | if (map.containsKey(key)) {
32 | return map.get(key);
33 | }
34 | V value = func.call();
35 | map.put(key, value);
36 | return value;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/OsUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.SELinux;
23 |
24 | public class OsUtils {
25 |
26 | private static final int UID = android.system.Os.getuid();
27 | private static final int PID = android.system.Os.getpid();
28 | private static final String SELINUX_CONTEXT;
29 |
30 | static {
31 | String context;
32 | try {
33 | context = SELinux.getContext();
34 | } catch (Throwable tr) {
35 | context =null;
36 | }
37 | SELINUX_CONTEXT = context;
38 | }
39 |
40 |
41 | public static int getUid() {
42 | return UID;
43 | }
44 |
45 | public static int getPid() {
46 | return PID;
47 | }
48 |
49 | public static String getSELinuxContext() {
50 | return SELINUX_CONTEXT;
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/ParcelFileDescriptorUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.ParcelFileDescriptor;
23 | import android.util.Log;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 |
29 | public class ParcelFileDescriptorUtil {
30 |
31 | public static ParcelFileDescriptor pipeFrom(InputStream inputStream) throws IOException {
32 | ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
33 | ParcelFileDescriptor readSide = pipe[0];
34 | ParcelFileDescriptor writeSide = pipe[1];
35 |
36 | new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide))
37 | .start();
38 |
39 | return readSide;
40 | }
41 |
42 | public static ParcelFileDescriptor pipeTo(OutputStream outputStream) throws IOException {
43 | ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
44 | ParcelFileDescriptor readSide = pipe[0];
45 | ParcelFileDescriptor writeSide = pipe[1];
46 |
47 | new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream)
48 | .start();
49 |
50 | return writeSide;
51 | }
52 |
53 | static class TransferThread extends Thread {
54 | final InputStream mIn;
55 | final OutputStream mOut;
56 |
57 | TransferThread(InputStream in, OutputStream out) {
58 | super("ParcelFileDescriptor Transfer Thread");
59 | mIn = in;
60 | mOut = out;
61 | setDaemon(true);
62 | }
63 |
64 | @Override
65 | public void run() {
66 | byte[] buf = new byte[8192];
67 | int len;
68 |
69 | try {
70 | while ((len = mIn.read(buf)) > 0) {
71 | mOut.write(buf, 0, len);
72 | mOut.flush();
73 | }
74 | } catch (IOException e) {
75 | Log.e("TransferThread", Log.getStackTraceString(e));
76 | } finally {
77 | try {
78 | mIn.close();
79 | } catch (IOException e) {
80 | e.printStackTrace();
81 | }
82 | try {
83 | mOut.close();
84 | } catch (IOException e) {
85 | e.printStackTrace();
86 | }
87 | }
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/ParcelUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.Build;
23 | import android.os.Parcel;
24 |
25 | import java.lang.reflect.Method;
26 |
27 | public class ParcelUtils {
28 |
29 | public static String readInterfaceDescriptor(Parcel parcel) {
30 | parcel.readInt();
31 | if (Build.VERSION.SDK_INT >= 29) {
32 | parcel.readInt();
33 | }
34 | if (Build.VERSION.SDK_INT >= 30) {
35 | parcel.readInt();
36 | }
37 | return parcel.readString();
38 | }
39 |
40 | private static Method obtainMethod;
41 |
42 | public static Parcel fromNativePointer(long ptr) {
43 | if (ptr == 0) return null;
44 |
45 | if (obtainMethod == null) {
46 | try {
47 | //noinspection JavaReflectionMemberAccess
48 | obtainMethod = Parcel.class.getDeclaredMethod("obtain", long.class);
49 | obtainMethod.setAccessible(true);
50 | } catch (Throwable e) {
51 | throw new RuntimeException(e);
52 | }
53 | }
54 |
55 | try {
56 | return (Parcel) obtainMethod.invoke(null, ptr);
57 | } catch (Throwable e) {
58 | throw new RuntimeException(e);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/SQLiteDataBaseRemoteCompat.java:
--------------------------------------------------------------------------------
1 | package rikka.sui.util;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.database.DatabaseErrorHandler;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.os.Build;
7 | import android.util.Log;
8 |
9 | import java.io.File;
10 |
11 | public class SQLiteDataBaseRemoteCompat {
12 |
13 | private static final String TAG = "SQLiteDataBaseRemoteCompat";
14 |
15 | @SuppressLint("WrongConstant")
16 | public static SQLiteDatabase openDatabase(String path, DatabaseErrorHandler errorHandler) {
17 | File file = new File(path);
18 |
19 | int openFlags = SQLiteDatabase.OPEN_READWRITE
20 | | SQLiteDatabase.CREATE_IF_NECESSARY
21 | | SQLiteDatabase.NO_LOCALIZED_COLLATORS
22 | | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
23 |
24 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
25 | SQLiteDatabase.OpenParams.Builder params = new SQLiteDatabase.OpenParams.Builder()
26 | .addOpenFlags(openFlags)
27 | .setErrorHandler(sqLiteDatabase -> Log.w(TAG, "database corrupted"));
28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
29 | params.setSynchronousMode("NORMAL");
30 | }
31 | return SQLiteDatabase.openDatabase(file, params.build());
32 | } else {
33 | return SQLiteDatabase.openDatabase(
34 | path, null,
35 | openFlags,
36 | errorHandler
37 | );
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/Unsafe.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | public class Unsafe {
23 | @SuppressWarnings("unchecked")
24 | public static T unsafeCast(Object object) {
25 | return (T) object;
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/module/src/main/java/rikka/sui/util/UserHandleCompat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | public class UserHandleCompat {
23 |
24 | public static final int PER_USER_RANGE = 100000;
25 |
26 | public static int getUserId(int uid) {
27 | return uid / PER_USER_RANGE;
28 | }
29 |
30 | public static int getAppId(int uid) {
31 | return uid % PER_USER_RANGE;
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | mavenLocal()
7 | }
8 | }
9 | dependencyResolutionManagement {
10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11 | repositories {
12 | google()
13 | mavenCentral()
14 | mavenLocal()
15 | }
16 | versionCatalogs {
17 | libs {
18 | version('hidden-api', '4.1.0')
19 | library('hidden-compat', 'dev.rikka.hidden', 'compat').versionRef('hidden-api')
20 | library('hidden-stub', 'dev.rikka.hidden', 'stub').versionRef('hidden-api')
21 |
22 | version('refine', '4.3.0')
23 | library('refine-runtime', 'dev.rikka.tools.refine', 'runtime').versionRef('refine')
24 | library('refine-annotation', 'dev.rikka.tools.refine', 'annotation').versionRef('refine')
25 | library('refine-annotation-processor', 'dev.rikka.tools.refine', 'annotation-processor').versionRef('refine')
26 | plugin('refine', 'dev.rikka.tools.refine').versionRef('refine')
27 | }
28 | }
29 | }
30 |
31 | include ':module', ':ui'
32 |
33 | import org.apache.tools.ant.DirectoryScanner
34 |
35 | DirectoryScanner.removeDefaultExclude('**/.gitattributes')
36 |
37 | def root = "api"
38 |
39 | def propFile = file('local.properties')
40 | def props = new Properties()
41 |
42 | if (propFile.canRead()) {
43 | props.load(new FileInputStream(propFile))
44 |
45 | if (props != null) {
46 | if (props["api.useLocal"].equals("true")) {
47 | root = props["api.dir"]
48 | }
49 | }
50 | }
51 |
52 | include ':aidl'
53 | project(':aidl').projectDir = file("$root${File.separator}aidl")
54 |
55 | include ':rish'
56 | project(':rish').projectDir = file("$root${File.separator}rish")
57 |
58 | include ':shared'
59 | project(':shared').projectDir = file("$root${File.separator}shared")
60 |
61 | include ':api'
62 | project(':api').projectDir = file("$root${File.separator}api")
63 |
64 | include ':provider'
65 | project(':provider').projectDir = file("$root${File.separator}provider")
66 |
67 | include ':server-shared'
68 | project(':server-shared').projectDir = file("$root${File.separator}server-shared")
69 |
--------------------------------------------------------------------------------
/template/magisk_module/.gitattributes:
--------------------------------------------------------------------------------
1 | # Declare files that will always have LF line endings on checkout.
2 | META-INF/** text eol=lf
3 | *.prop text eol=lf
4 | *.sh text eol=lf
5 | *.md text eol=lf
6 | sepolicy.rule text eol=lf
7 |
8 | # Denote all files that are truly binary and should not be modified.
9 | lib/** binary
--------------------------------------------------------------------------------
/template/magisk_module/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ### v13.5.1 (2023-09-19)
4 |
5 | - Works on Android 14
6 | - Works on ColorOS (OPPO & OnePlus) Android 14
7 |
8 | ### v13.0.1 (2023-02-01)
9 |
10 | - Fix authentication error of `transactRemote` with `IBinder.FLAG_ONEWAY`
11 | - Fix `rish` does not work on Android 8.x
12 |
13 | ### v12.7.1 (2022-10-06)
14 |
15 | - Don't set `java.library.path` in rish (#38)
16 | - Fix `peekUserService` not work after app process restarts
17 | - Fix UserServices are not killed after permission is revoked
18 | - Fix UserServices are not killed after the app is uninstalled
19 | - Wrap hidden methods of `Instrumentation` (#41)
20 |
21 | ### v12.6.3 (2022-06-09)
22 |
23 | * Works on Android 13 Beta 3
24 |
25 | ### v12.6.2 (2022-04-10)
26 |
27 | * Temporary solution for [#35](https://github.com/RikkaApps/Sui/issues/35)
28 | * Add `updateJson`, module now can be upgraded through Magisk app
29 |
30 | ### v12.6.1 (2022-02-23)
31 |
32 | * Works on Android 13 DP1 (Apps use Sui/Shizuku may need changes also)
33 | * Create `/data/adb/sui` on start (Swithing from Riru version to zygisk version will delete this folder, causing config unable to save)
34 |
35 | ### v12.4.0 (2022-01-09)
36 |
37 | - Adapt recent Magisk (Zygisk) changes
38 | - Remove the shortcut (shows when you long-press Settings) on uninstall (The shortcut that has already added to the launcher still needs manual removal)
39 |
40 | ### v12.3.0
41 |
42 | - Zygisk support
43 |
44 | ### v12.2.1 (2021-09-20)
45 |
46 | - Fix "adb install" under "adb root"
47 | - Fix "adb root" support is not enabled for Android 11
48 |
49 | ### v12.2.0 (2021-09-11)
50 |
51 | - Add adb root support (disabled by default, see description at [GitHub release](https://github.com/RikkaApps/Sui/releases))
52 | - Fix using UserService will crash sui service on some devices
53 |
54 | ### v12.1.4 (2021-08-28)
55 |
56 | - Make sure original extras from newActivity is not deserialized (For example, this will fix the crash of MIUI Settings "All specs" page)
57 |
58 | ### v12.1.3 (2021-08-26)
59 |
60 | - Fix not working on Sony devices (Not sure if only China version ROMs have this problem)
61 |
62 | ### v12.1.2 (2021-08-26)
63 |
64 | - Bug fix
65 |
66 | ### v12.1.1 (2021-08-25)
67 |
68 | - Don't compile with R8 full mode
69 |
70 | ### v12.1.0 (2021-08-25)
71 |
72 | - [Shizuku API 12](https://github.com/RikkaApps/Shizuku-API/releases/tag/12)
73 | - Add interactive shell support (`post-install.sh` needs changes, see new `post-install.example.sh` for more)
74 | - (Android 8.0+) Long press system settings from the home app, you will find the shortcut of Sui
75 | - (Android 8.0+) Enter "Developer options" in system settings, the system will ask you to add the shortcut of Sui
76 | - Use "the standard Android way" to create UI, the file size increases but a lot more things can achieve
77 |
78 | ### v11.5.0 (2021-03-02)
79 |
80 | - Provide an experimental tool that can run commands, this tool can be used in terminal apps and adb shell (see README for more)
81 | - Filter out packages without components
82 | - Filter out nonexistent packages added by `MATCH_UNINSTALLED_PACKAGES` flag
83 |
84 | > What's the meaning of the command-line tool? There is already "su" from Magisk.
85 | >
86 | > This does helped me to investigate [a bug of Magisk](https://github.com/topjohnwu/Magisk/issues/3976) that happens rarely. At that time, Magisk's su is not available.
87 |
88 | ### v11.4.5 (2021-02-21)
89 |
90 | - Fix random authorization dialog or management ui not showing
91 |
92 | ### v11.4.4 (2021-02-19)
93 |
94 | - Fix developer options crash on Android 12
95 | - Works on devices that have dropped 32-bit support (Android 12 emulator or devices in the future)
96 |
97 | ### v11.4.3 (2021-02-14)
98 |
99 | - Fix installation on x86
100 |
101 | ### v11.4.2 (2021-02-11)
102 |
103 | - Reduce the file size
104 |
105 | ### v11.4.1 (2021-02-07)
106 |
107 | - Fix an undefined behavior
108 | - Skip packages with no code
109 |
110 | ### v11.4 (2021-01-26)
111 |
112 | - Avoid a possible race condition
113 |
114 | ### v11.3 (2021-01-19)
115 |
116 | - Open management UI trough a notification, this notification will show when you are in "Developer options"
117 |
118 | ### v11.2 (2021-01-18)
119 |
120 | - Management UI works more like an `Activity` rather than a window
121 |
122 | ### v11.1 (2021-01-16)
123 |
124 | - Fix permission for multi-process applications
125 |
126 | ### v11.0 (2021-01-16)
127 |
128 | - First public version
129 |
--------------------------------------------------------------------------------
/template/magisk_module/META-INF/com/google/android/update-binary:
--------------------------------------------------------------------------------
1 | #!/sbin/sh
2 |
3 | #################
4 | # Initialization
5 | #################
6 |
7 | umask 022
8 |
9 | # echo before loading util_functions
10 | ui_print() { echo "$1"; }
11 |
12 | require_new_magisk() {
13 | ui_print "*******************************"
14 | ui_print " Please install Magisk v20.4+! "
15 | ui_print "*******************************"
16 | exit 1
17 | }
18 |
19 | #########################
20 | # Load util_functions.sh
21 | #########################
22 |
23 | OUTFD=$2
24 | ZIPFILE=$3
25 |
26 | mount /data 2>/dev/null
27 |
28 | [ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
29 | . /data/adb/magisk/util_functions.sh
30 | [ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
31 |
32 | install_module
33 | exit 0
34 |
--------------------------------------------------------------------------------
/template/magisk_module/META-INF/com/google/android/updater-script:
--------------------------------------------------------------------------------
1 | #MAGISK
2 |
--------------------------------------------------------------------------------
/template/magisk_module/module.prop:
--------------------------------------------------------------------------------
1 | id=${id}
2 | name=${name}
3 | version=${version}
4 | versionCode=${versionCode}
5 | author=${author}
6 | description=${description}
7 | updateJson=${updateJson}
8 |
--------------------------------------------------------------------------------
/template/magisk_module/post-fs-data.sh:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | MODDIR=${0%/*}
3 | MODULE_ID=$(basename "$MODDIR")
4 | FLAVOR=@FLAVOR@
5 |
6 | if [ "$ZYGISK_ENABLED" = false ] && [ "$FLAVOR" = "zygisk" ]; then
7 | log -p w -t "Sui" "Zygisk is disabled, skip zygisk-flavor script"
8 | exit 1
9 | fi
10 |
11 | if [ "$ZYGISK_ENABLED" = true ] && [ "$FLAVOR" = "riru" ]; then
12 | log -p w -t "Sui" "Zygisk is enabled, skip riru-flavor script"
13 | exit 1
14 | fi
15 |
16 | MAGISK_VER_CODE=$(magisk -V)
17 | if [ "$MAGISK_VER_CODE" -ge 21000 ]; then
18 | MAGISK_PATH="$(magisk --path)/.magisk/modules/$MODULE_ID"
19 | else
20 | MAGISK_PATH=/sbin/.magisk/modules/$MODULE_ID
21 | fi
22 |
23 | log -p i -t "Sui" "Magisk version $MAGISK_VER_CODE"
24 | log -p i -t "Sui" "Magisk module path $MAGISK_PATH"
25 |
26 | enable_once="/data/adb/sui/enable_adb_root_once"
27 | enable_forever="/data/adb/sui/enable_adb_root"
28 | adb_root_exit=0
29 |
30 | if [ -f $enable_once ]; then
31 | log -p i -t "Sui" "adb root support is enabled for this time of boot"
32 | rm $enable_once
33 | enable_adb_root=true
34 | fi
35 |
36 | if [ -f $enable_forever ]; then
37 | log -p i -t "Sui" "adb root support is enabled forever"
38 | enable_adb_root=true
39 | fi
40 |
41 | if [ "$enable_adb_root" = true ]; then
42 | log -p i -t "Sui" "Setup adb root support"
43 |
44 | # Run magiskpolicy manually if Magisk does not load sepolicy.rule
45 | if [ ! -e "$(magisk --path)/.magisk/mirror/sepolicy.rules/$MODULE_ID/sepolicy.rule" ]; then
46 | log -p e -t "Sui" "Magisk does not load sepolicy.rule..."
47 | log -p e -t "Sui" "Exec magiskpolicy --live --apply $MAGISK_PATH/sepolicy.rule..."
48 | magiskpolicy --live --apply "$MAGISK_PATH"/sepolicy.rule
49 | log -p i -t "Sui" "Apply finished"
50 | else
51 | log -p i -t "Sui" "Magisk should have loaded sepolicy.rule correctly"
52 | fi
53 |
54 | # Setup adb root support
55 | rm "$MODDIR/bin/adb_root"
56 | ln -s "$MODDIR/bin/sui" "$MODDIR/bin/adb_root"
57 | chmod 700 "$MODDIR/bin/adb_root"
58 | "$MODDIR/bin/adb_root" "$MAGISK_PATH"
59 | adb_root_exit=$?
60 | log -p i -t "Sui" "Exited with $adb_root_exit"
61 | else
62 | log -p i -t "Sui" "adb root support is disabled"
63 | fi
64 |
65 | # Setup uninstaller
66 | rm "$MODDIR/bin/uninstall"
67 | ln -s "$MODDIR/bin/sui" "$MODDIR/bin/uninstall"
68 |
69 | # Run Sui server
70 | chmod 700 "$MODDIR"/bin/sui
71 | exec "$MODDIR"/bin/sui "$MODDIR" "$adb_root_exit"
72 |
--------------------------------------------------------------------------------
/template/magisk_module/post-install.example.sh:
--------------------------------------------------------------------------------
1 | # This script will be loaded during the installation process of Sui.
2 | #
3 | # It's designed to automatically copy rish.
4 | # rish is an Android program for interacting with a shell that runs on a high-privileged daemon process (Sui server).
5 | #
6 | # Rename this file to /data/adb/sui/post-install.sh to allow this script to be loaded.
7 |
8 | # This line is required.
9 | SCRIPT_VERSION=2
10 |
11 | # Variables:
12 | # $RISH_DEX: the path to the dex of rish
13 | # $RISH_LIB: the path to the native library of rish
14 | # $RISH_SCRIPT: the path to the wrapper script to start rish
15 |
16 | copy_rish() {
17 | APP_APPLICATION_ID=$1
18 | APP_UID=$2
19 | DEX_TARGET=$3/$4.dex
20 | LIB_TARGET=$3/librish.so
21 | SCRIPT_TARGET=$3/$4
22 |
23 | cp "$RISH_DEX" "$DEX_TARGET"
24 | cp "$RISH_LIB" "$LIB_TARGET"
25 | cp "$RISH_SCRIPT" "$SCRIPT_TARGET"
26 | chmod 600 "$DEX_TARGET" "$LIB_TARGET"
27 | chmod 700 "$SCRIPT_TARGET"
28 | chown "$APP_UID":"$APP_UID" "$DEX_TARGET" "$LIB_TARGET" "$SCRIPT_TARGET"
29 | sed -i "s/%%%RISH_APPLICATION_ID%%%/$APP_APPLICATION_ID/g" "$SCRIPT_TARGET"
30 | }
31 |
32 | # Example: copy rish to /data/local/tmp (for adb)
33 | #
34 | #ui_print "- Copy rish to /data/local/tmp"
35 | #copy_rish com.android.shell 2000 /data/local/tmp rish # Since every app can check if a specific file exists in /data/local/tmp, it's recommended to change the last parameter "rish" to something else
36 |
37 | # Example: copy rish to Termux
38 | #
39 | #ui_print "- Copy rish to Termux"
40 | #APP_UID=$(stat -c '%u' /data/user/0/com.termux)
41 | #copy_rish com.termux $APP_UID /data/user/0/com.termux/files/home rish
42 |
--------------------------------------------------------------------------------
/template/magisk_module/riru.sh:
--------------------------------------------------------------------------------
1 | #!/sbin/sh
2 | RIRU_MODULE_LIB_NAME="@RIRU_MODULE_LIB_NAME@"
3 |
4 | # Variables for customize.sh
5 | RIRU_API=0
6 | RIRU_MIN_COMPATIBLE_API=0
7 | RIRU_VERSION_CODE=0
8 | RIRU_VERSION_NAME=""
9 |
10 | # Used by util_functions.sh
11 | RIRU_MODULE_API_VERSION=@RIRU_MODULE_API_VERSION@
12 | RIRU_MODULE_MIN_API_VERSION=@RIRU_MODULE_MIN_API_VERSION@
13 | RIRU_MODULE_MIN_RIRU_VERSION_NAME="@RIRU_MODULE_MIN_RIRU_VERSION_NAME@"
14 |
15 | if [ "$MAGISK_VER_CODE" -ge 21000 ]; then
16 | MAGISK_CURRENT_RIRU_MODULE_PATH=$(magisk --path)/.magisk/modules/riru-core
17 | else
18 | MAGISK_CURRENT_RIRU_MODULE_PATH=/sbin/.magisk/modules/riru-core
19 | fi
20 |
21 | if [ ! -d $MAGISK_CURRENT_RIRU_MODULE_PATH ]; then
22 | ui_print "*********************************************************"
23 | ui_print "! Riru is not installed"
24 | ui_print "! Please install Riru from Magisk Manager or https://github.com/RikkaApps/Riru/releases"
25 | abort "*********************************************************"
26 | fi
27 |
28 | if [ -f "$MAGISK_CURRENT_RIRU_MODULE_PATH/disable" ] || [ -f "$MAGISK_CURRENT_RIRU_MODULE_PATH/remove" ]; then
29 | ui_print "*********************************************************"
30 | ui_print "! Riru is not enabled or will be removed"
31 | ui_print "! Please enable Riru in Magisk first"
32 | abort "*********************************************************"
33 | fi
34 |
35 | if [ -f $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh ]; then
36 | ui_print "- Load $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh"
37 | # shellcheck disable=SC1090
38 | . $MAGISK_CURRENT_RIRU_MODULE_PATH/util_functions.sh
39 | else
40 | ui_print "*********************************************************"
41 | ui_print "! Riru $RIRU_MODULE_MIN_RIRU_VERSION_NAME or above is required"
42 | ui_print "! Please upgrade Riru from Magisk Manager or https://github.com/RikkaApps/Riru/releases"
43 | abort "*********************************************************"
44 | fi
45 |
--------------------------------------------------------------------------------
/template/magisk_module/rish:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | BASEDIR=$(dirname "$0")
3 | DEX="$BASEDIR"/rish.dex
4 |
5 | if [ ! -f "$DEX" ]; then
6 | echo "Cannot find $DEX, please check post-install.sh"
7 | exit 1
8 | fi
9 |
10 | [ -z "$RISH_APPLICATION_ID" ] && export RISH_APPLICATION_ID="%%%RISH_APPLICATION_ID%%%"
11 | /system/bin/app_process -Djava.class.path="$DEX" -Dsui.library.path="$BASEDIR" /system/bin --nice-name=rish rikka.sui.shell.Shell "$@"
12 |
--------------------------------------------------------------------------------
/template/magisk_module/sepolicy.rule:
--------------------------------------------------------------------------------
1 | # Allow adbd to transition to magisk:s0 context
2 | allow adbd adbd process setcurrent
3 | allow adbd magisk process dyntransition
4 |
5 | # Fix "adb install" under "adb root"
6 | allow system_server magisk unix_stream_socket { getopt getattr read write }
7 |
--------------------------------------------------------------------------------
/template/magisk_module/uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/sbin/sh
2 | MODDIR=${0%/*}
3 | MODULES=$(dirname "$MODDIR")
4 |
5 | uninstall() {
6 | chmod 700 "$MODDIR"/bin/uninstall
7 | "$MODDIR"/bin/uninstall "$MODDIR"
8 | rm -rf "/data/adb/sui"
9 | }
10 |
11 | if [ -d "$MODULES/riru_sui" ] && [ -d "$MODULES/zygisk_sui" ]; then
12 | if [ -f "$MODULES/riru_sui/remove" ] && [ -f "$MODULES/zygisk_sui/remove" ]; then
13 | uninstall
14 | fi
15 | else
16 | uninstall
17 | fi
18 |
--------------------------------------------------------------------------------
/template/magisk_module/util_functions.sh:
--------------------------------------------------------------------------------
1 | if [ "$ARCH" = "arm64" ]; then
2 | ARCH_NAME="arm64-v8a"
3 | ARCH_NAME_SECONDARY="armeabi-v7a"
4 | ARCH_DIR="lib64"
5 | ARCH_DIR_SECONDARY="lib"
6 | elif [ "$ARCH" = "arm" ]; then
7 | ARCH_NAME="armeabi-v7a"
8 | ARCH_DIR="lib"
9 | elif [ "$ARCH" = "x64" ]; then
10 | ARCH_NAME="x86_64"
11 | ARCH_NAME_SECONDARY="x86"
12 | ARCH_DIR="lib64"
13 | ARCH_DIR_SECONDARY="lib"
14 | elif [ "$ARCH" = "x86" ]; then
15 | ARCH_NAME="x86"
16 | ARCH_DIR="lib"
17 | fi
18 |
19 | enforce_install_from_magisk_app() {
20 | if [ ! "$BOOTMODE" ]; then
21 | ui_print "*********************************************************"
22 | ui_print "! Install from recovery is NOT supported"
23 | ui_print "! Some recovery has broken implementations, install with such recovery will finally cause Riru or Riru modules not working"
24 | ui_print "! Please install from Magisk app"
25 | abort "*********************************************************"
26 | fi
27 | }
28 |
29 | check_arch() {
30 | if [ -z $ARCH_NAME ]; then
31 | abort "! Unsupported platform: $ARCH"
32 | else
33 | ui_print "- Device platform: $ARCH"
34 | fi
35 | }
36 |
37 | check_android_version() {
38 | if [ "$API" -ge 23 ]; then
39 | ui_print "- Android SDK version: $API"
40 | else
41 | ui_print "*********************************************************"
42 | ui_print "! Requires Android 6.0 (API 23) or above"
43 | abort "*********************************************************"
44 | fi
45 | }
46 |
47 | check_magisk_version() {
48 | ui_print "- Magisk version: $MAGISK_VER ($MAGISK_VER_CODE)"
49 |
50 | if [ "$FLAVOR" == "riru" ]; then
51 | ui_print "- Installing Sui (Riru version)"
52 | elif [ "$FLAVOR" == "zygisk" ]; then
53 | ui_print "- Installing Sui (Zygisk version)"
54 |
55 | if [ "$MAGISK_VER_CODE" -lt 23016 ]; then
56 | ui_print "*********************************************************"
57 | ui_print "! Zygisk requires Magisk 23016+"
58 | abort "*********************************************************"
59 | fi
60 | else
61 | ui_print "*********************************************************"
62 | ui_print "! Unsupported flavor $FLAVOR"
63 | abort "*********************************************************"
64 | fi
65 | }
66 |
--------------------------------------------------------------------------------
/template/magisk_module/verify.sh:
--------------------------------------------------------------------------------
1 | TMPDIR_FOR_VERIFY="$TMPDIR/.vunzip"
2 | mkdir "$TMPDIR_FOR_VERIFY"
3 |
4 | abort_verify() {
5 | ui_print "*********************************************************"
6 | ui_print "! $1"
7 | ui_print "! This zip may be corrupted, please try downloading again"
8 | abort "*********************************************************"
9 | }
10 |
11 | # extract
12 | extract() {
13 | zip=$1
14 | file=$2
15 | dir=$3
16 | junk_paths=$4
17 | [ -z "$junk_paths" ] && junk_paths=false
18 | opts="-o"
19 | [ $junk_paths = true ] && opts="-oj"
20 |
21 | file_path=""
22 | hash_path=""
23 | if [ $junk_paths = true ]; then
24 | file_path="$dir/$(basename "$file")"
25 | hash_path="$TMPDIR_FOR_VERIFY/$(basename "$file").sha256sum"
26 | else
27 | file_path="$dir/$file"
28 | hash_path="$TMPDIR_FOR_VERIFY/$file.sha256sum"
29 | fi
30 |
31 | unzip $opts "$zip" "$file" -d "$dir" >&2
32 | [ -f "$file_path" ] || abort_verify "$file not exists"
33 |
34 | unzip $opts "$zip" "$file.sha256sum" -d "$TMPDIR_FOR_VERIFY" >&2
35 | [ -f "$hash_path" ] || abort_verify "$file.sha256sum not exists"
36 |
37 | (echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
38 | ui_print "- Verified $file" >&1
39 | }
40 |
--------------------------------------------------------------------------------
/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /.externalNativeBuild
2 | /build
3 | /release
--------------------------------------------------------------------------------
/ui/aapt2-resources.cfg:
--------------------------------------------------------------------------------
1 | drawable/ic_shortcut_24#no_obfuscate
2 | string/shortcut_is_out_dated#no_obfuscate
3 |
--------------------------------------------------------------------------------
/ui/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -repackageclasses rikka.sui
2 |
3 | -keepclasseswithmembers class rikka.sui.SuiActivity {
4 | public (...);
5 | }
6 |
7 | -keepclasseswithmembers class rikka.sui.SuiRequestPermissionDialog {
8 | public (...);
9 | }
10 |
11 | -keepnames class * implements android.os.Parcelable
12 |
13 | -keepclassmembers class * implements android.os.Parcelable {
14 | public static final android.os.Parcelable$Creator CREATOR;
15 | }
16 |
17 | -assumenosideeffects class android.util.Log {
18 | public static *** d(...);
19 | }
20 |
21 | -assumenosideeffects class rikka.sui.util.Logger {
22 | public *** d(...);
23 | }
24 |
25 | -assumenosideeffects class kotlin.jvm.internal.Intrinsics {
26 | public static void check*(...);
27 | public static void throw*(...);
28 | }
29 |
30 | -keepattributes SourceFile,LineNumberTable
31 | -renamesourcefileattribute SourceFile
32 |
33 | -dontwarn android.**
34 | -dontwarn com.android.**
35 |
--------------------------------------------------------------------------------
/ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/SuiActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui;
21 |
22 | import android.app.ActivityManager;
23 | import android.app.Application;
24 | import android.content.res.Resources;
25 | import android.os.Bundle;
26 |
27 | import androidx.annotation.Nullable;
28 |
29 | import java.util.Objects;
30 |
31 | import rikka.sui.app.AppActivity;
32 | import rikka.sui.management.ManagementFragment;
33 |
34 | public class SuiActivity extends AppActivity {
35 |
36 | public SuiActivity(Application application, Resources resources) {
37 | super(application, resources);
38 | }
39 |
40 | @Override
41 | protected void onCreate(@Nullable Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.main);
44 | setTitle("Sui");
45 | Objects.requireNonNull(getSupportActionBar()).setSubtitle(BuildConfig.VERSION_NAME);
46 |
47 | getSupportFragmentManager().beginTransaction()
48 | .replace(R.id.fragment_container, new ManagementFragment())
49 | .commit();
50 |
51 | setTaskDescription(new ActivityManager.TaskDescription("Sui"));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/SuiRequestPermissionDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui;
21 |
22 | import android.app.Application;
23 | import android.content.res.Resources;
24 |
25 | import rikka.sui.permission.ConfirmationDialog;
26 |
27 | public class SuiRequestPermissionDialog extends ConfirmationDialog {
28 |
29 | public SuiRequestPermissionDialog(
30 | Application application, Resources resources,
31 | int requestUid, int requestPid, String requestPackageName, int requestCode) {
32 | super(application, resources);
33 | show(requestUid, requestPid, requestPackageName, requestCode);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/app/AppFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.app;
21 |
22 | import androidx.fragment.app.Fragment;
23 |
24 | public class AppFragment extends Fragment {
25 |
26 | public AppActivity getAppActivity() {
27 | return (AppActivity) getActivity();
28 | }
29 |
30 | public AppActivity requireAppActivity() {
31 | return (AppActivity) requireActivity();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/ktx/Drawable.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package rikka.sui.ktx
18 |
19 | import android.graphics.Bitmap
20 | import android.graphics.Bitmap.Config
21 | import android.graphics.Canvas
22 | import android.graphics.drawable.BitmapDrawable
23 | import android.graphics.drawable.Drawable
24 | import androidx.annotation.Px
25 |
26 | /**
27 | * Return a [Bitmap] representation of this [Drawable].
28 | *
29 | * If this instance is a [BitmapDrawable] and the [width], [height], and [config] match, the
30 | * underlying [Bitmap] instance will be returned directly. If any of those three properties differ
31 | * then a new [Bitmap] is created. For all other [Drawable] types, a new [Bitmap] is created.
32 | *
33 | * @param width Width of the desired bitmap. Defaults to [Drawable.getIntrinsicWidth].
34 | * @param height Height of the desired bitmap. Defaults to [Drawable.getIntrinsicHeight].
35 | * @param config Bitmap config of the desired bitmap. Null attempts to use the native config, if
36 | * any. Defaults to [Config.ARGB_8888] otherwise.
37 | */
38 | fun Drawable.toBitmap(
39 | @Px width: Int = intrinsicWidth,
40 | @Px height: Int = intrinsicHeight,
41 | config: Config? = null
42 | ): Bitmap {
43 | if (this is BitmapDrawable) {
44 | if (config == null || bitmap.config == config) {
45 | // Fast-path to return original. Bitmap.createScaledBitmap will do this check, but it
46 | // involves allocation and two jumps into native code so we perform the check ourselves.
47 | if (width == intrinsicWidth && height == intrinsicHeight) {
48 | return bitmap
49 | }
50 | return Bitmap.createScaledBitmap(bitmap, width, height, true)
51 | }
52 | }
53 | val oldLeft = bounds.left
54 | val oldTop = bounds.top
55 | val oldRight = bounds.right
56 | val oldBottom = bounds.bottom
57 |
58 | val bitmap = Bitmap.createBitmap(width, height, config ?: Config.ARGB_8888)
59 | setBounds(0, 0, width, height)
60 | draw(Canvas(bitmap))
61 |
62 | setBounds(oldLeft, oldTop, oldRight, oldBottom)
63 | return bitmap
64 | }
65 |
66 | /**
67 | * Updates this drawable's bounds. This version of the method allows using named parameters
68 | * to just set one or more axes.
69 | *
70 | * @see Drawable.setBounds
71 | */
72 | fun Drawable.updateBounds(
73 | @Px left: Int = bounds.left,
74 | @Px top: Int = bounds.top,
75 | @Px right: Int = bounds.right,
76 | @Px bottom: Int = bounds.bottom
77 | ) {
78 | setBounds(left, top, right, bottom)
79 | }
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/ktx/Handler.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.ktx
21 |
22 | import android.os.Handler
23 | import android.os.Looper
24 |
25 | val mainHandler by lazy {
26 | Handler(Looper.getMainLooper())
27 | }
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/ktx/LayoutInflater.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.ktx
21 |
22 | import android.annotation.SuppressLint
23 | import android.content.Context
24 | import android.util.Log
25 | import android.view.LayoutInflater
26 |
27 | @SuppressLint("PrivateApi")
28 | private val constructor = try {
29 | Class.forName("com.android.internal.policy.PhoneLayoutInflater").getDeclaredConstructor(Context::class.java).apply {
30 | isAccessible = true
31 | }
32 | } catch (e: Throwable) {
33 | Log.e("LayoutInflaterKt", Log.getStackTraceString(e))
34 | null
35 | }
36 |
37 | fun createLayoutInflater(context: Context): LayoutInflater? {
38 | return try {
39 | constructor?.newInstance(context) as LayoutInflater?
40 | } catch (e: Throwable) {
41 | Log.e("LayoutInflaterKt", Log.getStackTraceString(e))
42 | null
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/ktx/TextView.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.ktx
21 |
22 | import android.view.View
23 | import android.widget.TextView
24 | import rikka.sui.R
25 |
26 | private const val tag_countdown = 1599296841
27 |
28 | fun TextView.applyCountdown(countdownSecond: Int, message: CharSequence? = null, format: Int = 0) {
29 | val countdownRunnable = object : Runnable {
30 | override fun run() {
31 | val countdown = getTag(tag_countdown) as Int
32 | setTag(tag_countdown, countdown - 1)
33 | if (countdown == 0) {
34 | isEnabled = true
35 | if (message != null) text = message
36 | } else {
37 | isEnabled = false
38 | if (message != null && format != 0) text = context.getString(R.string.brackets_format, message, countdown.toString())
39 | postDelayed(this, 1000)
40 | }
41 | }
42 | }
43 |
44 | val attached = isAttachedToWindow
45 |
46 | setTag(tag_countdown, countdownSecond)
47 | if (attached) {
48 | countdownRunnable.run()
49 | }
50 |
51 | addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
52 | override fun onViewAttachedToWindow(view: View) {
53 | if (!attached) {
54 | countdownRunnable.run()
55 | }
56 | }
57 |
58 | override fun onViewDetachedFromWindow(view: View) {
59 | removeOnAttachStateChangeListener(this)
60 | removeCallbacks(countdownRunnable)
61 | }
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/ktx/Window.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.ktx
21 |
22 | import android.view.Window
23 | import android.view.WindowManager
24 |
25 | private val addSystemFlags = try {
26 | Window::class.java.getDeclaredMethod("addSystemFlags", Int::class.javaPrimitiveType)
27 | } catch (e: Throwable) {
28 | null
29 | }
30 |
31 | private val privateFlagsField = try {
32 | WindowManager.LayoutParams::class.java.getDeclaredField("privateFlags")
33 | } catch (e: Throwable) {
34 | null
35 | }
36 |
37 | val SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS: Int = try {
38 | WindowManager.LayoutParams::class.java.getDeclaredField("SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS").getInt(null)
39 | } catch (e: Throwable) {
40 | 0
41 | }
42 |
43 | fun Window.addSystemFlags(flags: Int) {
44 | if (flags == 0) return
45 | addSystemFlags?.invoke(this, flags)
46 | }
47 |
48 | var WindowManager.LayoutParams.privateFlags: Int
49 | get() = try {
50 | privateFlagsField?.getInt(this) ?: 0
51 | } catch (e: Throwable) {
52 | 0
53 | }
54 | set(value) {
55 | try {
56 | privateFlagsField?.setInt(this, value)
57 | } catch (e: Throwable) {
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/management/ManagementAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 | package rikka.sui.management
20 |
21 | import rikka.recyclerview.BaseRecyclerViewAdapter
22 | import rikka.recyclerview.ClassCreatorPool
23 | import rikka.sui.model.AppInfo
24 |
25 | class ManagementAdapter : BaseRecyclerViewAdapter() {
26 |
27 | init {
28 | creatorPool.putRule(AppInfo::class.java, ManagementAppItemViewHolder.CREATOR)
29 | setHasStableIds(true)
30 | }
31 |
32 | override fun getItemId(position: Int): Long {
33 | return getItemAt(position).hashCode().toLong()
34 | }
35 |
36 | override fun onCreateCreatorPool(): ClassCreatorPool {
37 | return ClassCreatorPool()
38 | }
39 |
40 | fun updateData(data: List) {
41 | getItems().clear()
42 | getItems().addAll(data)
43 | notifyDataSetChanged()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/management/ManagementViewModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 | package rikka.sui.management
20 |
21 | import android.content.Context
22 | import androidx.lifecycle.MutableLiveData
23 | import androidx.lifecycle.ViewModel
24 | import androidx.lifecycle.viewModelScope
25 | import kotlinx.coroutines.CancellationException
26 | import kotlinx.coroutines.Dispatchers
27 | import kotlinx.coroutines.launch
28 | import rikka.lifecycle.Resource
29 | import rikka.lifecycle.Status
30 | import rikka.sui.model.AppInfo
31 | import rikka.sui.util.AppInfoComparator
32 | import rikka.sui.util.BridgeServiceClient
33 |
34 | class ManagementViewModel : ViewModel() {
35 |
36 | private val fullList = ArrayList()
37 |
38 | val appList = MutableLiveData>>(null)
39 |
40 | private fun handleList() {
41 | val list = fullList.sortedWith(AppInfoComparator()).toList()
42 |
43 | appList.postValue(Resource.success(list))
44 | }
45 |
46 | fun invalidateList() {
47 | if (appList.value?.status != Status.SUCCESS) {
48 | return
49 | }
50 |
51 | viewModelScope.launch(Dispatchers.IO) {
52 | handleList()
53 | }
54 | }
55 |
56 | fun reload(context: Context) {
57 | appList.postValue(Resource.loading(null))
58 |
59 | viewModelScope.launch(Dispatchers.IO) {
60 | try {
61 | val pm = context.packageManager
62 | val result = BridgeServiceClient.getApplications(-1 /* ALL */).apply {
63 | forEach { it.label = it.packageInfo.applicationInfo.loadLabel(pm) }
64 | }
65 |
66 | fullList.clear()
67 | fullList.addAll(result)
68 |
69 | handleList()
70 | } catch (e: CancellationException) {
71 |
72 | } catch (e: Throwable) {
73 | appList.postValue(Resource.error(e, null))
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/model/AppInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.model;
21 |
22 | import android.content.pm.PackageInfo;
23 | import android.os.Parcel;
24 | import android.os.Parcelable;
25 | import android.util.Log;
26 |
27 | public class AppInfo implements Parcelable {
28 |
29 | public PackageInfo packageInfo;
30 | public int flags;
31 | public CharSequence label = null;
32 |
33 | public AppInfo() {
34 | }
35 |
36 | protected AppInfo(Parcel in) {
37 | packageInfo = in.readParcelable(PackageInfo.class.getClassLoader());
38 | flags = in.readInt();
39 | }
40 |
41 | public static final Creator CREATOR = new Creator() {
42 | @Override
43 | public AppInfo createFromParcel(Parcel in) {
44 | return new AppInfo(in);
45 | }
46 |
47 | @Override
48 | public AppInfo[] newArray(int size) {
49 | return new AppInfo[size];
50 | }
51 | };
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeParcelable(packageInfo, flags);
61 | dest.writeInt(this.flags);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/permission/SystemDialogRootView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.permission;
21 |
22 | import android.content.BroadcastReceiver;
23 | import android.content.Context;
24 | import android.content.Intent;
25 | import android.content.IntentFilter;
26 | import android.view.KeyEvent;
27 | import android.view.WindowManager;
28 | import android.widget.FrameLayout;
29 |
30 | import androidx.annotation.NonNull;
31 |
32 | import rikka.sui.util.Logger;
33 |
34 | public class SystemDialogRootView extends FrameLayout {
35 |
36 | private static final Logger LOGGER = new Logger("SystemDialogRootView");
37 |
38 | private final BroadcastReceiver receiver = new BroadcastReceiver() {
39 | @Override
40 | public void onReceive(Context context, Intent intent) {
41 | onClose();
42 | dismiss();
43 | }
44 | };
45 | private final WindowManager windowManager;
46 |
47 | public SystemDialogRootView(@NonNull Context context) {
48 | super(context);
49 |
50 | windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
51 | }
52 |
53 | public void onClose() {
54 |
55 | }
56 |
57 | public boolean onBackPressed() {
58 | return true;
59 | }
60 |
61 | public final void show(WindowManager.LayoutParams lp) {
62 | try {
63 | windowManager.addView(this, lp);
64 | requestFocus();
65 | } catch (Exception e) {
66 | LOGGER.w(e, "addView");
67 | }
68 | }
69 |
70 | public final void dismiss() {
71 | try {
72 | windowManager.removeView(this);
73 | } catch (Throwable e) {
74 | LOGGER.w(e, "removeView");
75 | }
76 | }
77 |
78 | @Override
79 | public boolean dispatchKeyEvent(KeyEvent event) {
80 | if (event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
81 | return super.dispatchKeyEvent(event);
82 | }
83 |
84 | if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
85 | getKeyDispatcherState().startTracking(event, this);
86 | return true;
87 | } else if (event.getAction() == KeyEvent.ACTION_UP) {
88 | getKeyDispatcherState().handleUpEvent(event);
89 |
90 | if (event.isTracking() && !event.isCanceled()) {
91 | if (onBackPressed()) {
92 | dismiss();
93 | }
94 | return true;
95 | }
96 | }
97 | return super.dispatchKeyEvent(event);
98 | }
99 |
100 | @Override
101 | protected void onAttachedToWindow() {
102 | super.onAttachedToWindow();
103 |
104 | IntentFilter intentFilter = new IntentFilter();
105 | intentFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
106 |
107 | try {
108 | try {
109 | getContext().registerReceiver(receiver, intentFilter);
110 | LOGGER.i("registerReceiver android.intent.action.CLOSE_SYSTEM_DIALOGS");
111 | } catch (Exception e) {
112 | LOGGER.w(e, "registerReceiver android.intent.action.CLOSE_SYSTEM_DIALOGS");
113 | }
114 | } catch (Throwable e) {
115 | LOGGER.w(e, "registerReceiver");
116 | }
117 | }
118 |
119 | @Override
120 | protected void onDetachedFromWindow() {
121 | super.onDetachedFromWindow();
122 |
123 | try {
124 | getContext().unregisterReceiver(receiver);
125 | } catch (Throwable e) {
126 | LOGGER.w(e, "unregisterReceiver");
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/server/SuiConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.server;
21 |
22 | public class SuiConfig {
23 |
24 | public static final int FLAG_ALLOWED = 1 << 1;
25 | public static final int FLAG_DENIED = 1 << 2;
26 | public static final int FLAG_HIDDEN = 1 << 3;
27 | public static final int MASK_PERMISSION = FLAG_ALLOWED | FLAG_DENIED | FLAG_HIDDEN;
28 | }
29 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/AppIconUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.content.Context;
23 | import android.graphics.drawable.AdaptiveIconDrawable;
24 | import android.os.Build;
25 |
26 | public class AppIconUtil {
27 |
28 | private static Boolean shouldShrinkNonAdaptiveIcons = null;
29 |
30 | public static boolean shouldShrinkNonAdaptiveIcons(Context context) {
31 | if (shouldShrinkNonAdaptiveIcons == null) {
32 | try {
33 | shouldShrinkNonAdaptiveIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
34 | && context.getApplicationContext().getPackageManager().getApplicationIcon(context.getPackageName()) instanceof AdaptiveIconDrawable;
35 | } catch (Throwable e) {
36 | shouldShrinkNonAdaptiveIcons = false;
37 | }
38 | }
39 | return shouldShrinkNonAdaptiveIcons;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/AppInfoComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import java.util.Comparator;
23 |
24 | import rikka.sui.model.AppInfo;
25 | import rikka.sui.util.AppNameComparator;
26 | import rikka.sui.util.UserHandleCompat;
27 |
28 | public class AppInfoComparator implements Comparator {
29 |
30 | private final AppNameComparator appNameComparator = new AppNameComparator<>(new AppInfoProvider());
31 |
32 | @Override
33 | public int compare(AppInfo o1, AppInfo o2) {
34 | int o1f = o1.flags, o2f = o2.flags;
35 | if (o1.flags == 0) o1f = Integer.MAX_VALUE;
36 | if (o2.flags == 0) o2f = Integer.MAX_VALUE;
37 | int c = Integer.compare(o1f, o2f);
38 | if (c == 0) return appNameComparator.compare(o1, o2);
39 | return c;
40 | }
41 |
42 | private static class AppInfoProvider implements AppNameComparator.InfoProvider {
43 |
44 | @Override
45 | public CharSequence getTitle(AppInfo item) {
46 | if (item.label != null) return item.label;
47 | return item.packageInfo.packageName;
48 | }
49 |
50 | @Override
51 | public String getPackageName(AppInfo item) {
52 | return item.packageInfo.packageName;
53 | }
54 |
55 | @Override
56 | public int getUserId(AppInfo item) {
57 | return UserHandleCompat.getUserId(item.packageInfo.applicationInfo.uid);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/AppLabel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package rikka.sui.util;
18 |
19 | import android.content.Context;
20 | import android.content.pm.ApplicationInfo;
21 | import android.text.BidiFormatter;
22 |
23 | import androidx.annotation.NonNull;
24 |
25 | public class AppLabel {
26 |
27 | /**
28 | * The maximum length of a safe label, in characters
29 | */
30 | public static final int MAX_SAFE_LABEL_LENGTH = 1000;
31 |
32 | public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
33 |
34 | /**
35 | * Get the label for an application, truncating if it is too long.
36 | *
37 | * @param applicationInfo the {@link ApplicationInfo} of the application
38 | * @param context the {@code Context} to retrieve {@code PackageManager}
39 | * @return the label for the application
40 | */
41 | @NonNull
42 | public static String getAppLabel(@NonNull ApplicationInfo applicationInfo,
43 | @NonNull Context context) {
44 | return getAppLabel(applicationInfo, DEFAULT_MAX_LABEL_SIZE_PX, context);
45 | }
46 |
47 | /**
48 | * Get the label for an application with the ability to control truncating.
49 | *
50 | * @param applicationInfo the {@link ApplicationInfo} of the application
51 | * @param ellipsizeDip see {@link TextUtilsCompat#makeSafeForPresentation}.
52 | * @param context the {@code Context} to retrieve {@code PackageManager}
53 | * @return the label for the application
54 | */
55 | @NonNull
56 | private static String getAppLabel(@NonNull ApplicationInfo applicationInfo, float ellipsizeDip,
57 | @NonNull Context context) {
58 | String unsafeLabel = applicationInfo.loadLabel(context.getPackageManager()).toString();
59 |
60 | return BidiFormatter.getInstance().unicodeWrap(TextUtilsCompat.makeSafeForPresentation(
61 | unsafeLabel, MAX_SAFE_LABEL_LENGTH, ellipsizeDip,
62 | TextUtilsCompat.SAFE_STRING_FLAG_TRIM | TextUtilsCompat.SAFE_STRING_FLAG_FIRST_LINE)
63 | .toString());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/AppNameComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | import android.os.Process;
23 |
24 | import java.util.Comparator;
25 |
26 | public class AppNameComparator implements Comparator {
27 |
28 | private final LabelComparator mLabelComparator;
29 | private final InfoProvider mInfoProvider;
30 |
31 | public interface InfoProvider {
32 | CharSequence getTitle(T item);
33 | String getPackageName(T item);
34 | int getUserId(T item);
35 | }
36 |
37 | public AppNameComparator(InfoProvider infoProvider) {
38 | mInfoProvider = infoProvider;
39 | mLabelComparator = new LabelComparator();
40 | }
41 |
42 | @Override
43 | public int compare(T a, T b) {
44 | // Order by the title in the current locale
45 | int result = mLabelComparator.compare(
46 | mInfoProvider.getTitle(a).toString(),
47 | mInfoProvider.getTitle(b).toString());
48 |
49 | if (result != 0) {
50 | return result;
51 | }
52 |
53 | // If labels are same, compare component names
54 | result = mInfoProvider.getPackageName(a).compareTo(mInfoProvider.getPackageName(b));
55 | if (result != 0) {
56 | return result;
57 | }
58 |
59 | if (Process.myUserHandle().hashCode() == mInfoProvider.getUserId(a)) {
60 | return -1;
61 | } else {
62 | int aUserId = mInfoProvider.getUserId(a);
63 | int bUserId = mInfoProvider.getUserId(b);
64 | return Integer.compare(aUserId, bUserId);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/LabelComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package rikka.sui.util;
17 |
18 | import java.text.Collator;
19 | import java.util.Comparator;
20 |
21 | /**
22 | * Extension of {@link java.text.Collator} with special handling for digits. Used for comparing
23 | * user visible labels.
24 | */
25 | public class LabelComparator implements Comparator {
26 |
27 | private final Collator mCollator = Collator.getInstance();
28 |
29 | @Override
30 | public int compare(String titleA, String titleB) {
31 | // Ensure that we de-prioritize any titles that don't start with a
32 | // linguistic letter or digit
33 | boolean aStartsWithLetter = (titleA.length() > 0) &&
34 | Character.isLetterOrDigit(titleA.codePointAt(0));
35 | boolean bStartsWithLetter = (titleB.length() > 0) &&
36 | Character.isLetterOrDigit(titleB.codePointAt(0));
37 | if (aStartsWithLetter && !bStartsWithLetter) {
38 | return -1;
39 | } else if (!aStartsWithLetter && bStartsWithLetter) {
40 | return 1;
41 | }
42 |
43 | // Order by the title in the current locale
44 | return mCollator.compare(titleA, titleB);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/Unsafe.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | public class Unsafe {
23 | @SuppressWarnings("unchecked")
24 | public static T unsafeCast(Object object) {
25 | return (T) object;
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/ui/src/main/java/rikka/sui/util/UserHandleCompat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Sui.
3 | *
4 | * Sui is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * Sui is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with Sui. If not, see .
16 | *
17 | * Copyright (c) 2021 Sui Contributors
18 | */
19 |
20 | package rikka.sui.util;
21 |
22 | public class UserHandleCompat {
23 |
24 | private static final int UID = android.system.Os.getuid();
25 | public static final int PER_USER_RANGE = 100000;
26 |
27 | public static int getUserId(int uid) {
28 | return uid / PER_USER_RANGE;
29 | }
30 |
31 | public static int getAppId(int uid) {
32 | return uid % PER_USER_RANGE;
33 | }
34 |
35 | public static int myUserId() {
36 | return getUserId(UID);
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/ui/src/main/res/anim/stagger_layout_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
13 |
16 |
17 |
18 |
19 |
24 |
25 |
--------------------------------------------------------------------------------
/ui/src/main/res/animator/alpha_animator.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
11 |
12 |
13 | -
14 |
15 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ui/src/main/res/color/confirmation_dialog_button_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/confirmation_dialog_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/ic_close_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/ic_shortcut_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/ui/src/main/res/drawable/ic_su_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/appbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
27 |
28 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/appbar_fragment_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/confirmation_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
26 |
27 |
37 |
38 |
43 |
44 |
55 |
56 |
61 |
62 |
73 |
74 |
79 |
80 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/management.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
19 |
20 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/ui/src/main/res/layout/management_app_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
23 |
24 |
33 |
34 |
43 |
44 |
53 |
54 |
55 |
56 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/ui/src/main/res/raw/keep.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/ui/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/src/main/res/values-v31/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:color/system_accent1_500
4 | @android:color/system_accent1_600
5 | @android:color/system_accent1_700
6 | @android:color/system_accent1_700
7 | @android:color/system_neutral1_50
8 |
9 | @android:color/system_accent1_100
10 | @android:color/system_accent1_200
11 | @android:color/system_accent1_300
12 | @android:color/system_accent1_300
13 | @android:color/system_neutral1_900
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ui/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$s%2$s吗?]]>
4 | 拥有设备的完全访问权限
5 | 始终允许
6 | 仅限这一次
7 | 拒绝
8 | 拒绝,不要再询问
9 | %1$s(%2$s)
10 | 超级用户管理
11 | 关闭
12 | 允许
13 | 拒绝
14 | 隐藏
15 | 询问
16 | 显示管理界面
17 | 您已进入“开发者设置”
18 | 点按以显示超级用户管理界面
19 | 快捷方式已过期,请移除此快捷方式后重新添加。
20 |
21 |
--------------------------------------------------------------------------------
/ui/src/main/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 要允許「%1$s」%2$s嗎?
4 | 擁有裝置的 Root 權限
5 | 一律允許
6 | 僅允許這一次
7 | 拒絕
8 | 拒絕且不要再詢問
9 | %1$s(%2$s)
10 | 超級使用者管理
11 | 關閉
12 | 允許
13 | 拒絕
14 | 隱藏
15 | 詢問
16 | 顯示管理介面
17 | 您已進入「開發人員設定」
18 | 輕觸以顯示超級使用者管理介面
19 | 快捷方式已過期,請移除此快捷方式後重新新增。
20 |
21 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/material_teal_500
4 | @color/material_teal_600
5 | @color/material_teal_700
6 | @color/material_teal_700
7 | #f5f5f5
8 |
9 | @color/material_teal_100
10 | @color/material_teal_200
11 | @color/material_teal_300
12 | @color/material_teal_300
13 | #1b1b1b
14 |
15 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 40dp
4 |
5 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$s to %2$s?]]>
4 | have the full access of the device
5 | Allow all the time
6 | Only this time
7 | Deny
8 | Deny, don\'t ask again
9 | %1$s (%2$s)
10 | Superuser management
11 | Close
12 | Allowed
13 | Denied
14 | Hidden
15 | Ask
16 | Show management
17 | You have entered \"Developer options\"
18 | Tap to show superuser management
19 | This shortcut is outdated, please remove this shortcut add it again.
20 |
21 |
--------------------------------------------------------------------------------
/ui/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------