diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e589..41dfb87 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 2a6ce83..fa33063 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -34,6 +34,13 @@ android { buildFeatures { prefab = true + prefabPublishing = true + } + + prefab { + create("lsplant") { + headers = "jni/include" + } } defaultConfig { diff --git a/settings.gradle.kts b/settings.gradle.kts index 3839100..82f2921 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,4 +9,5 @@ dependencyResolutionManagement { rootProject.name = "LSPlant" include( ":library", + ":test" ) diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/test/build.gradle.kts b/test/build.gradle.kts new file mode 100644 index 0000000..382f4f0 --- /dev/null +++ b/test/build.gradle.kts @@ -0,0 +1,57 @@ +plugins { + id("com.android.application") +} + +val androidTargetSdkVersion: Int by rootProject.extra +val androidMinSdkVersion: Int by rootProject.extra +val androidBuildToolsVersion: String by rootProject.extra +val androidCompileSdkVersion: Int by rootProject.extra +val androidCompileNdkVersion: String by rootProject.extra + +android { + namespace = "org.lsposed.lsplant.test" + compileSdk = androidCompileSdkVersion + ndkVersion = androidCompileNdkVersion + buildToolsVersion = androidBuildToolsVersion + + buildFeatures { + prefab = true + } + + defaultConfig { + applicationId = "org.lsposed.lsplant.test" + minSdk = androidMinSdkVersion + targetSdk = androidTargetSdkVersion + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner" + } + + externalNativeBuild { + cmake { + path("src/main/jni/CMakeLists.txt") + } + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} + +dependencies { + implementation(project(":library")) + implementation("io.github.vvb2060.ndk:dobby:1.2") + + testImplementation("junit:junit:4.13.2") + androidTestImplementation("com.android.support.test:runner:1.0.2") + androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2") +} diff --git a/test/proguard-rules.pro b/test/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/test/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/test/src/androidTest/java/org/lsposed/lsplant/UnitTest.java b/test/src/androidTest/java/org/lsposed/lsplant/UnitTest.java new file mode 100644 index 0000000..72d7063 --- /dev/null +++ b/test/src/androidTest/java/org/lsposed/lsplant/UnitTest.java @@ -0,0 +1,17 @@ +package org.lsposed.lsplant; + +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class UnitTest { + + @Test + public void initTest() { + boolean result = LSPTest.initHooker(); + Assert.assertTrue(result); + } +} diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b51b00f --- /dev/null +++ b/test/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/test/src/main/java/org/lsposed/lsplant/LSPTest.java b/test/src/main/java/org/lsposed/lsplant/LSPTest.java new file mode 100644 index 0000000..84dc323 --- /dev/null +++ b/test/src/main/java/org/lsposed/lsplant/LSPTest.java @@ -0,0 +1,10 @@ +package org.lsposed.lsplant; + +public class LSPTest { + + static { + System.loadLibrary("test"); + } + + native static boolean initHooker(); +} diff --git a/test/src/main/jni/CMakeLists.txt b/test/src/main/jni/CMakeLists.txt new file mode 100644 index 0000000..cc4d2d6 --- /dev/null +++ b/test/src/main/jni/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.18.1) +project("lsplant_test") + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_library(test SHARED test.cpp) +find_package(dobby REQUIRED CONFIG) +find_package(library REQUIRED CONFIG) +target_link_libraries(test log dobby::dobby library::lsplant) diff --git a/test/src/main/jni/test.cpp b/test/src/main/jni/test.cpp new file mode 100644 index 0000000..9cb4493 --- /dev/null +++ b/test/src/main/jni/test.cpp @@ -0,0 +1,55 @@ +#include +#include +#include + +#define _uintval(p) reinterpret_cast(p) +#define _ptr(p) reinterpret_cast(p) +#define _align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) +#define _align_down(x, n) ((x) & -(n)) +#define _page_size 4096 +#define _page_align(n) _align_up(static_cast(n), _page_size) +#define _ptr_align(x) _ptr(_align_down(reinterpret_cast(x), _page_size)) +#define _make_rwx(p, n) ::mprotect(_ptr_align(p), \ + _page_align(_uintval(p) + n) != _page_align(_uintval(p)) ? _page_align(n) + _page_size : _page_align(n), \ + PROT_READ | PROT_WRITE | PROT_EXEC) + +bool init_result; + +void* InlineHooker(void* target, void* hooker) { + _make_rwx(target, _page_size); + void* origin_call; + if (DobbyHook(target, hooker, &origin_call) == RS_SUCCESS) { + return origin_call; + } else { + return nullptr; + } +} + +bool InlineUnhooker(void* func) { + return DobbyDestroy(func) == RT_SUCCESS; +} + +void* ArtSymbolResolver(std::string_view symbol_name) { + return DobbySymbolResolver("libart.so", symbol_name.data()); +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_org_lsposed_lsplant_LSPTest_initHooker(JNIEnv*, jclass) { + return init_result; +} + +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + lsplant::InitInfo initInfo{ + .inline_hooker = InlineHooker, + .inline_unhooker = InlineUnhooker, + .art_symbol_resolver = ArtSymbolResolver + }; + init_result = lsplant::Init(env, initInfo); + return JNI_VERSION_1_6; +}