You've already forked TrickyStore
mirror of
https://github.com/5ec1cff/TrickyStore.git
synced 2025-09-06 06:37:07 +00:00
Initial commit
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "module/src/main/cpp/external/libcxx"]
|
||||
path = module/src/main/cpp/external/libcxx
|
||||
url = https://github.com/topjohnwu/libcxx
|
||||
70
build.gradle.kts
Normal file
70
build.gradle.kts
Normal file
@@ -0,0 +1,70 @@
|
||||
import com.android.build.gradle.AppExtension
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.agp.app) apply false
|
||||
}
|
||||
|
||||
fun String.execute(currentWorkingDir: File = file("./")): String {
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
project.exec {
|
||||
workingDir = currentWorkingDir
|
||||
commandLine = split("\\s".toRegex())
|
||||
standardOutput = byteOut
|
||||
}
|
||||
return String(byteOut.toByteArray()).trim()
|
||||
}
|
||||
|
||||
val gitCommitCount = "git rev-list HEAD --count".execute().toInt()
|
||||
val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
|
||||
|
||||
// also the soname
|
||||
val moduleId by extra("tricky_store")
|
||||
val moduleName by extra("Tricky Store")
|
||||
val verName by extra("v1")
|
||||
val verCode by extra(gitCommitCount)
|
||||
val commitHash by extra(gitCommitHash)
|
||||
val abiList by extra(listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"))
|
||||
|
||||
val androidMinSdkVersion by extra(26)
|
||||
val androidTargetSdkVersion by extra(34)
|
||||
val androidCompileSdkVersion by extra(34)
|
||||
val androidBuildToolsVersion by extra("34.0.0")
|
||||
val androidCompileNdkVersion by extra("27.0.11902837")
|
||||
val androidSourceCompatibility by extra(JavaVersion.VERSION_17)
|
||||
val androidTargetCompatibility by extra(JavaVersion.VERSION_17)
|
||||
|
||||
tasks.register("Delete", Delete::class) {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
|
||||
fun Project.configureBaseExtension() {
|
||||
extensions.findByType(AppExtension::class)?.run {
|
||||
namespace = "io.github.a13e300.tricky_store"
|
||||
compileSdkVersion(androidCompileSdkVersion)
|
||||
ndkVersion = androidCompileNdkVersion
|
||||
buildToolsVersion = androidBuildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdk = androidMinSdkVersion
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = androidSourceCompatibility
|
||||
targetCompatibility = androidTargetCompatibility
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
subprojects {
|
||||
plugins.withId("com.android.application") {
|
||||
configureBaseExtension()
|
||||
}
|
||||
plugins.withType(JavaPlugin::class.java) {
|
||||
extensions.configure(JavaPluginExtension::class.java) {
|
||||
sourceCompatibility = androidSourceCompatibility
|
||||
targetCompatibility = androidTargetCompatibility
|
||||
}
|
||||
}
|
||||
}
|
||||
19
gradle.properties
Normal file
19
gradle.properties
Normal file
@@ -0,0 +1,19 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
5
gradle/libs.versions.toml
Normal file
5
gradle/libs.versions.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.5.0"
|
||||
|
||||
[plugins]
|
||||
agp-app = { id = "com.android.application", version.ref = "agp" }
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sun Dec 31 12:28:57 CST 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
gradlew
vendored
Executable file
185
gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
4
module/.gitignore
vendored
Normal file
4
module/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/build
|
||||
/libs
|
||||
/obj
|
||||
/release
|
||||
154
module/build.gradle.kts
Normal file
154
module/build.gradle.kts
Normal file
@@ -0,0 +1,154 @@
|
||||
import android.databinding.tool.ext.capitalizeUS
|
||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
import java.security.MessageDigest
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.agp.app)
|
||||
}
|
||||
|
||||
val moduleId: String by rootProject.extra
|
||||
val moduleName: String by rootProject.extra
|
||||
val verCode: Int by rootProject.extra
|
||||
val verName: String by rootProject.extra
|
||||
val commitHash: String by rootProject.extra
|
||||
val abiList: List<String> by rootProject.extra
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
ndk {
|
||||
abiFilters.addAll(abiList)
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags("-std=c++20")
|
||||
arguments(
|
||||
"-DANDROID_STL=none",
|
||||
"-DMODULE_NAME=$moduleId"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path("src/main/cpp/CMakeLists.txt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
afterEvaluate {
|
||||
val variantLowered = variant.name.lowercase()
|
||||
val variantCapped = variant.name.capitalizeUS()
|
||||
val buildTypeLowered = variant.buildType?.lowercase()
|
||||
val supportedAbis = abiList.map {
|
||||
when (it) {
|
||||
"arm64-v8a" -> "arm64"
|
||||
"armeabi-v7a" -> "arm"
|
||||
"x86" -> "x86"
|
||||
"x86_64" -> "x64"
|
||||
else -> error("unsupported abi $it")
|
||||
}
|
||||
}.joinToString(" ")
|
||||
|
||||
val moduleDir = layout.buildDirectory.file("outputs/module/$variantLowered")
|
||||
val zipFileName =
|
||||
"$moduleName-$verName-$verCode-$commitHash-$buildTypeLowered.zip".replace(' ', '-')
|
||||
|
||||
val prepareModuleFilesTask = task<Sync>("prepareModuleFiles$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn("assemble$variantCapped")
|
||||
into(moduleDir)
|
||||
from(rootProject.layout.projectDirectory.file("README.md"))
|
||||
from(layout.projectDirectory.file("template")) {
|
||||
exclude("module.prop", "customize.sh", "post-fs-data.sh", "service.sh")
|
||||
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
|
||||
}
|
||||
from(layout.projectDirectory.file("template")) {
|
||||
include("module.prop")
|
||||
expand(
|
||||
"moduleId" to moduleId,
|
||||
"moduleName" to moduleName,
|
||||
"versionName" to "$verName ($verCode-$commitHash-$variantLowered)",
|
||||
"versionCode" to verCode
|
||||
)
|
||||
}
|
||||
from(layout.projectDirectory.file("template")) {
|
||||
include("customize.sh", "post-fs-data.sh", "service.sh")
|
||||
val tokens = mapOf(
|
||||
"DEBUG" to if (buildTypeLowered == "debug") "true" else "false",
|
||||
"SONAME" to moduleId,
|
||||
"SUPPORTED_ABIS" to supportedAbis
|
||||
)
|
||||
filter<ReplaceTokens>("tokens" to tokens)
|
||||
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
|
||||
}
|
||||
from(layout.buildDirectory.file("intermediates/stripped_native_libs/$variantLowered/strip${variantCapped}DebugSymbols/out/lib")) {
|
||||
into("lib")
|
||||
}
|
||||
|
||||
doLast {
|
||||
fileTree(moduleDir).visit {
|
||||
if (isDirectory) return@visit
|
||||
val md = MessageDigest.getInstance("SHA-256")
|
||||
file.forEachBlock(4096) { bytes, size ->
|
||||
md.update(bytes, 0, size)
|
||||
}
|
||||
file(file.path + ".sha256").writeText(
|
||||
org.apache.commons.codec.binary.Hex.encodeHexString(
|
||||
md.digest()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val zipTask = task<Zip>("zip$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(prepareModuleFilesTask)
|
||||
archiveFileName.set(zipFileName)
|
||||
destinationDirectory.set(layout.projectDirectory.file("release").asFile)
|
||||
from(moduleDir)
|
||||
}
|
||||
|
||||
val pushTask = task<Exec>("push$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(zipTask)
|
||||
commandLine("adb", "push", zipTask.outputs.files.singleFile.path, "/data/local/tmp")
|
||||
}
|
||||
|
||||
val installKsuTask = task<Exec>("installKsu$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(pushTask)
|
||||
commandLine(
|
||||
"adb", "shell", "su", "-c",
|
||||
"/data/adb/ksud module install /data/local/tmp/$zipFileName"
|
||||
)
|
||||
}
|
||||
|
||||
val installMagiskTask = task<Exec>("installMagisk$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(pushTask)
|
||||
commandLine(
|
||||
"adb",
|
||||
"shell",
|
||||
"su",
|
||||
"-M",
|
||||
"-c",
|
||||
"magisk --install-module /data/local/tmp/$zipFileName"
|
||||
)
|
||||
}
|
||||
|
||||
task<Exec>("installKsuAndReboot$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(installKsuTask)
|
||||
commandLine("adb", "reboot")
|
||||
}
|
||||
|
||||
task<Exec>("installMagiskAndReboot$variantCapped") {
|
||||
group = "module"
|
||||
dependsOn(installMagiskTask)
|
||||
commandLine("adb", "reboot")
|
||||
}
|
||||
}
|
||||
}
|
||||
2
module/src/main/AndroidManifest.xml
Normal file
2
module/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest/>
|
||||
27
module/src/main/cpp/CMakeLists.txt
Normal file
27
module/src/main/cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
project(sample)
|
||||
|
||||
set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both")
|
||||
|
||||
# TODO: set visibility only for our libs (-fvisibility=hidden -fvisibility-inlines-hidden)
|
||||
set(CXX_FLAGS "${CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS}")
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
add_subdirectory(external)
|
||||
link_libraries(cxx)
|
||||
|
||||
# libutils stub
|
||||
add_library(utils SHARED binder/stub_utils.cpp)
|
||||
target_include_directories(utils PUBLIC binder/include)
|
||||
|
||||
# libbinder stub
|
||||
add_library(binder SHARED binder/stub_binder.cpp)
|
||||
target_include_directories(binder PUBLIC binder/include)
|
||||
target_link_libraries(binder utils)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED example.cpp)
|
||||
target_link_libraries(${MODULE_NAME} log binder utils)
|
||||
113
module/src/main/cpp/binder/include/binder/Binder.h
Normal file
113
module/src/main/cpp/binder/include/binder/Binder.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
#include <binder/Common.h>
|
||||
#include <binder/IBinder.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
namespace internal {
|
||||
class Stability;
|
||||
}
|
||||
|
||||
class BBinder : public IBinder {
|
||||
public:
|
||||
LIBBINDER_EXPORTED BBinder();
|
||||
|
||||
LIBBINDER_EXPORTED virtual const String16& getInterfaceDescriptor() const;
|
||||
LIBBINDER_EXPORTED virtual bool isBinderAlive() const;
|
||||
LIBBINDER_EXPORTED virtual status_t pingBinder();
|
||||
LIBBINDER_EXPORTED virtual status_t dump(int fd, const Vector<String16>& args);
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
LIBBINDER_EXPORTED virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply,
|
||||
uint32_t flags = 0) final;
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
LIBBINDER_EXPORTED virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
|
||||
void* cookie = nullptr, uint32_t flags = 0);
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
LIBBINDER_EXPORTED virtual status_t unlinkToDeath(const wp<DeathRecipient>& recipient,
|
||||
void* cookie = nullptr, uint32_t flags = 0,
|
||||
wp<DeathRecipient>* outRecipient = nullptr);
|
||||
|
||||
LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object,
|
||||
void* cleanupCookie,
|
||||
object_cleanup_func func) final;
|
||||
LIBBINDER_EXPORTED virtual void* findObject(const void* objectID) const final;
|
||||
LIBBINDER_EXPORTED virtual void* detachObject(const void* objectID) final;
|
||||
LIBBINDER_EXPORTED void withLock(const std::function<void()>& doWithLock);
|
||||
|
||||
LIBBINDER_EXPORTED virtual BBinder* localBinder();
|
||||
protected:
|
||||
LIBBINDER_EXPORTED virtual ~BBinder();
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
LIBBINDER_EXPORTED virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
|
||||
private:
|
||||
BBinder(const BBinder& o);
|
||||
BBinder& operator=(const BBinder& o);
|
||||
|
||||
class RpcServerLink;
|
||||
class Extras;
|
||||
|
||||
std::atomic<Extras*> mExtras;
|
||||
|
||||
friend ::android::internal::Stability;
|
||||
int16_t mStability;
|
||||
bool mParceled;
|
||||
bool mRecordingOn;
|
||||
|
||||
#ifdef __LP64__
|
||||
int32_t mReserved1;
|
||||
#endif
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class BpRefBase : public virtual RefBase {
|
||||
protected:
|
||||
LIBBINDER_EXPORTED explicit BpRefBase(const sp<IBinder>& o);
|
||||
LIBBINDER_EXPORTED virtual ~BpRefBase();
|
||||
LIBBINDER_EXPORTED virtual void onFirstRef();
|
||||
LIBBINDER_EXPORTED virtual void onLastStrongRef(const void* id);
|
||||
LIBBINDER_EXPORTED virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
|
||||
|
||||
LIBBINDER_EXPORTED inline IBinder* remote() const { return mRemote; }
|
||||
LIBBINDER_EXPORTED inline sp<IBinder> remoteStrong() const {
|
||||
return sp<IBinder>::fromExisting(mRemote);
|
||||
}
|
||||
|
||||
private:
|
||||
BpRefBase(const BpRefBase& o);
|
||||
BpRefBase& operator=(const BpRefBase& o);
|
||||
|
||||
IBinder* const mRemote;
|
||||
RefBase::weakref_type* mRefs;
|
||||
std::atomic<int32_t> mState;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
21
module/src/main/cpp/binder/include/binder/BpBinder.h
Normal file
21
module/src/main/cpp/binder/include/binder/BpBinder.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2005 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
class BpBinder;
|
||||
}
|
||||
2
module/src/main/cpp/binder/include/binder/Common.h
Normal file
2
module/src/main/cpp/binder/include/binder/Common.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define LIBBINDER_EXPORTED __attribute__((__visibility__("default")))
|
||||
228
module/src/main/cpp/binder/include/binder/IBinder.h
Normal file
228
module/src/main/cpp/binder/include/binder/IBinder.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <binder/Common.h>
|
||||
#include <binder/unique_fd.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
// linux/binder.h defines this, but we don't want to include it here in order to
|
||||
// avoid exporting the kernel headers
|
||||
#ifndef B_PACK_CHARS
|
||||
#define B_PACK_CHARS(c1, c2, c3, c4) \
|
||||
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
|
||||
#endif // B_PACK_CHARS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class BBinder;
|
||||
class BpBinder;
|
||||
class IInterface;
|
||||
class Parcel;
|
||||
|
||||
/**
|
||||
* Base class and low-level protocol for a remotable object.
|
||||
* You can derive from this class to create an object for which other
|
||||
* processes can hold references to it. Communication between processes
|
||||
* (method calls, property get and set) is down through a low-level
|
||||
* protocol implemented on top of the transact() API.
|
||||
*/
|
||||
class LIBBINDER_EXPORTED IBinder : public virtual RefBase {
|
||||
public:
|
||||
enum {
|
||||
FIRST_CALL_TRANSACTION = 0x00000001,
|
||||
LAST_CALL_TRANSACTION = 0x00ffffff,
|
||||
|
||||
PING_TRANSACTION = B_PACK_CHARS('_', 'P', 'N', 'G'),
|
||||
START_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'S', 'R', 'D'),
|
||||
STOP_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'E', 'R', 'D'),
|
||||
DUMP_TRANSACTION = B_PACK_CHARS('_', 'D', 'M', 'P'),
|
||||
SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_', 'C', 'M', 'D'),
|
||||
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
|
||||
SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
|
||||
EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
|
||||
DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'),
|
||||
SET_RPC_CLIENT_TRANSACTION = B_PACK_CHARS('_', 'R', 'P', 'C'),
|
||||
|
||||
// See android.os.IBinder.TWEET_TRANSACTION
|
||||
// Most importantly, messages can be anything not exceeding 130 UTF-8
|
||||
// characters, and callees should exclaim "jolly good message old boy!"
|
||||
TWEET_TRANSACTION = B_PACK_CHARS('_', 'T', 'W', 'T'),
|
||||
|
||||
// See android.os.IBinder.LIKE_TRANSACTION
|
||||
// Improve binder self-esteem.
|
||||
LIKE_TRANSACTION = B_PACK_CHARS('_', 'L', 'I', 'K'),
|
||||
|
||||
// Corresponds to TF_ONE_WAY -- an asynchronous call.
|
||||
FLAG_ONEWAY = 0x00000001,
|
||||
|
||||
// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call
|
||||
// is made
|
||||
FLAG_CLEAR_BUF = 0x00000020,
|
||||
|
||||
// Private userspace flag for transaction which is being requested from
|
||||
// a vendor context.
|
||||
FLAG_PRIVATE_VENDOR = 0x10000000,
|
||||
};
|
||||
|
||||
IBinder();
|
||||
|
||||
/**
|
||||
* Check if this IBinder implements the interface named by
|
||||
* @a descriptor. If it does, the base pointer to it is returned,
|
||||
* which you can safely static_cast<> to the concrete C++ interface.
|
||||
*/
|
||||
virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
|
||||
|
||||
/**
|
||||
* Return the canonical name of the interface provided by this IBinder
|
||||
* object.
|
||||
*/
|
||||
virtual const String16& getInterfaceDescriptor() const = 0;
|
||||
|
||||
/**
|
||||
* Last known alive status, from last call. May be arbitrarily stale.
|
||||
* May be incorrect if a service returns an incorrect status code.
|
||||
*/
|
||||
virtual bool isBinderAlive() const = 0;
|
||||
virtual status_t pingBinder() = 0;
|
||||
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
virtual status_t transact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0) = 0;
|
||||
|
||||
// DeathRecipient is pure abstract, there is no virtual method
|
||||
// implementation to put in a translation unit in order to silence the
|
||||
// weak vtables warning.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
class DeathRecipient : public virtual RefBase
|
||||
{
|
||||
public:
|
||||
virtual void binderDied(const wp<IBinder>& who) = 0;
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Register the @a recipient for a notification if this binder
|
||||
* goes away. If this binder object unexpectedly goes away
|
||||
* (typically because its hosting process has been killed),
|
||||
* then DeathRecipient::binderDied() will be called with a reference
|
||||
* to this.
|
||||
*
|
||||
* The @a cookie is optional -- if non-NULL, it should be a
|
||||
* memory address that you own (that is, you know it is unique).
|
||||
*
|
||||
* @note When all references to the binder being linked to are dropped, the
|
||||
* recipient is automatically unlinked. So, you must hold onto a binder in
|
||||
* order to receive death notifications about it.
|
||||
*
|
||||
* @note You will only receive death notifications for remote binders,
|
||||
* as local binders by definition can't die without you dying as well.
|
||||
* Trying to use this function on a local binder will result in an
|
||||
* INVALID_OPERATION code being returned and nothing happening.
|
||||
*
|
||||
* @note This link always holds a weak reference to its recipient.
|
||||
*
|
||||
* @note You will only receive a weak reference to the dead
|
||||
* binder. You should not try to promote this to a strong reference.
|
||||
* (Nor should you need to, as there is nothing useful you can
|
||||
* directly do with it now that it has passed on.)
|
||||
*/
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
|
||||
void* cookie = nullptr,
|
||||
uint32_t flags = 0) = 0;
|
||||
|
||||
/**
|
||||
* Remove a previously registered death notification.
|
||||
* The @a recipient will no longer be called if this object
|
||||
* dies. The @a cookie is optional. If non-NULL, you can
|
||||
* supply a NULL @a recipient, and the recipient previously
|
||||
* added with that cookie will be unlinked.
|
||||
*
|
||||
* If the binder is dead, this will return DEAD_OBJECT. Deleting
|
||||
* the object will also unlink all death recipients.
|
||||
*/
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
|
||||
void* cookie = nullptr,
|
||||
uint32_t flags = 0,
|
||||
wp<DeathRecipient>* outRecipient = nullptr) = 0;
|
||||
|
||||
virtual bool checkSubclass(const void* subclassID) const;
|
||||
|
||||
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
|
||||
|
||||
/**
|
||||
* This object is attached for the lifetime of this binder object. When
|
||||
* this binder object is destructed, the cleanup function of all attached
|
||||
* objects are invoked with their respective objectID, object, and
|
||||
* cleanupCookie. Access to these APIs can be made from multiple threads,
|
||||
* but calls from different threads are allowed to be interleaved.
|
||||
*
|
||||
* This returns the object which is already attached. If this returns a
|
||||
* non-null value, it means that attachObject failed (a given objectID can
|
||||
* only be used once).
|
||||
*/
|
||||
[[nodiscard]] virtual void* attachObject(const void* objectID, void* object,
|
||||
void* cleanupCookie, object_cleanup_func func) = 0;
|
||||
/**
|
||||
* Returns object attached with attachObject.
|
||||
*/
|
||||
[[nodiscard]] virtual void* findObject(const void* objectID) const = 0;
|
||||
/**
|
||||
* Returns object attached with attachObject, and detaches it. This does not
|
||||
* delete the object.
|
||||
*/
|
||||
[[nodiscard]] virtual void* detachObject(const void* objectID) = 0;
|
||||
|
||||
/**
|
||||
* Use the lock that this binder contains internally. For instance, this can
|
||||
* be used to modify an attached object without needing to add an additional
|
||||
* lock (though, that attached object must be retrieved before calling this
|
||||
* method). Calling (most) IBinder methods inside this will deadlock.
|
||||
*/
|
||||
void withLock(const std::function<void()>& doWithLock);
|
||||
|
||||
virtual BBinder* localBinder();
|
||||
virtual BpBinder* remoteBinder();
|
||||
|
||||
protected:
|
||||
virtual ~IBinder();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
9
module/src/main/cpp/binder/include/binder/IInterface.h
Normal file
9
module/src/main/cpp/binder/include/binder/IInterface.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/RefBase.h"
|
||||
|
||||
namespace android {
|
||||
class IInterface : public virtual RefBase {
|
||||
|
||||
};
|
||||
}
|
||||
59
module/src/main/cpp/binder/include/binder/IPCThreadState.h
Normal file
59
module/src/main/cpp/binder/include/binder/IPCThreadState.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2005 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <binder/Common.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Kernel binder thread state. All operations here refer to kernel binder. This
|
||||
* object is allocated per-thread.
|
||||
*/
|
||||
class IPCThreadState {
|
||||
public:
|
||||
|
||||
LIBBINDER_EXPORTED static IPCThreadState* self();
|
||||
LIBBINDER_EXPORTED static IPCThreadState* selfOrNull(); // self(), but won't instantiate
|
||||
|
||||
[[nodiscard]] LIBBINDER_EXPORTED pid_t getCallingPid() const;
|
||||
|
||||
/**
|
||||
* Returns the SELinux security identifier of the process which has
|
||||
* made the current binder call. If not in a binder call this will
|
||||
* return nullptr. If this isn't requested with
|
||||
* Binder::setRequestingSid, it will also return nullptr.
|
||||
*
|
||||
* This can't be restored once it's cleared, and it does not return the
|
||||
* context of the current process when not in a binder call.
|
||||
*/
|
||||
[[nodiscard]] LIBBINDER_EXPORTED const char* getCallingSid() const;
|
||||
|
||||
/**
|
||||
* Returns the UID of the process which has made the current binder
|
||||
* call. If not in a binder call, this will return 0.
|
||||
*/
|
||||
[[nodiscard]] LIBBINDER_EXPORTED uid_t getCallingUid() const;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
190
module/src/main/cpp/binder/include/binder/Parcel.h
Normal file
190
module/src/main/cpp/binder/include/binder/Parcel.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <map> // for legacy reasons
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <binder/unique_fd.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include <binder/Common.h>
|
||||
|
||||
//NOLINTNEXTLINE(google-runtime-int) b/173188702
|
||||
typedef unsigned long long binder_size_t;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
class IBinder;
|
||||
namespace binder {
|
||||
class Status {};
|
||||
}
|
||||
|
||||
class Parcel {
|
||||
public:
|
||||
|
||||
LIBBINDER_EXPORTED Parcel();
|
||||
LIBBINDER_EXPORTED ~Parcel();
|
||||
|
||||
LIBBINDER_EXPORTED const uint8_t* data() const;
|
||||
LIBBINDER_EXPORTED size_t dataSize() const;
|
||||
LIBBINDER_EXPORTED size_t dataAvail() const;
|
||||
LIBBINDER_EXPORTED size_t dataPosition() const;
|
||||
LIBBINDER_EXPORTED size_t dataCapacity() const;
|
||||
LIBBINDER_EXPORTED size_t dataBufferSize() const;
|
||||
|
||||
LIBBINDER_EXPORTED status_t setDataSize(size_t size);
|
||||
|
||||
// this must only be used to set a data position that was previously returned from
|
||||
// dataPosition(). If writes are made, the exact same types of writes must be made (e.g.
|
||||
// auto i = p.dataPosition(); p.writeInt32(0); p.setDataPosition(i); p.writeInt32(1);).
|
||||
// Writing over objects, such as file descriptors and binders, is not supported.
|
||||
LIBBINDER_EXPORTED void setDataPosition(size_t pos) const;
|
||||
LIBBINDER_EXPORTED status_t setDataCapacity(size_t size);
|
||||
|
||||
LIBBINDER_EXPORTED status_t setData(const uint8_t* buffer, size_t len);
|
||||
|
||||
LIBBINDER_EXPORTED status_t appendFrom(const Parcel* parcel, size_t start, size_t len);
|
||||
|
||||
// Verify there are no bytes left to be read on the Parcel.
|
||||
// Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
|
||||
LIBBINDER_EXPORTED binder::Status enforceNoDataAvail() const;
|
||||
|
||||
// This Api is used by fuzzers to skip dataAvail checks.
|
||||
LIBBINDER_EXPORTED void setEnforceNoDataAvail(bool enforceNoDataAvail);
|
||||
|
||||
LIBBINDER_EXPORTED void freeData();
|
||||
|
||||
LIBBINDER_EXPORTED status_t write(const void* data, size_t len);
|
||||
LIBBINDER_EXPORTED void* writeInplace(size_t len);
|
||||
LIBBINDER_EXPORTED status_t writeUnpadded(const void* data, size_t len);
|
||||
LIBBINDER_EXPORTED status_t writeInt32(int32_t val);
|
||||
LIBBINDER_EXPORTED status_t writeUint32(uint32_t val);
|
||||
LIBBINDER_EXPORTED status_t writeInt64(int64_t val);
|
||||
LIBBINDER_EXPORTED status_t writeUint64(uint64_t val);
|
||||
LIBBINDER_EXPORTED status_t writeFloat(float val);
|
||||
LIBBINDER_EXPORTED status_t writeDouble(double val);
|
||||
LIBBINDER_EXPORTED status_t writeCString(const char* str);
|
||||
LIBBINDER_EXPORTED status_t writeString8(const char* str, size_t len);
|
||||
LIBBINDER_EXPORTED status_t writeStrongBinder(const sp<IBinder>& val);
|
||||
LIBBINDER_EXPORTED status_t writeBool(bool val);
|
||||
LIBBINDER_EXPORTED status_t writeChar(char16_t val);
|
||||
LIBBINDER_EXPORTED status_t writeByte(int8_t val);
|
||||
|
||||
// Like Parcel.java's writeNoException(). Just writes a zero int32.
|
||||
// Currently the native implementation doesn't do any of the StrictMode
|
||||
// stack gathering and serialization that the Java implementation does.
|
||||
LIBBINDER_EXPORTED status_t writeNoException();
|
||||
|
||||
LIBBINDER_EXPORTED status_t read(void* outData, size_t len) const;
|
||||
LIBBINDER_EXPORTED const void* readInplace(size_t len) const;
|
||||
LIBBINDER_EXPORTED int32_t readInt32() const;
|
||||
LIBBINDER_EXPORTED status_t readInt32(int32_t* pArg) const;
|
||||
LIBBINDER_EXPORTED uint32_t readUint32() const;
|
||||
LIBBINDER_EXPORTED status_t readUint32(uint32_t* pArg) const;
|
||||
LIBBINDER_EXPORTED int64_t readInt64() const;
|
||||
LIBBINDER_EXPORTED status_t readInt64(int64_t* pArg) const;
|
||||
LIBBINDER_EXPORTED uint64_t readUint64() const;
|
||||
LIBBINDER_EXPORTED status_t readUint64(uint64_t* pArg) const;
|
||||
LIBBINDER_EXPORTED float readFloat() const;
|
||||
LIBBINDER_EXPORTED status_t readFloat(float* pArg) const;
|
||||
LIBBINDER_EXPORTED double readDouble() const;
|
||||
LIBBINDER_EXPORTED status_t readDouble(double* pArg) const;
|
||||
LIBBINDER_EXPORTED bool readBool() const;
|
||||
LIBBINDER_EXPORTED status_t readBool(bool* pArg) const;
|
||||
LIBBINDER_EXPORTED char16_t readChar() const;
|
||||
LIBBINDER_EXPORTED status_t readChar(char16_t* pArg) const;
|
||||
LIBBINDER_EXPORTED int8_t readByte() const;
|
||||
LIBBINDER_EXPORTED status_t readByte(int8_t* pArg) const;
|
||||
|
||||
LIBBINDER_EXPORTED sp<IBinder> readStrongBinder() const;
|
||||
LIBBINDER_EXPORTED status_t readStrongBinder(sp<IBinder>* val) const;
|
||||
LIBBINDER_EXPORTED status_t readNullableStrongBinder(sp<IBinder>* val) const;
|
||||
|
||||
// Like Parcel.java's readExceptionCode(). Reads the first int32
|
||||
// off of a Parcel's header, returning 0 or the negative error
|
||||
// code on exceptions, but also deals with skipping over rich
|
||||
// response headers. Callers should use this to read & parse the
|
||||
// response headers rather than doing it by hand.
|
||||
LIBBINDER_EXPORTED int32_t readExceptionCode() const;
|
||||
|
||||
// Retrieve a file descriptor from the parcel. This returns the raw fd
|
||||
// in the parcel, which you do not own -- use dup() to get your own copy.
|
||||
LIBBINDER_EXPORTED int readFileDescriptor() const;
|
||||
|
||||
private:
|
||||
// `objects` and `objectsSize` always 0 for RPC Parcels.
|
||||
typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
|
||||
size_t objectsSize);
|
||||
|
||||
// special int32 value to indicate NonNull or Null parcelables
|
||||
// This is fixed to be only 0 or 1 by contract, do not change.
|
||||
static constexpr int32_t kNonNullParcelableFlag = 1;
|
||||
static constexpr int32_t kNullParcelableFlag = 0;
|
||||
|
||||
// special int32 size representing a null vector, when applicable in Nullable data.
|
||||
// This fixed as -1 by contract, do not change.
|
||||
static constexpr int32_t kNullVectorSize = -1;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
|
||||
status_t mError;
|
||||
uint8_t* mData;
|
||||
size_t mDataSize;
|
||||
size_t mDataCapacity;
|
||||
mutable size_t mDataPos;
|
||||
|
||||
// Fields only needed when parcelling for "kernel Binder".
|
||||
struct KernelFields {
|
||||
KernelFields() {}
|
||||
binder_size_t* mObjects = nullptr;
|
||||
size_t mObjectsSize = 0;
|
||||
size_t mObjectsCapacity = 0;
|
||||
mutable size_t mNextObjectHint = 0;
|
||||
|
||||
mutable size_t mWorkSourceRequestHeaderPosition = 0;
|
||||
mutable bool mRequestHeaderPresent = false;
|
||||
|
||||
mutable bool mObjectsSorted = false;
|
||||
mutable bool mFdsKnown = true;
|
||||
mutable bool mHasFds = false;
|
||||
};
|
||||
// Fields only needed when parcelling for RPC Binder.
|
||||
struct RpcFields {};
|
||||
std::variant<KernelFields, RpcFields> mVariantFields;
|
||||
|
||||
// Pointer to KernelFields in mVariantFields if present.
|
||||
KernelFields* maybeKernelFields() { return std::get_if<KernelFields>(&mVariantFields); }
|
||||
const KernelFields* maybeKernelFields() const {
|
||||
return std::get_if<KernelFields>(&mVariantFields);
|
||||
}
|
||||
// Pointer to RpcFields in mVariantFields if present.
|
||||
RpcFields* maybeRpcFields() { return std::get_if<RpcFields>(&mVariantFields); }
|
||||
const RpcFields* maybeRpcFields() const { return std::get_if<RpcFields>(&mVariantFields); }
|
||||
|
||||
bool mAllowFds;
|
||||
|
||||
// if this parcelable is involved in a secure transaction, force the
|
||||
// data to be overridden with zero when deallocated
|
||||
mutable bool mDeallocZero;
|
||||
|
||||
// Set this to false to skip dataAvail checks.
|
||||
bool mEnforceNoDataAvail;
|
||||
bool mServiceFuzzing;
|
||||
|
||||
release_func mOwner;
|
||||
|
||||
size_t mReserved;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
5
module/src/main/cpp/binder/include/binder/unique_fd.h
Normal file
5
module/src/main/cpp/binder/include/binder/unique_fd.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace android::binder {
|
||||
class unique_fd;
|
||||
}
|
||||
77
module/src/main/cpp/binder/include/utils/Errors.h
Normal file
77
module/src/main/cpp/binder/include/utils/Errors.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* The type used to return success/failure from frameworks APIs.
|
||||
* See the anonymous enum below for valid values.
|
||||
*/
|
||||
typedef int32_t status_t;
|
||||
|
||||
/*
|
||||
* Error codes.
|
||||
* All error codes are negative values.
|
||||
*/
|
||||
|
||||
enum {
|
||||
OK = 0, // Preferred constant for checking success.
|
||||
#ifndef NO_ERROR
|
||||
// Win32 #defines NO_ERROR as well. It has the same value, so there's no
|
||||
// real conflict, though it's a bit awkward.
|
||||
NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
|
||||
#endif
|
||||
|
||||
UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
|
||||
|
||||
NO_MEMORY = -ENOMEM,
|
||||
INVALID_OPERATION = -ENOSYS,
|
||||
BAD_VALUE = -EINVAL,
|
||||
BAD_TYPE = (UNKNOWN_ERROR + 1),
|
||||
NAME_NOT_FOUND = -ENOENT,
|
||||
PERMISSION_DENIED = -EPERM,
|
||||
NO_INIT = -ENODEV,
|
||||
ALREADY_EXISTS = -EEXIST,
|
||||
DEAD_OBJECT = -EPIPE,
|
||||
FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
|
||||
#if !defined(_WIN32)
|
||||
BAD_INDEX = -EOVERFLOW,
|
||||
NOT_ENOUGH_DATA = -ENODATA,
|
||||
WOULD_BLOCK = -EWOULDBLOCK,
|
||||
TIMED_OUT = -ETIMEDOUT,
|
||||
UNKNOWN_TRANSACTION = -EBADMSG,
|
||||
#else
|
||||
BAD_INDEX = -E2BIG,
|
||||
NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3),
|
||||
WOULD_BLOCK = (UNKNOWN_ERROR + 4),
|
||||
TIMED_OUT = (UNKNOWN_ERROR + 5),
|
||||
UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
|
||||
#endif
|
||||
FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
|
||||
UNEXPECTED_NULL = (UNKNOWN_ERROR + 8),
|
||||
};
|
||||
|
||||
// Human readable name of error
|
||||
std::string statusToString(status_t status);
|
||||
|
||||
} // namespace android
|
||||
487
module/src/main/cpp/binder/include/utils/RefBase.h
Normal file
487
module/src/main/cpp/binder/include/utils/RefBase.h
Normal file
@@ -0,0 +1,487 @@
|
||||
#ifndef ANDROID_REF_BASE_H
|
||||
#define ANDROID_REF_BASE_H
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits> // for common_type.
|
||||
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
// LightRefBase used to be declared in this header, so we have to include it
|
||||
// #include <utils/LightRefBase.h>
|
||||
|
||||
#include <utils/StrongPointer.h>
|
||||
// #include <utils/TypeHelpers.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define COMPARE_WEAK(_op_) \
|
||||
template<typename U> \
|
||||
inline bool operator _op_ (const U* o) const { \
|
||||
return m_ptr _op_ o; \
|
||||
} \
|
||||
/* Needed to handle type inference for nullptr: */ \
|
||||
inline bool operator _op_ (const T* o) const { \
|
||||
return m_ptr _op_ o; \
|
||||
}
|
||||
|
||||
template<template<typename C> class comparator, typename T, typename U>
|
||||
static inline bool _wp_compare_(T* a, U* b) {
|
||||
return comparator<typename std::common_type<T*, U*>::type>()(a, b);
|
||||
}
|
||||
|
||||
// Use std::less and friends to avoid undefined behavior when ordering pointers
|
||||
// to different objects.
|
||||
#define COMPARE_WEAK_FUNCTIONAL(_op_, _compare_) \
|
||||
template<typename U> \
|
||||
inline bool operator _op_ (const U* o) const { \
|
||||
return _wp_compare_<_compare_>(m_ptr, o); \
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// RefererenceRenamer is pure abstract, there is no virtual method
|
||||
// implementation to put in a translation unit in order to silence the
|
||||
// weak vtables warning.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
class ReferenceRenamer {
|
||||
protected:
|
||||
// destructor is purposely not virtual so we avoid code overhead from
|
||||
// subclasses; we have to make it protected to guarantee that it
|
||||
// cannot be called from this base class (and to make strict compilers
|
||||
// happy).
|
||||
~ReferenceRenamer() { }
|
||||
public:
|
||||
virtual void operator()(size_t i) const = 0;
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class RefBase
|
||||
{
|
||||
public:
|
||||
void incStrong(const void* id) const;
|
||||
void incStrongRequireStrong(const void* id) const;
|
||||
void decStrong(const void* id) const;
|
||||
|
||||
void forceIncStrong(const void* id) const;
|
||||
|
||||
class weakref_type
|
||||
{
|
||||
public:
|
||||
RefBase* refBase() const;
|
||||
|
||||
void incWeak(const void* id);
|
||||
void incWeakRequireWeak(const void* id);
|
||||
void decWeak(const void* id);
|
||||
|
||||
// acquires a strong reference if there is already one.
|
||||
bool attemptIncStrong(const void* id);
|
||||
|
||||
// acquires a weak reference if there is already one.
|
||||
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
|
||||
// for proper use.
|
||||
bool attemptIncWeak(const void* id);
|
||||
};
|
||||
|
||||
weakref_type* createWeak(const void* id) const;
|
||||
|
||||
weakref_type* getWeakRefs() const;
|
||||
protected:
|
||||
// When constructing these objects, prefer using sp::make<>. Using a RefBase
|
||||
// object on the stack or with other refcount mechanisms (e.g.
|
||||
// std::shared_ptr) is inherently wrong. RefBase types have an implicit
|
||||
// ownership model and cannot be safely used with other ownership models.
|
||||
|
||||
RefBase();
|
||||
virtual ~RefBase();
|
||||
|
||||
//! Flags for onIncStrongAttempted()
|
||||
enum {
|
||||
FIRST_INC_STRONG = 0x0001
|
||||
};
|
||||
|
||||
// Invoked after creation of initial strong pointer/reference.
|
||||
virtual void onFirstRef();
|
||||
// Invoked when either the last strong reference goes away, or we need to undo
|
||||
// the effect of an unnecessary onIncStrongAttempted.
|
||||
virtual void onLastStrongRef(const void* id);
|
||||
// Only called in OBJECT_LIFETIME_WEAK case. Returns true if OK to promote to
|
||||
// strong reference. May have side effects if it returns true.
|
||||
// The first flags argument is always FIRST_INC_STRONG.
|
||||
// TODO: Remove initial flag argument.
|
||||
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
|
||||
// Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
|
||||
// kind goes away. Unused.
|
||||
// TODO: Remove.
|
||||
virtual void onLastWeakRef(const void* id);
|
||||
|
||||
private:
|
||||
friend class weakref_type;
|
||||
class weakref_impl;
|
||||
|
||||
RefBase(const RefBase& o);
|
||||
RefBase& operator=(const RefBase& o);
|
||||
|
||||
private:
|
||||
weakref_impl* const mRefs;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class wp
|
||||
{
|
||||
public:
|
||||
typedef typename RefBase::weakref_type weakref_type;
|
||||
|
||||
inline wp() : m_ptr(nullptr), m_refs(nullptr) { }
|
||||
|
||||
// if nullptr, returns nullptr
|
||||
//
|
||||
// if a weak pointer is already available, this will retrieve it,
|
||||
// otherwise, this will abort
|
||||
static inline wp<T> fromExisting(T* other);
|
||||
|
||||
// for more information about this flag, see above
|
||||
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
|
||||
wp(std::nullptr_t) : wp() {}
|
||||
#else
|
||||
wp(T* other); // NOLINT(implicit)
|
||||
template <typename U>
|
||||
wp(U* other); // NOLINT(implicit)
|
||||
wp& operator=(T* other);
|
||||
template <typename U>
|
||||
wp& operator=(U* other);
|
||||
#endif
|
||||
|
||||
wp(const wp<T>& other);
|
||||
explicit wp(const sp<T>& other);
|
||||
|
||||
template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
|
||||
template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
|
||||
|
||||
~wp();
|
||||
|
||||
// Assignment
|
||||
|
||||
wp& operator = (const wp<T>& other);
|
||||
wp& operator = (const sp<T>& other);
|
||||
|
||||
template<typename U> wp& operator = (const wp<U>& other);
|
||||
template<typename U> wp& operator = (const sp<U>& other);
|
||||
|
||||
void set_object_and_refs(T* other, weakref_type* refs);
|
||||
|
||||
// promotion to sp
|
||||
|
||||
sp<T> promote() const;
|
||||
|
||||
// Reset
|
||||
|
||||
void clear();
|
||||
|
||||
// Accessors
|
||||
|
||||
inline weakref_type* get_refs() const { return m_refs; }
|
||||
|
||||
inline T* unsafe_get() const { return m_ptr; }
|
||||
|
||||
// Operators
|
||||
|
||||
COMPARE_WEAK(==)
|
||||
COMPARE_WEAK(!=)
|
||||
COMPARE_WEAK_FUNCTIONAL(>, std::greater)
|
||||
COMPARE_WEAK_FUNCTIONAL(<, std::less)
|
||||
COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal)
|
||||
COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal)
|
||||
|
||||
template<typename U>
|
||||
inline bool operator == (const wp<U>& o) const {
|
||||
return m_refs == o.m_refs; // Implies m_ptr == o.mptr; see invariants below.
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline bool operator == (const sp<U>& o) const {
|
||||
// Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older
|
||||
// object at the same address.
|
||||
if (o == nullptr) {
|
||||
return m_ptr == nullptr;
|
||||
} else {
|
||||
return m_refs == o->getWeakRefs(); // Implies m_ptr == o.mptr.
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline bool operator != (const sp<U>& o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline bool operator > (const wp<U>& o) const {
|
||||
if (m_ptr == o.m_ptr) {
|
||||
return _wp_compare_<std::greater>(m_refs, o.m_refs);
|
||||
} else {
|
||||
return _wp_compare_<std::greater>(m_ptr, o.m_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline bool operator < (const wp<U>& o) const {
|
||||
if (m_ptr == o.m_ptr) {
|
||||
return _wp_compare_<std::less>(m_refs, o.m_refs);
|
||||
} else {
|
||||
return _wp_compare_<std::less>(m_ptr, o.m_ptr);
|
||||
}
|
||||
}
|
||||
template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
|
||||
template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
|
||||
template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
|
||||
|
||||
private:
|
||||
template<typename Y> friend class sp;
|
||||
template<typename Y> friend class wp;
|
||||
|
||||
T* m_ptr;
|
||||
weakref_type* m_refs;
|
||||
};
|
||||
|
||||
#undef COMPARE_WEAK
|
||||
#undef COMPARE_WEAK_FUNCTIONAL
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts below here.
|
||||
|
||||
// Implementation invariants:
|
||||
// Either
|
||||
// 1) m_ptr and m_refs are both null, or
|
||||
// 2) m_refs == m_ptr->mRefs, or
|
||||
// 3) *m_ptr is no longer live, and m_refs points to the weakref_type object that corresponded
|
||||
// to m_ptr while it was live. *m_refs remains live while a wp<> refers to it.
|
||||
//
|
||||
// The m_refs field in a RefBase object is allocated on construction, unique to that RefBase
|
||||
// object, and never changes. Thus if two wp's have identical m_refs fields, they are either both
|
||||
// null or point to the same object. If two wp's have identical m_ptr fields, they either both
|
||||
// point to the same live object and thus have the same m_ref fields, or at least one of the
|
||||
// objects is no longer live.
|
||||
//
|
||||
// Note that the above comparison operations go out of their way to provide an ordering consistent
|
||||
// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs.
|
||||
|
||||
template <typename T>
|
||||
wp<T> wp<T>::fromExisting(T* other) {
|
||||
if (!other) return nullptr;
|
||||
|
||||
auto refs = other->getWeakRefs();
|
||||
refs->incWeakRequireWeak(other);
|
||||
|
||||
wp<T> ret;
|
||||
ret.m_ptr = other;
|
||||
ret.m_refs = refs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
|
||||
template<typename T>
|
||||
wp<T>::wp(T* other)
|
||||
: m_ptr(other)
|
||||
{
|
||||
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
wp<T>::wp(U* other) : m_ptr(other) {
|
||||
m_refs = other ? other->createWeak(this) : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
wp<T>& wp<T>::operator=(T* other) {
|
||||
weakref_type* newRefs = other ? other->createWeak(this) : nullptr;
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other;
|
||||
m_refs = newRefs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
wp<T>& wp<T>::operator=(U* other) {
|
||||
weakref_type* newRefs = other ? other->createWeak(this) : 0;
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other;
|
||||
m_refs = newRefs;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
wp<T>::wp(const wp<T>& other)
|
||||
: m_ptr(other.m_ptr), m_refs(other.m_refs)
|
||||
{
|
||||
if (m_ptr) m_refs->incWeak(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wp<T>::wp(const sp<T>& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
{
|
||||
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
wp<T>::wp(const wp<U>& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
{
|
||||
if (m_ptr) {
|
||||
m_refs = other.m_refs;
|
||||
m_refs->incWeak(this);
|
||||
} else {
|
||||
m_refs = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
wp<T>::wp(const sp<U>& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
{
|
||||
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wp<T>::~wp()
|
||||
{
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wp<T>& wp<T>::operator = (const wp<T>& other)
|
||||
{
|
||||
weakref_type* otherRefs(other.m_refs);
|
||||
T* otherPtr(other.m_ptr);
|
||||
if (otherPtr) otherRefs->incWeak(this);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = otherPtr;
|
||||
m_refs = otherRefs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wp<T>& wp<T>::operator = (const sp<T>& other)
|
||||
{
|
||||
weakref_type* newRefs =
|
||||
other != nullptr ? other->createWeak(this) : nullptr;
|
||||
T* otherPtr(other.m_ptr);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = otherPtr;
|
||||
m_refs = newRefs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
wp<T>& wp<T>::operator = (const wp<U>& other)
|
||||
{
|
||||
weakref_type* otherRefs(other.m_refs);
|
||||
U* otherPtr(other.m_ptr);
|
||||
if (otherPtr) otherRefs->incWeak(this);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = otherPtr;
|
||||
m_refs = otherRefs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
wp<T>& wp<T>::operator = (const sp<U>& other)
|
||||
{
|
||||
weakref_type* newRefs =
|
||||
other != nullptr ? other->createWeak(this) : 0;
|
||||
U* otherPtr(other.m_ptr);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = otherPtr;
|
||||
m_refs = newRefs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
|
||||
{
|
||||
if (other) refs->incWeak(this);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other;
|
||||
m_refs = refs;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T> wp<T>::promote() const
|
||||
{
|
||||
sp<T> result;
|
||||
if (m_ptr && m_refs->attemptIncStrong(&result)) {
|
||||
result.set_pointer(m_ptr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void wp<T>::clear()
|
||||
{
|
||||
if (m_ptr) {
|
||||
m_refs->decWeak(this);
|
||||
m_refs = 0;
|
||||
m_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
namespace libutilsinternal {
|
||||
template <typename T, typename = void>
|
||||
struct is_complete_type : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
|
||||
} // namespace libutilsinternal
|
||||
|
||||
namespace std {
|
||||
|
||||
// Define `RefBase` specific versions of `std::make_shared` and
|
||||
// `std::make_unique` to block people from using them. Using them to allocate
|
||||
// `RefBase` objects results in double ownership. Use
|
||||
// `sp<T>::make(...)` instead.
|
||||
//
|
||||
// Note: We exclude incomplete types because `std::is_base_of` is undefined in
|
||||
// that case.
|
||||
|
||||
template <typename T, typename... Args,
|
||||
typename std::enable_if<libutilsinternal::is_complete_type<T>::value, bool>::value = true,
|
||||
typename std::enable_if<std::is_base_of<android::RefBase, T>::value, bool>::value = true>
|
||||
shared_ptr<T> make_shared(Args...) { // SEE COMMENT ABOVE.
|
||||
static_assert(!std::is_base_of<android::RefBase, T>::value, "Must use RefBase with sp<>");
|
||||
}
|
||||
|
||||
template <typename T, typename... Args,
|
||||
typename std::enable_if<libutilsinternal::is_complete_type<T>::value, bool>::value = true,
|
||||
typename std::enable_if<std::is_base_of<android::RefBase, T>::value, bool>::value = true>
|
||||
unique_ptr<T> make_unique(Args...) { // SEE COMMENT ABOVE.
|
||||
static_assert(!std::is_base_of<android::RefBase, T>::value, "Must use RefBase with sp<>");
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_REF_BASE_H
|
||||
6
module/src/main/cpp/binder/include/utils/String16.h
Normal file
6
module/src/main/cpp/binder/include/utils/String16.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// TODO
|
||||
namespace android {
|
||||
class String16 {};
|
||||
}
|
||||
361
module/src/main/cpp/binder/include/utils/StrongPointer.h
Normal file
361
module/src/main/cpp/binder/include/utils/StrongPointer.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (C) 2005 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_STRONG_POINTER_H
|
||||
#define ANDROID_STRONG_POINTER_H
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits> // for common_type.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
template<typename T> class wp;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
class sp {
|
||||
public:
|
||||
inline sp() : m_ptr(nullptr) { }
|
||||
|
||||
// The old way of using sp<> was like this. This is bad because it relies
|
||||
// on implicit conversion to sp<>, which we would like to remove (if an
|
||||
// object is being managed some other way, this is double-ownership). We
|
||||
// want to move away from this:
|
||||
//
|
||||
// sp<Foo> foo = new Foo(...); // DO NOT DO THIS
|
||||
//
|
||||
// Instead, prefer to do this:
|
||||
//
|
||||
// sp<Foo> foo = sp<Foo>::make(...); // DO THIS
|
||||
//
|
||||
// Sometimes, in order to use this, when a constructor is marked as private,
|
||||
// you may need to add this to your class:
|
||||
//
|
||||
// friend class sp<Foo>;
|
||||
template <typename... Args>
|
||||
static inline sp<T> make(Args&&... args);
|
||||
|
||||
// if nullptr, returns nullptr
|
||||
//
|
||||
// if a strong pointer is already available, this will retrieve it,
|
||||
// otherwise, this will abort
|
||||
static inline sp<T> fromExisting(T* other);
|
||||
|
||||
// for more information about this macro and correct RefBase usage, see
|
||||
// the comment at the top of utils/RefBase.h
|
||||
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
|
||||
sp(std::nullptr_t) : sp() {}
|
||||
#else
|
||||
sp(T* other); // NOLINT(implicit)
|
||||
template <typename U>
|
||||
sp(U* other); // NOLINT(implicit)
|
||||
sp& operator=(T* other);
|
||||
template <typename U>
|
||||
sp& operator=(U* other);
|
||||
#endif
|
||||
|
||||
sp(const sp<T>& other);
|
||||
sp(sp<T>&& other) noexcept;
|
||||
|
||||
template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
|
||||
template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
|
||||
|
||||
// Cast a strong pointer directly from one type to another. Constructors
|
||||
// allow changing types, but only if they are pointer-compatible. This does
|
||||
// a static_cast internally.
|
||||
template <typename U>
|
||||
static inline sp<T> cast(const sp<U>& other);
|
||||
|
||||
~sp();
|
||||
|
||||
// Assignment
|
||||
|
||||
sp& operator = (const sp<T>& other);
|
||||
sp& operator=(sp<T>&& other) noexcept;
|
||||
|
||||
template<typename U> sp& operator = (const sp<U>& other);
|
||||
template<typename U> sp& operator = (sp<U>&& other);
|
||||
|
||||
//! Special optimization for use by ProcessState (and nobody else).
|
||||
void force_set(T* other);
|
||||
|
||||
// Reset
|
||||
|
||||
void clear();
|
||||
|
||||
// Accessors
|
||||
|
||||
inline T& operator* () const { return *m_ptr; }
|
||||
inline T* operator-> () const { return m_ptr; }
|
||||
inline T* get() const { return m_ptr; }
|
||||
inline explicit operator bool () const { return m_ptr != nullptr; }
|
||||
|
||||
// Punt these to the wp<> implementation.
|
||||
template<typename U>
|
||||
inline bool operator == (const wp<U>& o) const {
|
||||
return o == *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline bool operator != (const wp<U>& o) const {
|
||||
return o != *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Y> friend class sp;
|
||||
template<typename Y> friend class wp;
|
||||
void set_pointer(T* ptr);
|
||||
T* m_ptr;
|
||||
};
|
||||
|
||||
#define COMPARE_STRONG(_op_) \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
|
||||
return t.get() _op_ u.get(); \
|
||||
} \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const T* t, const sp<U>& u) { \
|
||||
return t _op_ u.get(); \
|
||||
} \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const sp<T>& t, const U* u) { \
|
||||
return t.get() _op_ u; \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
|
||||
return t.get() _op_ nullptr; \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
|
||||
return nullptr _op_ t.get(); \
|
||||
}
|
||||
|
||||
template <template <typename C> class comparator, typename T, typename U>
|
||||
static inline bool _sp_compare_(T* a, U* b) {
|
||||
return comparator<typename std::common_type<T*, U*>::type>()(a, b);
|
||||
}
|
||||
|
||||
#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
|
||||
return _sp_compare_<_compare_>(t.get(), u.get()); \
|
||||
} \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const T* t, const sp<U>& u) { \
|
||||
return _sp_compare_<_compare_>(t, u.get()); \
|
||||
} \
|
||||
template <typename T, typename U> \
|
||||
static inline bool operator _op_(const sp<T>& t, const U* u) { \
|
||||
return _sp_compare_<_compare_>(t.get(), u); \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
|
||||
return _sp_compare_<_compare_>(t.get(), nullptr); \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
|
||||
return _sp_compare_<_compare_>(nullptr, t.get()); \
|
||||
}
|
||||
|
||||
COMPARE_STRONG(==)
|
||||
COMPARE_STRONG(!=)
|
||||
COMPARE_STRONG_FUNCTIONAL(>, std::greater)
|
||||
COMPARE_STRONG_FUNCTIONAL(<, std::less)
|
||||
COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
|
||||
COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
|
||||
|
||||
#undef COMPARE_STRONG
|
||||
#undef COMPARE_STRONG_FUNCTIONAL
|
||||
|
||||
// For code size reasons, we do not want these inlined or templated.
|
||||
void sp_report_race();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts below here.
|
||||
|
||||
// TODO: Ideally we should find a way to increment the reference count before running the
|
||||
// constructor, so that generating an sp<> to this in the constructor is no longer dangerous.
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
sp<T> sp<T>::make(Args&&... args) {
|
||||
T* t = new T(std::forward<Args>(args)...);
|
||||
sp<T> result;
|
||||
result.m_ptr = t;
|
||||
t->incStrong(t);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
sp<T> sp<T>::fromExisting(T* other) {
|
||||
if (other) {
|
||||
other->incStrongRequireStrong(other);
|
||||
sp<T> result;
|
||||
result.m_ptr = other;
|
||||
return result;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
|
||||
template<typename T>
|
||||
sp<T>::sp(T* other)
|
||||
: m_ptr(other) {
|
||||
if (other) {
|
||||
other->incStrong(this);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
sp<T>::sp(U* other) : m_ptr(other) {
|
||||
if (other) {
|
||||
(static_cast<T*>(other))->incStrong(this);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
sp<T>& sp<T>::operator=(T* other) {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
if (other) {
|
||||
other->incStrong(this);
|
||||
}
|
||||
if (oldPtr) oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = other;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
sp<T>::sp(const sp<T>& other)
|
||||
: m_ptr(other.m_ptr) {
|
||||
if (m_ptr)
|
||||
m_ptr->incStrong(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
sp<T>::sp(sp<T>&& other) noexcept : m_ptr(other.m_ptr) {
|
||||
other.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>::sp(const sp<U>& other)
|
||||
: m_ptr(other.m_ptr) {
|
||||
if (m_ptr)
|
||||
m_ptr->incStrong(this);
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>::sp(sp<U>&& other)
|
||||
: m_ptr(other.m_ptr) {
|
||||
other.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
sp<T> sp<T>::cast(const sp<U>& other) {
|
||||
return sp<T>::fromExisting(static_cast<T*>(other.get()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>::~sp() {
|
||||
if (m_ptr)
|
||||
m_ptr->decStrong(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>& sp<T>::operator =(const sp<T>& other) {
|
||||
// Force m_ptr to be read twice, to heuristically check for data races.
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
T* otherPtr(other.m_ptr);
|
||||
if (otherPtr) otherPtr->incStrong(this);
|
||||
if (oldPtr) oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = otherPtr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
sp<T>& sp<T>::operator=(sp<T>&& other) noexcept {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
if (oldPtr) oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = other.m_ptr;
|
||||
other.m_ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>& sp<T>::operator =(const sp<U>& other) {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
T* otherPtr(other.m_ptr);
|
||||
if (otherPtr) otherPtr->incStrong(this);
|
||||
if (oldPtr) oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = otherPtr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>& sp<T>::operator =(sp<U>&& other) {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = other.m_ptr;
|
||||
other.m_ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
|
||||
template<typename T> template<typename U>
|
||||
sp<T>& sp<T>::operator =(U* other) {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
if (other) (static_cast<T*>(other))->incStrong(this);
|
||||
if (oldPtr) oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = other;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void sp<T>::force_set(T* other) {
|
||||
other->forceIncStrong(this);
|
||||
m_ptr = other;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sp<T>::clear() {
|
||||
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
|
||||
if (oldPtr) {
|
||||
oldPtr->decStrong(this);
|
||||
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sp<T>::set_pointer(T* ptr) {
|
||||
m_ptr = ptr;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_STRONG_POINTER_H
|
||||
7
module/src/main/cpp/binder/include/utils/Vector.h
Normal file
7
module/src/main/cpp/binder/include/utils/Vector.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// TODO
|
||||
namespace android {
|
||||
template<class TYPE>
|
||||
class Vector;
|
||||
}
|
||||
140
module/src/main/cpp/binder/stub_binder.cpp
Normal file
140
module/src/main/cpp/binder/stub_binder.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "binder/IBinder.h"
|
||||
#include "binder/Binder.h"
|
||||
#include "binder/BpBinder.h"
|
||||
#include "binder/IPCThreadState.h"
|
||||
#include "binder/Parcel.h"
|
||||
#include "binder/IInterface.h"
|
||||
|
||||
namespace android {
|
||||
// IBinder.h
|
||||
IBinder::IBinder() {}
|
||||
IBinder::~IBinder() {}
|
||||
sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor) { return nullptr; }
|
||||
bool IBinder::checkSubclass(const void* subclassID) const { return false; }
|
||||
void IBinder::withLock(const std::function<void()>& doWithLock) {}
|
||||
|
||||
BBinder* IBinder::localBinder() { return nullptr; }
|
||||
BpBinder* IBinder::remoteBinder() { return nullptr; }
|
||||
|
||||
// Binder.h
|
||||
|
||||
BBinder::BBinder() {}
|
||||
|
||||
const String16& BBinder::getInterfaceDescriptor() const { return {}; }
|
||||
bool BBinder::isBinderAlive() const { return false; }
|
||||
status_t BBinder::pingBinder() { return 0; }
|
||||
status_t BBinder::dump(int fd, const Vector<String16>& args) { return 0; }
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return 0; }
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
status_t BBinder::linkToDeath(const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags) { return 0; }
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
status_t BBinder::unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, wp<DeathRecipient>* outRecipient) { return 0; }
|
||||
|
||||
void* BBinder::attachObject(const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) { return nullptr; }
|
||||
void* BBinder::findObject(const void* objectID) const { return nullptr; }
|
||||
void* BBinder::detachObject(const void* objectID) { return nullptr; }
|
||||
void BBinder::withLock(const std::function<void()>& doWithLock) {}
|
||||
|
||||
BBinder* BBinder::localBinder() { return nullptr; }
|
||||
BBinder::~BBinder() {}
|
||||
|
||||
// NOLINTNEXTLINE(google-default-arguments)
|
||||
status_t BBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return 0; }
|
||||
|
||||
// IPCThreadState.h
|
||||
|
||||
IPCThreadState* IPCThreadState::self() { return nullptr; }
|
||||
IPCThreadState* IPCThreadState::selfOrNull() { return nullptr; }
|
||||
|
||||
pid_t IPCThreadState::getCallingPid() const { return 0; }
|
||||
|
||||
const char* IPCThreadState::getCallingSid() const { return nullptr; }
|
||||
|
||||
uid_t IPCThreadState::getCallingUid() const { return 0; }
|
||||
|
||||
// Parcel.h
|
||||
Parcel::Parcel() {}
|
||||
Parcel::~Parcel() {}
|
||||
|
||||
const uint8_t* Parcel::data() const { return nullptr; }
|
||||
size_t Parcel::dataSize() const { return 0; }
|
||||
size_t Parcel::dataAvail() const { return 0; }
|
||||
size_t Parcel::dataPosition() const { return 0; }
|
||||
size_t Parcel::dataCapacity() const { return 0; }
|
||||
size_t Parcel::dataBufferSize() const { return 0; }
|
||||
|
||||
status_t Parcel::setDataSize(size_t size) { return 0; }
|
||||
|
||||
// this must only be used to set a data position that was previously returned from
|
||||
// dataPosition(). If writes are made, the exact same types of writes must be made (e.g.
|
||||
// auto i = p.dataPosition(); p.writeInt32(0); p.setDataPosition(i); p.writeInt32(1);).
|
||||
// Writing over objects, such as file descriptors and binders, is not supported.
|
||||
void Parcel::setDataPosition(size_t pos) const { }
|
||||
status_t Parcel::setDataCapacity(size_t size) { return 0; }
|
||||
|
||||
status_t Parcel::setData(const uint8_t* buffer, size_t len) { return 0; }
|
||||
|
||||
status_t Parcel::appendFrom(const Parcel* parcel, size_t start, size_t len) { return 0; }
|
||||
|
||||
// Verify there are no bytes left to be read on the Parcel.
|
||||
// Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
|
||||
binder::Status Parcel::enforceNoDataAvail() const { return {}; }
|
||||
|
||||
// This Api is used by fuzzers to skip dataAvail checks.
|
||||
void Parcel::setEnforceNoDataAvail(bool enforceNoDataAvail) {}
|
||||
|
||||
void Parcel::freeData() {}
|
||||
|
||||
status_t Parcel::write(const void* data, size_t len) { return 0; }
|
||||
void* Parcel::writeInplace(size_t len) { return nullptr; }
|
||||
status_t Parcel::writeUnpadded(const void* data, size_t len) { return 0; }
|
||||
status_t Parcel::writeInt32(int32_t val) { return 0; }
|
||||
status_t Parcel::writeUint32(uint32_t val) { return 0; }
|
||||
status_t Parcel::writeInt64(int64_t val) { return 0; }
|
||||
status_t Parcel::writeUint64(uint64_t val) { return 0; }
|
||||
status_t Parcel::writeFloat(float val) { return 0; }
|
||||
status_t Parcel::writeDouble(double val) { return 0; }
|
||||
status_t Parcel::writeCString(const char* str) { return 0; }
|
||||
status_t Parcel::writeString8(const char* str, size_t len) { return 0; }
|
||||
status_t Parcel::writeStrongBinder(const sp<IBinder>& val) { return 0; }
|
||||
status_t Parcel::writeBool(bool val) { return 0; }
|
||||
status_t Parcel::writeChar(char16_t val) { return 0; }
|
||||
status_t Parcel::writeByte(int8_t val) { return 0; }
|
||||
|
||||
// Like Parcel.java's writeNoException(). Just writes a zero int32.
|
||||
// Currently the native implementation doesn't do any of the StrictMode
|
||||
// stack gathering and serialization that the Java implementation does.
|
||||
status_t Parcel::writeNoException() { return 0; }
|
||||
|
||||
status_t Parcel::read(void* outData, size_t len) const { return 0; }
|
||||
const void* Parcel::readInplace(size_t len) const { return nullptr; }
|
||||
int32_t Parcel::readInt32() const { return 0; }
|
||||
status_t Parcel::readInt32(int32_t* pArg) const { return 0; }
|
||||
uint32_t Parcel::readUint32() const { return 0; }
|
||||
status_t Parcel::readUint32(uint32_t* pArg) const { return 0; }
|
||||
int64_t Parcel::readInt64() const { return 0; }
|
||||
status_t Parcel::readInt64(int64_t* pArg) const { return 0; }
|
||||
uint64_t Parcel::readUint64() const { return 0; }
|
||||
status_t Parcel::readUint64(uint64_t* pArg) const { return 0; }
|
||||
float Parcel::readFloat() const { return 0; }
|
||||
status_t Parcel::readFloat(float* pArg) const { return 0; }
|
||||
double Parcel::readDouble() const { return 0; }
|
||||
status_t Parcel::readDouble(double* pArg) const { return 0; }
|
||||
bool Parcel::readBool() const { return 0; }
|
||||
status_t Parcel::readBool(bool* pArg) const { return 0; }
|
||||
char16_t Parcel::readChar() const { return 0; }
|
||||
status_t Parcel::readChar(char16_t* pArg) const { return 0; }
|
||||
int8_t Parcel::readByte() const { return 0; }
|
||||
status_t Parcel::readByte(int8_t* pArg) const { return 0; }
|
||||
|
||||
sp<IBinder> Parcel::readStrongBinder() const { return nullptr; }
|
||||
status_t Parcel::readStrongBinder(sp<IBinder>* val) const { return 0; }
|
||||
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const { return 0; }
|
||||
|
||||
int32_t Parcel::readExceptionCode() const { return 0; }
|
||||
int Parcel::readFileDescriptor() const { return 0; }
|
||||
}
|
||||
52
module/src/main/cpp/binder/stub_utils.cpp
Normal file
52
module/src/main/cpp/binder/stub_utils.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "utils/StrongPointer.h"
|
||||
#include "utils/RefBase.h"
|
||||
|
||||
namespace android {
|
||||
void RefBase::incStrong(const void *id) const {
|
||||
|
||||
}
|
||||
|
||||
void RefBase::incStrongRequireStrong(const void *id) const {
|
||||
|
||||
}
|
||||
|
||||
void RefBase::decStrong(const void *id) const {
|
||||
|
||||
}
|
||||
|
||||
void RefBase::forceIncStrong(const void *id) const {
|
||||
|
||||
}
|
||||
|
||||
RefBase::weakref_type* RefBase::createWeak(const void* id) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefBase::weakref_type* RefBase::getWeakRefs() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefBase::RefBase(): mRefs(nullptr) {}
|
||||
RefBase::~RefBase() {}
|
||||
|
||||
void RefBase::onFirstRef() {}
|
||||
void RefBase::onLastStrongRef(const void* id) {}
|
||||
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) { return false; }
|
||||
void RefBase::onLastWeakRef(const void* id) {}
|
||||
|
||||
RefBase* RefBase::weakref_type::refBase() const { return nullptr; }
|
||||
|
||||
void RefBase::weakref_type::incWeak(const void* id) {}
|
||||
void RefBase::weakref_type::incWeakRequireWeak(const void* id) {}
|
||||
void RefBase::weakref_type::decWeak(const void* id) {}
|
||||
|
||||
// acquires a strong reference if there is already one.
|
||||
bool RefBase::weakref_type::attemptIncStrong(const void* id) { return false; }
|
||||
|
||||
// acquires a weak reference if there is already one.
|
||||
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
|
||||
// for proper use.
|
||||
bool RefBase::weakref_type::attemptIncWeak(const void* id) { return false; }
|
||||
|
||||
void sp_report_race() {}
|
||||
}
|
||||
79
module/src/main/cpp/example.cpp
Normal file
79
module/src/main/cpp/example.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright 2022-2023 John "topjohnwu" Wu
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
|
||||
using zygisk::Api;
|
||||
using zygisk::AppSpecializeArgs;
|
||||
using zygisk::ServerSpecializeArgs;
|
||||
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "MyModule", __VA_ARGS__)
|
||||
|
||||
class MyModule : public zygisk::ModuleBase {
|
||||
public:
|
||||
void onLoad(Api *api, JNIEnv *env) override {
|
||||
this->api = api;
|
||||
this->env = env;
|
||||
}
|
||||
|
||||
void preAppSpecialize(AppSpecializeArgs *args) override {
|
||||
// Use JNI to fetch our process name
|
||||
const char *process = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||
preSpecialize(process);
|
||||
env->ReleaseStringUTFChars(args->nice_name, process);
|
||||
}
|
||||
|
||||
void preServerSpecialize(ServerSpecializeArgs *args) override {
|
||||
preSpecialize("system_server");
|
||||
}
|
||||
|
||||
private:
|
||||
Api *api;
|
||||
JNIEnv *env;
|
||||
|
||||
void preSpecialize(const char *process) {
|
||||
// Demonstrate connecting to to companion process
|
||||
// We ask the companion for a random number
|
||||
unsigned r = 0;
|
||||
int fd = api->connectCompanion();
|
||||
read(fd, &r, sizeof(r));
|
||||
close(fd);
|
||||
LOGD("process=[%s], r=[%u]\n", process, r);
|
||||
|
||||
// Since we do not hook any functions, we should let Zygisk dlclose ourselves
|
||||
api->setOption(zygisk::Option::DLCLOSE_MODULE_LIBRARY);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static int urandom = -1;
|
||||
|
||||
static void companion_handler(int i) {
|
||||
if (urandom < 0) {
|
||||
urandom = open("/dev/urandom", O_RDONLY);
|
||||
}
|
||||
unsigned r;
|
||||
read(urandom, &r, sizeof(r));
|
||||
LOGD("companion r=[%u]\n", r);
|
||||
write(i, &r, sizeof(r));
|
||||
}
|
||||
|
||||
// Register our module class and the companion handler function
|
||||
REGISTER_ZYGISK_MODULE(MyModule)
|
||||
REGISTER_ZYGISK_COMPANION(companion_handler)
|
||||
96
module/src/main/cpp/external/CMakeLists.txt
vendored
Normal file
96
module/src/main/cpp/external/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
project(external)
|
||||
|
||||
# cxx
|
||||
set(LIBCXX_SOURCES
|
||||
algorithm.cpp
|
||||
# any.cpp
|
||||
atomic.cpp
|
||||
barrier.cpp
|
||||
# bind.cpp
|
||||
charconv.cpp
|
||||
chrono.cpp
|
||||
condition_variable.cpp
|
||||
condition_variable_destructor.cpp
|
||||
# debug.cpp
|
||||
exception.cpp
|
||||
# filesystem/directory_iterator.cpp
|
||||
# filesystem/int128_builtins.cpp
|
||||
# filesystem/operations.cpp
|
||||
functional.cpp
|
||||
future.cpp
|
||||
hash.cpp
|
||||
# ios.cpp
|
||||
# ios.instantiations.cpp
|
||||
# iostream.cpp
|
||||
# locale.cpp
|
||||
memory.cpp
|
||||
mutex.cpp
|
||||
mutex_destructor.cpp
|
||||
new.cpp
|
||||
optional.cpp
|
||||
random.cpp
|
||||
# regex.cpp
|
||||
# ryu/d2fixed.cpp
|
||||
# ryu/d2s.cpp
|
||||
# ryu/f2s.cpp
|
||||
shared_mutex.cpp
|
||||
stdexcept.cpp
|
||||
string.cpp
|
||||
# strstream.cpp
|
||||
system_error.cpp
|
||||
thread.cpp
|
||||
# typeinfo.cpp
|
||||
utility.cpp
|
||||
valarray.cpp
|
||||
variant.cpp
|
||||
vector.cpp
|
||||
)
|
||||
|
||||
list(TRANSFORM LIBCXX_SOURCES PREPEND libcxx/src/)
|
||||
|
||||
set(LIBCXX_EXPORT_FLAGS
|
||||
-DLIBCXX_BUILDING_LIBCXXABI
|
||||
-D_LIBCPP_NO_EXCEPTIONS
|
||||
-D_LIBCPP_NO_RTTI
|
||||
-D_LIBCPP_BUILDING_LIBRARY
|
||||
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
|
||||
-D_LIBCXXABI_NO_EXCEPTIONS
|
||||
-D_LIBCPP_HAS_NO_LOCALIZATION
|
||||
)
|
||||
set(LIBCXX_FLAGS
|
||||
-fvisibility-global-new-delete-hidden
|
||||
-fvisibility=hidden
|
||||
-fvisibility-inlines-hidden
|
||||
)
|
||||
set(LIBCXX_EXPORT_INCLUDES libcxx/include)
|
||||
set(LIBCXX_INCLUDES libcxx/src)
|
||||
|
||||
set(LIBCXXABI_SOURCES
|
||||
abort_message.cpp
|
||||
cxa_aux_runtime.cpp
|
||||
cxa_default_handlers.cpp
|
||||
cxa_exception_storage.cpp
|
||||
cxa_guard.cpp
|
||||
cxa_handlers.cpp
|
||||
cxa_noexception.cpp
|
||||
cxa_thread_atexit.cpp
|
||||
cxa_vector.cpp
|
||||
cxa_virtual.cpp
|
||||
stdlib_exception.cpp
|
||||
stdlib_new_delete.cpp
|
||||
stdlib_stdexcept.cpp
|
||||
stdlib_typeinfo.cpp
|
||||
)
|
||||
list(TRANSFORM LIBCXXABI_SOURCES PREPEND libcxx/src/abi/)
|
||||
set(LIBCXXABI_FLAGS
|
||||
-Wno-macro-redefined
|
||||
-Wno-unknown-attributes
|
||||
-DHAS_THREAD_LOCAL)
|
||||
set(LIBCXXABI_INCLUDES libcxx/include/abi)
|
||||
|
||||
add_library(cxx STATIC ${LIBCXX_SOURCES} ${LIBCXXABI_SOURCES})
|
||||
target_compile_options(cxx PUBLIC ${LIBCXX_EXPORT_FLAGS})
|
||||
target_compile_options(cxx PRIVATE ${LIBCXX_FLAGS} ${LIBCXXABI_FLAGS} -ffunction-sections -fdata-sections)
|
||||
target_include_directories(cxx PUBLIC ${LIBCXX_EXPORT_INCLUDES})
|
||||
target_include_directories(cxx PRIVATE ${LIBCXX_INCLUDES} ${LIBCXXABI_INCLUDES})
|
||||
# end cxx
|
||||
1
module/src/main/cpp/external/libcxx
vendored
Submodule
1
module/src/main/cpp/external/libcxx
vendored
Submodule
Submodule module/src/main/cpp/external/libcxx added at 12c8f4e93f
391
module/src/main/cpp/zygisk.hpp
Normal file
391
module/src/main/cpp/zygisk.hpp
Normal file
@@ -0,0 +1,391 @@
|
||||
/* Copyright 2022-2023 John "topjohnwu" Wu
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
// This is the public API for Zygisk modules.
|
||||
// DO NOT MODIFY ANY CODE IN THIS HEADER.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#define ZYGISK_API_VERSION 4
|
||||
|
||||
/*
|
||||
|
||||
***************
|
||||
* Introduction
|
||||
***************
|
||||
|
||||
On Android, all app processes are forked from a special daemon called "Zygote".
|
||||
For each new app process, zygote will fork a new process and perform "specialization".
|
||||
This specialization operation enforces the Android security sandbox on the newly forked
|
||||
process to make sure that 3rd party application code is only loaded after it is being
|
||||
restricted within a sandbox.
|
||||
|
||||
On Android, there is also this special process called "system_server". This single
|
||||
process hosts a significant portion of system services, which controls how the
|
||||
Android operating system and apps interact with each other.
|
||||
|
||||
The Zygisk framework provides a way to allow developers to build modules and run custom
|
||||
code before and after system_server and any app processes' specialization.
|
||||
This enable developers to inject code and alter the behavior of system_server and app processes.
|
||||
|
||||
Please note that modules will only be loaded after zygote has forked the child process.
|
||||
THIS MEANS ALL OF YOUR CODE RUNS IN THE APP/SYSTEM_SERVER PROCESS, NOT THE ZYGOTE DAEMON!
|
||||
|
||||
*********************
|
||||
* Development Guide
|
||||
*********************
|
||||
|
||||
Define a class and inherit zygisk::ModuleBase to implement the functionality of your module.
|
||||
Use the macro REGISTER_ZYGISK_MODULE(className) to register that class to Zygisk.
|
||||
|
||||
Example code:
|
||||
|
||||
static jint (*orig_logger_entry_max)(JNIEnv *env);
|
||||
static jint my_logger_entry_max(JNIEnv *env) { return orig_logger_entry_max(env); }
|
||||
|
||||
class ExampleModule : public zygisk::ModuleBase {
|
||||
public:
|
||||
void onLoad(zygisk::Api *api, JNIEnv *env) override {
|
||||
this->api = api;
|
||||
this->env = env;
|
||||
}
|
||||
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
||||
JNINativeMethod methods[] = {
|
||||
{ "logger_entry_max_payload_native", "()I", (void*) my_logger_entry_max },
|
||||
};
|
||||
api->hookJniNativeMethods(env, "android/util/Log", methods, 1);
|
||||
*(void **) &orig_logger_entry_max = methods[0].fnPtr;
|
||||
}
|
||||
private:
|
||||
zygisk::Api *api;
|
||||
JNIEnv *env;
|
||||
};
|
||||
|
||||
REGISTER_ZYGISK_MODULE(ExampleModule)
|
||||
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
Since your module class's code runs with either Zygote's privilege in pre[XXX]Specialize,
|
||||
or runs in the sandbox of the target process in post[XXX]Specialize, the code in your class
|
||||
never runs in a true superuser environment.
|
||||
|
||||
If your module require access to superuser permissions, you can create and register
|
||||
a root companion handler function. This function runs in a separate root companion
|
||||
daemon process, and an Unix domain socket is provided to allow you to perform IPC between
|
||||
your target process and the root companion process.
|
||||
|
||||
Example code:
|
||||
|
||||
static void example_handler(int socket) { ... }
|
||||
|
||||
REGISTER_ZYGISK_COMPANION(example_handler)
|
||||
|
||||
*/
|
||||
|
||||
namespace zygisk {
|
||||
|
||||
struct Api;
|
||||
struct AppSpecializeArgs;
|
||||
struct ServerSpecializeArgs;
|
||||
|
||||
class ModuleBase {
|
||||
public:
|
||||
|
||||
// This method is called as soon as the module is loaded into the target process.
|
||||
// A Zygisk API handle will be passed as an argument.
|
||||
virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIEnv *env) {}
|
||||
|
||||
// This method is called before the app process is specialized.
|
||||
// At this point, the process just got forked from zygote, but no app specific specialization
|
||||
// is applied. This means that the process does not have any sandbox restrictions and
|
||||
// still runs with the same privilege of zygote.
|
||||
//
|
||||
// All the arguments that will be sent and used for app specialization is passed as a single
|
||||
// AppSpecializeArgs object. You can read and overwrite these arguments to change how the app
|
||||
// process will be specialized.
|
||||
//
|
||||
// If you need to run some operations as superuser, you can call Api::connectCompanion() to
|
||||
// get a socket to do IPC calls with a root companion process.
|
||||
// See Api::connectCompanion() for more info.
|
||||
virtual void preAppSpecialize([[maybe_unused]] AppSpecializeArgs *args) {}
|
||||
|
||||
// This method is called after the app process is specialized.
|
||||
// At this point, the process has all sandbox restrictions enabled for this application.
|
||||
// This means that this method runs with the same privilege of the app's own code.
|
||||
virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {}
|
||||
|
||||
// This method is called before the system server process is specialized.
|
||||
// See preAppSpecialize(args) for more info.
|
||||
virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeArgs *args) {}
|
||||
|
||||
// This method is called after the system server process is specialized.
|
||||
// At this point, the process runs with the privilege of system_server.
|
||||
virtual void postServerSpecialize([[maybe_unused]] const ServerSpecializeArgs *args) {}
|
||||
};
|
||||
|
||||
struct AppSpecializeArgs {
|
||||
// Required arguments. These arguments are guaranteed to exist on all Android versions.
|
||||
jint &uid;
|
||||
jint &gid;
|
||||
jintArray &gids;
|
||||
jint &runtime_flags;
|
||||
jobjectArray &rlimits;
|
||||
jint &mount_external;
|
||||
jstring &se_info;
|
||||
jstring &nice_name;
|
||||
jstring &instruction_set;
|
||||
jstring &app_data_dir;
|
||||
|
||||
// Optional arguments. Please check whether the pointer is null before de-referencing
|
||||
jintArray *const fds_to_ignore;
|
||||
jboolean *const is_child_zygote;
|
||||
jboolean *const is_top_app;
|
||||
jobjectArray *const pkg_data_info_list;
|
||||
jobjectArray *const whitelisted_data_info_list;
|
||||
jboolean *const mount_data_dirs;
|
||||
jboolean *const mount_storage_dirs;
|
||||
|
||||
AppSpecializeArgs() = delete;
|
||||
};
|
||||
|
||||
struct ServerSpecializeArgs {
|
||||
jint &uid;
|
||||
jint &gid;
|
||||
jintArray &gids;
|
||||
jint &runtime_flags;
|
||||
jlong &permitted_capabilities;
|
||||
jlong &effective_capabilities;
|
||||
|
||||
ServerSpecializeArgs() = delete;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
struct api_table;
|
||||
template <class T> void entry_impl(api_table *, JNIEnv *);
|
||||
}
|
||||
|
||||
// These values are used in Api::setOption(Option)
|
||||
enum Option : int {
|
||||
// Force Magisk's denylist unmount routines to run on this process.
|
||||
//
|
||||
// Setting this option only makes sense in preAppSpecialize.
|
||||
// The actual unmounting happens during app process specialization.
|
||||
//
|
||||
// Set this option to force all Magisk and modules' files to be unmounted from the
|
||||
// mount namespace of the process, regardless of the denylist enforcement status.
|
||||
FORCE_DENYLIST_UNMOUNT = 0,
|
||||
|
||||
// When this option is set, your module's library will be dlclose-ed after post[XXX]Specialize.
|
||||
// Be aware that after dlclose-ing your module, all of your code will be unmapped from memory.
|
||||
// YOU MUST NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTIONS IN THE PROCESS.
|
||||
DLCLOSE_MODULE_LIBRARY = 1,
|
||||
};
|
||||
|
||||
// Bit masks of the return value of Api::getFlags()
|
||||
enum StateFlag : uint32_t {
|
||||
// The user has granted root access to the current process
|
||||
PROCESS_GRANTED_ROOT = (1u << 0),
|
||||
|
||||
// The current process was added on the denylist
|
||||
PROCESS_ON_DENYLIST = (1u << 1),
|
||||
};
|
||||
|
||||
// All API methods will stop working after post[XXX]Specialize as Zygisk will be unloaded
|
||||
// from the specialized process afterwards.
|
||||
struct Api {
|
||||
|
||||
// Connect to a root companion process and get a Unix domain socket for IPC.
|
||||
//
|
||||
// This API only works in the pre[XXX]Specialize methods due to SELinux restrictions.
|
||||
//
|
||||
// The pre[XXX]Specialize methods run with the same privilege of zygote.
|
||||
// If you would like to do some operations with superuser permissions, register a handler
|
||||
// function that would be called in the root process with REGISTER_ZYGISK_COMPANION(func).
|
||||
// Another good use case for a companion process is that if you want to share some resources
|
||||
// across multiple processes, hold the resources in the companion process and pass it over.
|
||||
//
|
||||
// The root companion process is ABI aware; that is, when calling this method from a 32-bit
|
||||
// process, you will be connected to a 32-bit companion process, and vice versa for 64-bit.
|
||||
//
|
||||
// Returns a file descriptor to a socket that is connected to the socket passed to your
|
||||
// module's companion request handler. Returns -1 if the connection attempt failed.
|
||||
int connectCompanion();
|
||||
|
||||
// Get the file descriptor of the root folder of the current module.
|
||||
//
|
||||
// This API only works in the pre[XXX]Specialize methods.
|
||||
// Accessing the directory returned is only possible in the pre[XXX]Specialize methods
|
||||
// or in the root companion process (assuming that you sent the fd over the socket).
|
||||
// Both restrictions are due to SELinux and UID.
|
||||
//
|
||||
// Returns -1 if errors occurred.
|
||||
int getModuleDir();
|
||||
|
||||
// Set various options for your module.
|
||||
// Please note that this method accepts one single option at a time.
|
||||
// Check zygisk::Option for the full list of options available.
|
||||
void setOption(Option opt);
|
||||
|
||||
// Get information about the current process.
|
||||
// Returns bitwise-or'd zygisk::StateFlag values.
|
||||
uint32_t getFlags();
|
||||
|
||||
// Exempt the provided file descriptor from being automatically closed.
|
||||
//
|
||||
// This API only make sense in preAppSpecialize; calling this method in any other situation
|
||||
// is either a no-op (returns true) or an error (returns false).
|
||||
//
|
||||
// When false is returned, the provided file descriptor will eventually be closed by zygote.
|
||||
bool exemptFd(int fd);
|
||||
|
||||
// Hook JNI native methods for a class
|
||||
//
|
||||
// Lookup all registered JNI native methods and replace it with your own methods.
|
||||
// The original function pointer will be saved in each JNINativeMethod's fnPtr.
|
||||
// If no matching class, method name, or signature is found, that specific JNINativeMethod.fnPtr
|
||||
// will be set to nullptr.
|
||||
void hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods);
|
||||
|
||||
// Hook functions in the PLT (Procedure Linkage Table) of ELFs loaded in memory.
|
||||
//
|
||||
// Parsing /proc/[PID]/maps will give you the memory map of a process. As an example:
|
||||
//
|
||||
// <address> <perms> <offset> <dev> <inode> <pathname>
|
||||
// 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64
|
||||
// (More details: https://man7.org/linux/man-pages/man5/proc.5.html)
|
||||
//
|
||||
// The `dev` and `inode` pair uniquely identifies a file being mapped into memory.
|
||||
// For matching ELFs loaded in memory, replace function `symbol` with `newFunc`.
|
||||
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
|
||||
void pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc);
|
||||
|
||||
// Commit all the hooks that was previously registered.
|
||||
// Returns false if an error occurred.
|
||||
bool pltHookCommit();
|
||||
|
||||
private:
|
||||
internal::api_table *tbl;
|
||||
template <class T> friend void internal::entry_impl(internal::api_table *, JNIEnv *);
|
||||
};
|
||||
|
||||
// Register a class as a Zygisk module
|
||||
|
||||
#define REGISTER_ZYGISK_MODULE(clazz) \
|
||||
void zygisk_module_entry(zygisk::internal::api_table *table, JNIEnv *env) { \
|
||||
zygisk::internal::entry_impl<clazz>(table, env); \
|
||||
}
|
||||
|
||||
// Register a root companion request handler function for your module
|
||||
//
|
||||
// The function runs in a superuser daemon process and handles a root companion request from
|
||||
// your module running in a target process. The function has to accept an integer value,
|
||||
// which is a Unix domain socket that is connected to the target process.
|
||||
// See Api::connectCompanion() for more info.
|
||||
//
|
||||
// NOTE: the function can run concurrently on multiple threads.
|
||||
// Be aware of race conditions if you have globally shared resources.
|
||||
|
||||
#define REGISTER_ZYGISK_COMPANION(func) \
|
||||
void zygisk_companion_entry(int client) { func(client); }
|
||||
|
||||
/*********************************************************
|
||||
* The following is internal ABI implementation detail.
|
||||
* You do not have to understand what it is doing.
|
||||
*********************************************************/
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct module_abi {
|
||||
long api_version;
|
||||
ModuleBase *impl;
|
||||
|
||||
void (*preAppSpecialize)(ModuleBase *, AppSpecializeArgs *);
|
||||
void (*postAppSpecialize)(ModuleBase *, const AppSpecializeArgs *);
|
||||
void (*preServerSpecialize)(ModuleBase *, ServerSpecializeArgs *);
|
||||
void (*postServerSpecialize)(ModuleBase *, const ServerSpecializeArgs *);
|
||||
|
||||
module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), impl(module) {
|
||||
preAppSpecialize = [](auto m, auto args) { m->preAppSpecialize(args); };
|
||||
postAppSpecialize = [](auto m, auto args) { m->postAppSpecialize(args); };
|
||||
preServerSpecialize = [](auto m, auto args) { m->preServerSpecialize(args); };
|
||||
postServerSpecialize = [](auto m, auto args) { m->postServerSpecialize(args); };
|
||||
}
|
||||
};
|
||||
|
||||
struct api_table {
|
||||
// Base
|
||||
void *impl;
|
||||
bool (*registerModule)(api_table *, module_abi *);
|
||||
|
||||
void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int);
|
||||
void (*pltHookRegister)(dev_t, ino_t, const char *, void *, void **);
|
||||
bool (*exemptFd)(int);
|
||||
bool (*pltHookCommit)();
|
||||
int (*connectCompanion)(void * /* impl */);
|
||||
void (*setOption)(void * /* impl */, Option);
|
||||
int (*getModuleDir)(void * /* impl */);
|
||||
uint32_t (*getFlags)(void * /* impl */);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void entry_impl(api_table *table, JNIEnv *env) {
|
||||
static Api api;
|
||||
api.tbl = table;
|
||||
static T module;
|
||||
ModuleBase *m = &module;
|
||||
static module_abi abi(m);
|
||||
if (!table->registerModule(table, &abi)) return;
|
||||
m->onLoad(&api, env);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
inline int Api::connectCompanion() {
|
||||
return tbl->connectCompanion ? tbl->connectCompanion(tbl->impl) : -1;
|
||||
}
|
||||
inline int Api::getModuleDir() {
|
||||
return tbl->getModuleDir ? tbl->getModuleDir(tbl->impl) : -1;
|
||||
}
|
||||
inline void Api::setOption(Option opt) {
|
||||
if (tbl->setOption) tbl->setOption(tbl->impl, opt);
|
||||
}
|
||||
inline uint32_t Api::getFlags() {
|
||||
return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0;
|
||||
}
|
||||
inline bool Api::exemptFd(int fd) {
|
||||
return tbl->exemptFd != nullptr && tbl->exemptFd(fd);
|
||||
}
|
||||
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
||||
if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods);
|
||||
}
|
||||
inline void Api::pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc) {
|
||||
if (tbl->pltHookRegister) tbl->pltHookRegister(dev, inode, symbol, newFunc, oldFunc);
|
||||
}
|
||||
inline bool Api::pltHookCommit() {
|
||||
return tbl->pltHookCommit != nullptr && tbl->pltHookCommit();
|
||||
}
|
||||
|
||||
} // namespace zygisk
|
||||
|
||||
extern "C" {
|
||||
|
||||
[[gnu::visibility("default"), maybe_unused]]
|
||||
void zygisk_module_entry(zygisk::internal::api_table *, JNIEnv *);
|
||||
|
||||
[[gnu::visibility("default"), maybe_unused]]
|
||||
void zygisk_companion_entry(int);
|
||||
|
||||
} // extern "C"
|
||||
190
module/template/META-INF/com/google/android/update-binary
Normal file
190
module/template/META-INF/com/google/android/update-binary
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/sbin/sh
|
||||
|
||||
#################
|
||||
# Initialization
|
||||
#################
|
||||
|
||||
umask 022
|
||||
|
||||
# echo before loading util_functions
|
||||
ui_print() { echo "$1"; }
|
||||
|
||||
require_new_magisk() {
|
||||
ui_print "*******************************"
|
||||
ui_print " Please install Magisk v19.0+! "
|
||||
ui_print "*******************************"
|
||||
exit 1
|
||||
}
|
||||
|
||||
#########################
|
||||
# Load util_functions.sh
|
||||
#########################
|
||||
|
||||
OUTFD=$2
|
||||
ZIPFILE=$3
|
||||
|
||||
mount /data 2>/dev/null
|
||||
|
||||
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
|
||||
. /data/adb/magisk/util_functions.sh
|
||||
[ $MAGISK_VER_CODE -lt 19000 ] && require_new_magisk
|
||||
|
||||
if [ $MAGISK_VER_CODE -ge 20400 ]; then
|
||||
# New Magisk have complete installation logic within util_functions.sh
|
||||
install_module
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#################
|
||||
# Legacy Support
|
||||
#################
|
||||
|
||||
TMPDIR=/dev/tmp
|
||||
PERSISTDIR=/sbin/.magisk/mirror/persist
|
||||
|
||||
is_legacy_script() {
|
||||
unzip -l "$ZIPFILE" install.sh | grep -q install.sh
|
||||
return $?
|
||||
}
|
||||
|
||||
print_modname() {
|
||||
local len
|
||||
len=`echo -n $MODNAME | wc -c`
|
||||
len=$((len + 2))
|
||||
local pounds=`printf "%${len}s" | tr ' ' '*'`
|
||||
ui_print "$pounds"
|
||||
ui_print " $MODNAME "
|
||||
ui_print "$pounds"
|
||||
ui_print "*******************"
|
||||
ui_print " Powered by Magisk "
|
||||
ui_print "*******************"
|
||||
}
|
||||
|
||||
# Override abort as old scripts have some issues
|
||||
abort() {
|
||||
ui_print "$1"
|
||||
$BOOTMODE || recovery_cleanup
|
||||
[ -n $MODPATH ] && rm -rf $MODPATH
|
||||
rm -rf $TMPDIR
|
||||
exit 1
|
||||
}
|
||||
|
||||
rm -rf $TMPDIR 2>/dev/null
|
||||
mkdir -p $TMPDIR
|
||||
|
||||
# Preperation for flashable zips
|
||||
setup_flashable
|
||||
|
||||
# Mount partitions
|
||||
mount_partitions
|
||||
|
||||
# Detect version and architecture
|
||||
api_level_arch_detect
|
||||
|
||||
# Setup busybox and binaries
|
||||
$BOOTMODE && boot_actions || recovery_actions
|
||||
|
||||
##############
|
||||
# Preparation
|
||||
##############
|
||||
|
||||
# Extract prop file
|
||||
unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
|
||||
[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!"
|
||||
|
||||
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
|
||||
MODULEROOT=$NVBASE/$MODDIRNAME
|
||||
MODID=`grep_prop id $TMPDIR/module.prop`
|
||||
MODPATH=$MODULEROOT/$MODID
|
||||
MODNAME=`grep_prop name $TMPDIR/module.prop`
|
||||
|
||||
# Create mod paths
|
||||
rm -rf $MODPATH 2>/dev/null
|
||||
mkdir -p $MODPATH
|
||||
|
||||
##########
|
||||
# Install
|
||||
##########
|
||||
|
||||
if is_legacy_script; then
|
||||
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
|
||||
|
||||
# Load install script
|
||||
. $TMPDIR/install.sh
|
||||
|
||||
# Callbacks
|
||||
print_modname
|
||||
on_install
|
||||
|
||||
# Custom uninstaller
|
||||
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
|
||||
|
||||
# Skip mount
|
||||
$SKIPMOUNT && touch $MODPATH/skip_mount
|
||||
|
||||
# prop file
|
||||
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
|
||||
|
||||
# Module info
|
||||
cp -af $TMPDIR/module.prop $MODPATH/module.prop
|
||||
|
||||
# post-fs-data scripts
|
||||
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
|
||||
|
||||
# service scripts
|
||||
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
|
||||
|
||||
ui_print "- Setting permissions"
|
||||
set_permissions
|
||||
else
|
||||
print_modname
|
||||
|
||||
unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
|
||||
|
||||
if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
|
||||
ui_print "- Extracting module files"
|
||||
unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
|
||||
|
||||
# Default permissions
|
||||
set_perm_recursive $MODPATH 0 0 0755 0644
|
||||
fi
|
||||
|
||||
# Load customization script
|
||||
[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
|
||||
fi
|
||||
|
||||
# Handle replace folders
|
||||
for TARGET in $REPLACE; do
|
||||
ui_print "- Replace target: $TARGET"
|
||||
mktouch $MODPATH$TARGET/.replace
|
||||
done
|
||||
|
||||
if $BOOTMODE; then
|
||||
# Update info for Magisk Manager
|
||||
mktouch $NVBASE/modules/$MODID/update
|
||||
cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop
|
||||
fi
|
||||
|
||||
# Copy over custom sepolicy rules
|
||||
if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then
|
||||
ui_print "- Installing custom sepolicy patch"
|
||||
PERSISTMOD=$PERSISTDIR/magisk/$MODID
|
||||
mkdir -p $PERSISTMOD
|
||||
cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule
|
||||
fi
|
||||
|
||||
# Remove stuffs that don't belong to modules
|
||||
rm -rf \
|
||||
$MODPATH/system/placeholder $MODPATH/customize.sh \
|
||||
$MODPATH/README.md $MODPATH/.git* 2>/dev/null
|
||||
|
||||
#############
|
||||
# Finalizing
|
||||
#############
|
||||
|
||||
cd /
|
||||
$BOOTMODE || recovery_cleanup
|
||||
rm -rf $TMPDIR
|
||||
|
||||
ui_print "- Done"
|
||||
exit 0
|
||||
@@ -0,0 +1 @@
|
||||
#MAGISK
|
||||
85
module/template/customize.sh
Normal file
85
module/template/customize.sh
Normal file
@@ -0,0 +1,85 @@
|
||||
# shellcheck disable=SC2034
|
||||
SKIPUNZIP=1
|
||||
|
||||
DEBUG=@DEBUG@
|
||||
SONAME=@SONAME@
|
||||
SUPPORTED_ABIS="@SUPPORTED_ABIS@"
|
||||
|
||||
if [ "$BOOTMODE" ] && [ "$KSU" ]; then
|
||||
ui_print "- Installing from KernelSU app"
|
||||
ui_print "- KernelSU version: $KSU_KERNEL_VER_CODE (kernel) + $KSU_VER_CODE (ksud)"
|
||||
if [ "$(which magisk)" ]; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Multiple root implementation is NOT supported!"
|
||||
ui_print "! Please uninstall Magisk before installing Zygisk Next"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
elif [ "$BOOTMODE" ] && [ "$MAGISK_VER_CODE" ]; then
|
||||
ui_print "- Installing from Magisk app"
|
||||
else
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Install from recovery is not supported"
|
||||
ui_print "! Please install from KernelSU or Magisk app"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
|
||||
VERSION=$(grep_prop version "${TMPDIR}/module.prop")
|
||||
ui_print "- Installing $SONAME $VERSION"
|
||||
|
||||
# check architecture
|
||||
support=false
|
||||
for abi in $SUPPORTED_ABIS
|
||||
do
|
||||
if [ "$ARCH" == "$abi" ]; then
|
||||
support=true
|
||||
fi
|
||||
done
|
||||
if [ "$support" == "false" ]; then
|
||||
abort "! Unsupported platform: $ARCH"
|
||||
else
|
||||
ui_print "- Device platform: $ARCH"
|
||||
fi
|
||||
|
||||
ui_print "- Extracting verify.sh"
|
||||
unzip -o "$ZIPFILE" 'verify.sh' -d "$TMPDIR" >&2
|
||||
if [ ! -f "$TMPDIR/verify.sh" ]; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Unable to extract verify.sh!"
|
||||
ui_print "! This zip may be corrupted, please try downloading again"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
. "$TMPDIR/verify.sh"
|
||||
extract "$ZIPFILE" 'customize.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'verify.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
|
||||
|
||||
ui_print "- Extracting module files"
|
||||
extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
||||
extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH"
|
||||
extract "$ZIPFILE" 'service.sh' "$MODPATH"
|
||||
mv "$TMPDIR/sepolicy.rule" "$MODPATH"
|
||||
|
||||
HAS32BIT=false && [ $(getprop ro.product.cpu.abilist32) ] && HAS32BIT=true
|
||||
|
||||
mkdir "$MODPATH/zygisk"
|
||||
|
||||
if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then
|
||||
if [ "$HAS32BIT" = true ]; then
|
||||
ui_print "- Extracting x86 libraries"
|
||||
extract "$ZIPFILE" "lib/x86/lib$SONAME.so" "$MODPATH/zygisk/" true
|
||||
mv "$MODPATH/zygisk/lib$SONAME.so" "$MODPATH/zygisk/x86.so"
|
||||
fi
|
||||
|
||||
ui_print "- Extracting x64 libraries"
|
||||
extract "$ZIPFILE" "lib/x86_64/lib$SONAME.so" "$MODPATH/zygisk" true
|
||||
mv "$MODPATH/zygisk/lib$SONAME.so" "$MODPATH/zygisk/x86_64.so"
|
||||
else
|
||||
if [ "$HAS32BIT" = true ]; then
|
||||
extract "$ZIPFILE" "lib/armeabi-v7a/lib$SONAME.so" "$MODPATH/zygisk" true
|
||||
mv "$MODPATH/zygisk/lib$SONAME.so" "$MODPATH/zygisk/armeabi-v7a.so"
|
||||
fi
|
||||
|
||||
ui_print "- Extracting arm64 libraries"
|
||||
extract "$ZIPFILE" "lib/arm64-v8a/lib$SONAME.so" "$MODPATH/zygisk" true
|
||||
mv "$MODPATH/zygisk/lib$SONAME.so" "$MODPATH/zygisk/arm64-v8a.so"
|
||||
fi
|
||||
7
module/template/module.prop
Normal file
7
module/template/module.prop
Normal file
@@ -0,0 +1,7 @@
|
||||
id=${moduleId}
|
||||
name=${moduleName}
|
||||
version=${versionName}
|
||||
versionCode=${versionCode}
|
||||
author=5ec1cff
|
||||
description=Module sample
|
||||
#updateJson=
|
||||
1
module/template/post-fs-data.sh
Normal file
1
module/template/post-fs-data.sh
Normal file
@@ -0,0 +1 @@
|
||||
MODDIR=${0%/*}
|
||||
0
module/template/sepolicy.rule
Normal file
0
module/template/sepolicy.rule
Normal file
3
module/template/service.sh
Normal file
3
module/template/service.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
DEBUG=@DEBUG@
|
||||
|
||||
MODDIR=${0%/*}
|
||||
51
module/template/verify.sh
Normal file
51
module/template/verify.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
TMPDIR_FOR_VERIFY="$TMPDIR/.vunzip"
|
||||
mkdir "$TMPDIR_FOR_VERIFY"
|
||||
|
||||
abort_verify() {
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! $1"
|
||||
ui_print "! This zip may be corrupted, please try downloading again"
|
||||
abort "*********************************************************"
|
||||
}
|
||||
|
||||
# extract <zip> <file> <target dir> <junk paths>
|
||||
extract() {
|
||||
zip=$1
|
||||
file=$2
|
||||
dir=$3
|
||||
junk_paths=$4
|
||||
[ -z "$junk_paths" ] && junk_paths=false
|
||||
opts="-o"
|
||||
[ $junk_paths = true ] && opts="-oj"
|
||||
|
||||
file_path=""
|
||||
hash_path=""
|
||||
if [ $junk_paths = true ]; then
|
||||
file_path="$dir/$(basename "$file")"
|
||||
hash_path="$TMPDIR_FOR_VERIFY/$(basename "$file").sha256"
|
||||
else
|
||||
file_path="$dir/$file"
|
||||
hash_path="$TMPDIR_FOR_VERIFY/$file.sha256"
|
||||
fi
|
||||
|
||||
unzip $opts "$zip" "$file" -d "$dir" >&2
|
||||
[ -f "$file_path" ] || abort_verify "$file not exists"
|
||||
|
||||
unzip $opts "$zip" "$file.sha256" -d "$TMPDIR_FOR_VERIFY" >&2
|
||||
[ -f "$hash_path" ] || abort_verify "$file.sha256 not exists"
|
||||
|
||||
(echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
|
||||
ui_print "- Verified $file" >&1
|
||||
}
|
||||
|
||||
file="META-INF/com/google/android/update-binary"
|
||||
file_path="$TMPDIR_FOR_VERIFY/$file"
|
||||
hash_path="$file_path.sha256"
|
||||
unzip -o "$ZIPFILE" "META-INF/com/google/android/*" -d "$TMPDIR_FOR_VERIFY" >&2
|
||||
[ -f "$file_path" ] || abort_verify "$file not exists"
|
||||
if [ -f "$hash_path" ]; then
|
||||
(echo "$(cat "$hash_path") $file_path" | sha256sum -c -s -) || abort_verify "Failed to verify $file"
|
||||
ui_print "- Verified $file" >&1
|
||||
else
|
||||
ui_print "- Download from Magisk app"
|
||||
fi
|
||||
20
settings.gradle.kts
Normal file
20
settings.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "TrickyStore"
|
||||
include(
|
||||
":module"
|
||||
)
|
||||
Reference in New Issue
Block a user