commit f1939a648402f9ec6ba216aef44cf729f19f2092 Author: 5ec1cff <56485584+5ec1cff@users.noreply.github.com> Date: Wed Jul 10 15:06:31 2024 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..10cfdbf --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +/local.properties +/.idea +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..598021a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "module/src/main/cpp/external/libcxx"] + path = module/src/main/cpp/external/libcxx + url = https://github.com/topjohnwu/libcxx diff --git a/README.md b/README.md new file mode 100644 index 0000000..213be36 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Tricky Store + +A trick of keystore. diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..570c9c5 --- /dev/null +++ b/build.gradle.kts @@ -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 + } + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..01b80d7 --- /dev/null +++ b/gradle.properties @@ -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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..6a3a176 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,5 @@ +[versions] +agp = "8.5.0" + +[plugins] +agp-app = { id = "com.android.application", version.ref = "agp" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..91900bd --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -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" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -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 diff --git a/module/.gitignore b/module/.gitignore new file mode 100644 index 0000000..5bf6fda --- /dev/null +++ b/module/.gitignore @@ -0,0 +1,4 @@ +/build +/libs +/obj +/release diff --git a/module/build.gradle.kts b/module/build.gradle.kts new file mode 100644 index 0000000..d8d0614 --- /dev/null +++ b/module/build.gradle.kts @@ -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 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("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("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("tokens" to tokens) + filter("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$variantCapped") { + group = "module" + dependsOn(prepareModuleFilesTask) + archiveFileName.set(zipFileName) + destinationDirectory.set(layout.projectDirectory.file("release").asFile) + from(moduleDir) + } + + val pushTask = task("push$variantCapped") { + group = "module" + dependsOn(zipTask) + commandLine("adb", "push", zipTask.outputs.files.singleFile.path, "/data/local/tmp") + } + + val installKsuTask = task("installKsu$variantCapped") { + group = "module" + dependsOn(pushTask) + commandLine( + "adb", "shell", "su", "-c", + "/data/adb/ksud module install /data/local/tmp/$zipFileName" + ) + } + + val installMagiskTask = task("installMagisk$variantCapped") { + group = "module" + dependsOn(pushTask) + commandLine( + "adb", + "shell", + "su", + "-M", + "-c", + "magisk --install-module /data/local/tmp/$zipFileName" + ) + } + + task("installKsuAndReboot$variantCapped") { + group = "module" + dependsOn(installKsuTask) + commandLine("adb", "reboot") + } + + task("installMagiskAndReboot$variantCapped") { + group = "module" + dependsOn(installMagiskTask) + commandLine("adb", "reboot") + } + } +} diff --git a/module/src/main/AndroidManifest.xml b/module/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5c3d365 --- /dev/null +++ b/module/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/module/src/main/cpp/CMakeLists.txt b/module/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..57788c2 --- /dev/null +++ b/module/src/main/cpp/CMakeLists.txt @@ -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) diff --git a/module/src/main/cpp/binder/include/binder/Binder.h b/module/src/main/cpp/binder/include/binder/Binder.h new file mode 100644 index 0000000..65f3419 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/Binder.h @@ -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 +#include +#include +#include + +// --------------------------------------------------------------------------- +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& 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& recipient, + void* cookie = nullptr, uint32_t flags = 0); + + // NOLINTNEXTLINE(google-default-arguments) + LIBBINDER_EXPORTED virtual status_t unlinkToDeath(const wp& recipient, + void* cookie = nullptr, uint32_t flags = 0, + wp* 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& 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 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& 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 remoteStrong() const { + return sp::fromExisting(mRemote); + } + + private: + BpRefBase(const BpRefBase& o); + BpRefBase& operator=(const BpRefBase& o); + + IBinder* const mRemote; + RefBase::weakref_type* mRefs; + std::atomic mState; + }; + +} // namespace android + +// --------------------------------------------------------------------------- \ No newline at end of file diff --git a/module/src/main/cpp/binder/include/binder/BpBinder.h b/module/src/main/cpp/binder/include/binder/BpBinder.h new file mode 100644 index 0000000..bceedd7 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/BpBinder.h @@ -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; +} diff --git a/module/src/main/cpp/binder/include/binder/Common.h b/module/src/main/cpp/binder/include/binder/Common.h new file mode 100644 index 0000000..a920077 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/Common.h @@ -0,0 +1,2 @@ +#pragma once +#define LIBBINDER_EXPORTED __attribute__((__visibility__("default"))) diff --git a/module/src/main/cpp/binder/include/binder/IBinder.h b/module/src/main/cpp/binder/include/binder/IBinder.h new file mode 100644 index 0000000..2727eca --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/IBinder.h @@ -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 +#include +#include +#include +#include +#include + +#include + +// 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 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& 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& 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& 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& recipient, + void* cookie = nullptr, + uint32_t flags = 0, + wp* 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& doWithLock); + + virtual BBinder* localBinder(); + virtual BpBinder* remoteBinder(); + + protected: + virtual ~IBinder(); + + private: +}; + +} // namespace android + +// --------------------------------------------------------------------------- diff --git a/module/src/main/cpp/binder/include/binder/IInterface.h b/module/src/main/cpp/binder/include/binder/IInterface.h new file mode 100644 index 0000000..8de9677 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/IInterface.h @@ -0,0 +1,9 @@ +#pragma once + +#include "utils/RefBase.h" + +namespace android { + class IInterface : public virtual RefBase { + + }; +} diff --git a/module/src/main/cpp/binder/include/binder/IPCThreadState.h b/module/src/main/cpp/binder/include/binder/IPCThreadState.h new file mode 100644 index 0000000..e8685e5 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/IPCThreadState.h @@ -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 +#include +#include +#include + +// --------------------------------------------------------------------------- +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 + +// --------------------------------------------------------------------------- \ No newline at end of file diff --git a/module/src/main/cpp/binder/include/binder/Parcel.h b/module/src/main/cpp/binder/include/binder/Parcel.h new file mode 100644 index 0000000..d4cfe5b --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/Parcel.h @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include // for legacy reasons +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +//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& 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 readStrongBinder() const; + LIBBINDER_EXPORTED status_t readStrongBinder(sp* val) const; + LIBBINDER_EXPORTED status_t readNullableStrongBinder(sp* 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 mVariantFields; + + // Pointer to KernelFields in mVariantFields if present. + KernelFields* maybeKernelFields() { return std::get_if(&mVariantFields); } + const KernelFields* maybeKernelFields() const { + return std::get_if(&mVariantFields); + } + // Pointer to RpcFields in mVariantFields if present. + RpcFields* maybeRpcFields() { return std::get_if(&mVariantFields); } + const RpcFields* maybeRpcFields() const { return std::get_if(&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 + +// --------------------------------------------------------------------------- \ No newline at end of file diff --git a/module/src/main/cpp/binder/include/binder/unique_fd.h b/module/src/main/cpp/binder/include/binder/unique_fd.h new file mode 100644 index 0000000..29bf927 --- /dev/null +++ b/module/src/main/cpp/binder/include/binder/unique_fd.h @@ -0,0 +1,5 @@ +#pragma once + +namespace android::binder { + class unique_fd; +} diff --git a/module/src/main/cpp/binder/include/utils/Errors.h b/module/src/main/cpp/binder/include/utils/Errors.h new file mode 100644 index 0000000..4e41277 --- /dev/null +++ b/module/src/main/cpp/binder/include/utils/Errors.h @@ -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 +#include +#include +#include + +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 diff --git a/module/src/main/cpp/binder/include/utils/RefBase.h b/module/src/main/cpp/binder/include/utils/RefBase.h new file mode 100644 index 0000000..6fdd497 --- /dev/null +++ b/module/src/main/cpp/binder/include/utils/RefBase.h @@ -0,0 +1,487 @@ +#ifndef ANDROID_REF_BASE_H +#define ANDROID_REF_BASE_H + +#include +#include +#include +#include // for common_type. + +#include +#include +#include +#include + +// LightRefBase used to be declared in this header, so we have to include it +// #include + +#include +// #include + +// --------------------------------------------------------------------------- +namespace android { + +// --------------------------------------------------------------------------- + +#define COMPARE_WEAK(_op_) \ +template \ +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 class comparator, typename T, typename U> + static inline bool _wp_compare_(T* a, U* b) { + return comparator::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 \ +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 + 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 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 + wp(U* other); // NOLINT(implicit) + wp& operator=(T* other); + template + wp& operator=(U* other); +#endif + + wp(const wp& other); + explicit wp(const sp& other); + + template wp(const sp& other); // NOLINT(implicit) + template wp(const wp& other); // NOLINT(implicit) + + ~wp(); + + // Assignment + + wp& operator = (const wp& other); + wp& operator = (const sp& other); + + template wp& operator = (const wp& other); + template wp& operator = (const sp& other); + + void set_object_and_refs(T* other, weakref_type* refs); + + // promotion to sp + + sp 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 + inline bool operator == (const wp& o) const { + return m_refs == o.m_refs; // Implies m_ptr == o.mptr; see invariants below. + } + + template + inline bool operator == (const sp& 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 + inline bool operator != (const sp& o) const { + return !(*this == o); + } + + template + inline bool operator > (const wp& o) const { + if (m_ptr == o.m_ptr) { + return _wp_compare_(m_refs, o.m_refs); + } else { + return _wp_compare_(m_ptr, o.m_ptr); + } + } + + template + inline bool operator < (const wp& o) const { + if (m_ptr == o.m_ptr) { + return _wp_compare_(m_refs, o.m_refs); + } else { + return _wp_compare_(m_ptr, o.m_ptr); + } + } + template inline bool operator != (const wp& o) const { return !operator == (o); } + template inline bool operator <= (const wp& o) const { return !operator > (o); } + template inline bool operator >= (const wp& o) const { return !operator < (o); } + + private: + template friend class sp; + template 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 + wp wp::fromExisting(T* other) { + if (!other) return nullptr; + + auto refs = other->getWeakRefs(); + refs->incWeakRequireWeak(other); + + wp ret; + ret.m_ptr = other; + ret.m_refs = refs; + return ret; + } + +#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION) + template + wp::wp(T* other) + : m_ptr(other) + { + m_refs = other ? m_refs = other->createWeak(this) : nullptr; + } + + template + template + wp::wp(U* other) : m_ptr(other) { + m_refs = other ? other->createWeak(this) : nullptr; + } + + template + wp& wp::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 + template + wp& wp::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 + wp::wp(const wp& other) + : m_ptr(other.m_ptr), m_refs(other.m_refs) + { + if (m_ptr) m_refs->incWeak(this); + } + + template + wp::wp(const sp& other) + : m_ptr(other.m_ptr) + { + m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr; + } + + template template + wp::wp(const wp& other) + : m_ptr(other.m_ptr) + { + if (m_ptr) { + m_refs = other.m_refs; + m_refs->incWeak(this); + } else { + m_refs = nullptr; + } + } + + template template + wp::wp(const sp& other) + : m_ptr(other.m_ptr) + { + m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr; + } + + template + wp::~wp() + { + if (m_ptr) m_refs->decWeak(this); + } + + template + wp& wp::operator = (const wp& 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 + wp& wp::operator = (const sp& 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 template + wp& wp::operator = (const wp& 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 template + wp& wp::operator = (const sp& 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 + void wp::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 + sp wp::promote() const + { + sp result; + if (m_ptr && m_refs->attemptIncStrong(&result)) { + result.set_pointer(m_ptr); + } + return result; + } + + template + void wp::clear() + { + if (m_ptr) { + m_refs->decWeak(this); + m_refs = 0; + m_ptr = 0; + } + } + +} // namespace android + +namespace libutilsinternal { + template + struct is_complete_type : std::false_type {}; + + template + struct is_complete_type : 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::make(...)` instead. +// +// Note: We exclude incomplete types because `std::is_base_of` is undefined in +// that case. + + template ::value, bool>::value = true, + typename std::enable_if::value, bool>::value = true> + shared_ptr make_shared(Args...) { // SEE COMMENT ABOVE. + static_assert(!std::is_base_of::value, "Must use RefBase with sp<>"); + } + + template ::value, bool>::value = true, + typename std::enable_if::value, bool>::value = true> + unique_ptr make_unique(Args...) { // SEE COMMENT ABOVE. + static_assert(!std::is_base_of::value, "Must use RefBase with sp<>"); + } + +} // namespace std + +// --------------------------------------------------------------------------- + +#endif // ANDROID_REF_BASE_H \ No newline at end of file diff --git a/module/src/main/cpp/binder/include/utils/String16.h b/module/src/main/cpp/binder/include/utils/String16.h new file mode 100644 index 0000000..d8073d4 --- /dev/null +++ b/module/src/main/cpp/binder/include/utils/String16.h @@ -0,0 +1,6 @@ +#pragma once + +// TODO +namespace android { + class String16 {}; +} diff --git a/module/src/main/cpp/binder/include/utils/StrongPointer.h b/module/src/main/cpp/binder/include/utils/StrongPointer.h new file mode 100644 index 0000000..beab010 --- /dev/null +++ b/module/src/main/cpp/binder/include/utils/StrongPointer.h @@ -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 +#include // for common_type. + +// --------------------------------------------------------------------------- +namespace android { + + template class wp; + +// --------------------------------------------------------------------------- + + template + 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 = new Foo(...); // DO NOT DO THIS + // + // Instead, prefer to do this: + // + // sp foo = sp::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; + template + static inline sp 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 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 + sp(U* other); // NOLINT(implicit) + sp& operator=(T* other); + template + sp& operator=(U* other); +#endif + + sp(const sp& other); + sp(sp&& other) noexcept; + + template sp(const sp& other); // NOLINT(implicit) + template sp(sp&& 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 + static inline sp cast(const sp& other); + + ~sp(); + + // Assignment + + sp& operator = (const sp& other); + sp& operator=(sp&& other) noexcept; + + template sp& operator = (const sp& other); + template sp& operator = (sp&& 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 + inline bool operator == (const wp& o) const { + return o == *this; + } + + template + inline bool operator != (const wp& o) const { + return o != *this; + } + + private: + template friend class sp; + template friend class wp; + void set_pointer(T* ptr); + T* m_ptr; + }; + +#define COMPARE_STRONG(_op_) \ + template \ + static inline bool operator _op_(const sp& t, const sp& u) { \ + return t.get() _op_ u.get(); \ + } \ + template \ + static inline bool operator _op_(const T* t, const sp& u) { \ + return t _op_ u.get(); \ + } \ + template \ + static inline bool operator _op_(const sp& t, const U* u) { \ + return t.get() _op_ u; \ + } \ + template \ + static inline bool operator _op_(const sp& t, std::nullptr_t) { \ + return t.get() _op_ nullptr; \ + } \ + template \ + static inline bool operator _op_(std::nullptr_t, const sp& t) { \ + return nullptr _op_ t.get(); \ + } + + template