diff --git a/app/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java b/app/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java index b181800..e9d4f61 100644 --- a/app/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java +++ b/app/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java @@ -1,6 +1,7 @@ package org.lsposed.lspatch.loader; import static android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE; +import static org.lsposed.lspd.service.ConfigFileManager.loadModule; import android.app.ActivityThread; import android.app.Application; @@ -15,10 +16,7 @@ import android.os.Environment; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; -import android.os.SharedMemory; -import android.system.ErrnoException; import android.system.Os; -import android.system.OsConstants; import android.util.Log; import org.lsposed.lspatch.loader.util.FileUtils; @@ -27,19 +25,15 @@ import org.lsposed.lspatch.share.Constants; import org.lsposed.lspd.config.ApplicationServiceClient; import org.lsposed.lspd.core.Main; import org.lsposed.lspd.models.Module; -import org.lsposed.lspd.models.PreLoadedApk; import org.lsposed.lspd.nativebridge.SigBypass; -import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.nio.channels.Channels; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermissions; @@ -176,7 +170,8 @@ public class LSPApplication extends ApplicationServiceClient { public static void loadModules(Context context) { if (useManager) { try { - LSPApplication.modules.addAll(managerResolver.getModules()); + modules.addAll(managerResolver.getModules()); + modules.forEach(m -> Log.i(TAG, "Load module " + m.packageName + " from manager")); } catch (NullPointerException | RemoteException e) { Log.e(TAG, "Failed to get modules from manager", e); } @@ -202,7 +197,8 @@ public class LSPApplication extends ApplicationServiceClient { var module = new Module(); module.apkPath = cacheApkPath; module.packageName = packageName; - module.file = loadModule(context, cacheApkPath); + module.file = loadModule(cacheApkPath); + if (module.file != null) module.file.hostApk = context.getApplicationInfo().sourceDir; modules.add(module); } } catch (Throwable ignored) { @@ -210,61 +206,6 @@ public class LSPApplication extends ApplicationServiceClient { } } - private static void readDexes(ZipFile apkFile, List preLoadedDexes) { - int secondary = 2; - for (var dexFile = apkFile.getEntry("classes.dex"); dexFile != null; - dexFile = apkFile.getEntry("classes" + secondary + ".dex"), secondary++) { - try (var in = apkFile.getInputStream(dexFile)) { - var memory = SharedMemory.create(null, in.available()); - var byteBuffer = memory.mapReadWrite(); - Channels.newChannel(in).read(byteBuffer); - SharedMemory.unmap(byteBuffer); - memory.setProtect(OsConstants.PROT_READ); - preLoadedDexes.add(memory); - } catch (IOException | ErrnoException e) { - Log.w(TAG, "Can not load " + dexFile + " in " + apkFile, e); - } - } - } - - private static void readName(ZipFile apkFile, String initName, List names) { - var initEntry = apkFile.getEntry(initName); - if (initEntry == null) return; - try (var in = apkFile.getInputStream(initEntry)) { - var reader = new BufferedReader(new InputStreamReader(in)); - String name; - while ((name = reader.readLine()) != null) { - name = name.trim(); - if (name.isEmpty() || name.startsWith("#")) continue; - names.add(name); - } - } catch (IOException e) { - Log.e(TAG, "Can not open " + initEntry, e); - } - } - - private static PreLoadedApk loadModule(Context context, String path) { - var file = new PreLoadedApk(); - var preLoadedDexes = new ArrayList(); - var moduleClassNames = new ArrayList(1); - var moduleLibraryNames = new ArrayList(1); - try (var apkFile = new ZipFile(path)) { - readDexes(apkFile, preLoadedDexes); - readName(apkFile, "assets/xposed_init", moduleClassNames); - readName(apkFile, "assets/native_init", moduleLibraryNames); - } catch (IOException e) { - Log.e(TAG, "Can not open " + path, e); - return null; - } - if (preLoadedDexes.isEmpty()) return null; - if (moduleClassNames.isEmpty()) return null; - file.hostApk = context.getApplicationInfo().sourceDir; - file.preLoadedDexes = preLoadedDexes; - file.moduleClassNames = moduleClassNames; - file.moduleLibraryNames = moduleLibraryNames; - return file; - } - public LSPApplication() { super(); } diff --git a/app/src/main/java/org/lsposed/lspatch/loader/ManagerResolver.java b/app/src/main/java/org/lsposed/lspatch/loader/ManagerResolver.java index 4022dd4..ea553cc 100644 --- a/app/src/main/java/org/lsposed/lspatch/loader/ManagerResolver.java +++ b/app/src/main/java/org/lsposed/lspatch/loader/ManagerResolver.java @@ -1,6 +1,7 @@ package org.lsposed.lspatch.loader; -import android.content.ContentResolver; +import static org.lsposed.lspatch.share.Constants.MANAGER_PACKAGE_NAME; + import android.content.Context; import android.net.Uri; import android.os.Bundle; @@ -11,19 +12,19 @@ import org.lsposed.lspd.models.Module; import java.util.List; -public class ManagerResolver extends ContentResolver { - private static final String MANAGER_PACKAGE_NAME = "org.lsposed.lspatch"; - private static final Uri BINDER_URI = Uri.parse("content://" + MANAGER_PACKAGE_NAME + "/binder"); +public class ManagerResolver { + private static final Uri PROVIDER = Uri.parse("content://" + MANAGER_PACKAGE_NAME + ".provider"); private final IManagerService service; public ManagerResolver(Context context) throws RemoteException { - super(context); try { - Bundle back = call(BINDER_URI, "getBinder", null, null); + Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null); service = IManagerService.Stub.asInterface(back.getBinder("binder")); + if (service == null) throw new RemoteException("Binder is null"); } catch (Throwable t) { var e = new RemoteException("Failed to get manager binder"); + e.setStackTrace(new StackTraceElement[0]); e.addSuppressed(t); throw e; } diff --git a/build.gradle b/build.gradle index 73692c3..061482f 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:7.1.0-alpha11' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30' } } diff --git a/core b/core index f955755..6b4c519 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f955755ac40134f1b0a858f4e7df3b4a4eec78a8 +Subproject commit 6b4c519cf1b0d1ada03c9f39e27c3a0971b47f9e diff --git a/manager/.gitignore b/manager/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/manager/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/manager/build.gradle b/manager/build.gradle new file mode 100644 index 0000000..a253de1 --- /dev/null +++ b/manager/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk 31 + + defaultConfig { + applicationId "org.lsposed.lspatch" + minSdk 27 + targetSdk 31 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + buildFeatures { + viewBinding = true + } +} + +dependencies { + implementation project(":imanager") + implementation project(path: ':lspcore') + + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' +} \ No newline at end of file diff --git a/manager/proguard-rules.pro b/manager/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/manager/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/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9442ab6 --- /dev/null +++ b/manager/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt new file mode 100644 index 0000000..0102924 --- /dev/null +++ b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt @@ -0,0 +1,16 @@ +package org.lsposed.lspatch + +import android.app.Application +import android.content.Context + +class LSPApplication : Application() { + companion object { + const val TAG = "LSPatch Manager" + lateinit var appContext: Context + } + + override fun onCreate() { + super.onCreate() + appContext = applicationContext + } +} \ No newline at end of file diff --git a/manager/src/main/java/org/lsposed/lspatch/ManagerServiceImpl.kt b/manager/src/main/java/org/lsposed/lspatch/ManagerServiceImpl.kt new file mode 100644 index 0000000..16ca1d6 --- /dev/null +++ b/manager/src/main/java/org/lsposed/lspatch/ManagerServiceImpl.kt @@ -0,0 +1,10 @@ +package org.lsposed.lspatch + +import org.lsposed.lspatch.manager.IManagerService +import org.lsposed.lspd.models.Module + +class ManagerServiceImpl : IManagerService.Stub() { + override fun getModules(): List { + return ModuleProvider.allModules + } +} \ No newline at end of file diff --git a/manager/src/main/java/org/lsposed/lspatch/ModuleProvider.kt b/manager/src/main/java/org/lsposed/lspatch/ModuleProvider.kt new file mode 100644 index 0000000..c279ec3 --- /dev/null +++ b/manager/src/main/java/org/lsposed/lspatch/ModuleProvider.kt @@ -0,0 +1,73 @@ +package org.lsposed.lspatch + +import android.content.ContentProvider +import android.content.ContentValues +import android.content.pm.PackageManager +import android.database.Cursor +import android.net.Uri +import android.os.Binder +import android.os.Bundle +import android.util.Log +import org.lsposed.lspatch.LSPApplication.Companion.TAG +import org.lsposed.lspd.models.Module +import org.lsposed.lspd.service.ConfigFileManager.loadModule + +class ModuleProvider : ContentProvider() { + companion object { + lateinit var allModules: List + } + + override fun onCreate(): Boolean { + return false + } + + override fun call(method: String, arg: String?, extras: Bundle?): Bundle { + val app = context!!.packageManager.getNameForUid(Binder.getCallingUid()) + Log.d(TAG, "$app calls binder") + when (method) { + "getBinder" -> { + loadAllModules() + return Bundle().apply { + putBinder("binder", ManagerServiceImpl()) + } + } + else -> throw IllegalArgumentException("Invalid method name") + } + } + + private fun loadAllModules() { + val list = mutableListOf() + for (pkg in context!!.packageManager.getInstalledPackages(PackageManager.GET_META_DATA)) { + val app = pkg.applicationInfo ?: continue + if (app.metaData != null && app.metaData.containsKey("xposedminversion")) { + Module().apply { + apkPath = app.publicSourceDir + packageName = app.packageName + file = loadModule(apkPath) + }.also { list.add(it) } + Log.d(TAG, "send module ${app.packageName}") + } + } + allModules = list + } + + override fun query(p0: Uri, p1: Array?, p2: String?, p3: Array?, p4: String?): Cursor? { + return null + } + + override fun getType(p0: Uri): String? { + return null + } + + override fun insert(p0: Uri, p1: ContentValues?): Uri? { + return null + } + + override fun delete(p0: Uri, p1: String?, p2: Array?): Int { + return 0 + } + + override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array?): Int { + return 0 + } +} \ No newline at end of file diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/MainActivity.kt b/manager/src/main/java/org/lsposed/lspatch/ui/MainActivity.kt new file mode 100644 index 0000000..69764df --- /dev/null +++ b/manager/src/main/java/org/lsposed/lspatch/ui/MainActivity.kt @@ -0,0 +1,15 @@ +package org.lsposed.lspatch.ui + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import org.lsposed.lspatch.databinding.ActivityMainBinding + +class MainActivity : AppCompatActivity() { + lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + } +} \ No newline at end of file diff --git a/manager/src/main/res/drawable-v24/ic_launcher_foreground.xml b/manager/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/manager/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/manager/src/main/res/drawable/ic_launcher_background.xml b/manager/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/manager/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manager/src/main/res/layout/activity_main.xml b/manager/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..71f2583 --- /dev/null +++ b/manager/src/main/res/layout/activity_main.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/manager/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/manager/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/manager/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/manager/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/manager/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/manager/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/manager/src/main/res/mipmap-hdpi/ic_launcher.webp b/manager/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/manager/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/manager/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/manager/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/manager/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/manager/src/main/res/mipmap-mdpi/ic_launcher.webp b/manager/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/manager/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/manager/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/manager/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/manager/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/manager/src/main/res/mipmap-xhdpi/ic_launcher.webp b/manager/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/manager/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/manager/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/manager/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/manager/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/manager/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/manager/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/manager/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/manager/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/manager/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/manager/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/manager/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/manager/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/manager/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/manager/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/manager/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/manager/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/manager/src/main/res/values-night/themes.xml b/manager/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..7d77c56 --- /dev/null +++ b/manager/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/manager/src/main/res/values/colors.xml b/manager/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/manager/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/manager/src/main/res/values/strings.xml b/manager/src/main/res/values/strings.xml new file mode 100644 index 0000000..057f035 --- /dev/null +++ b/manager/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + LSPatch + \ No newline at end of file diff --git a/manager/src/main/res/values/themes.xml b/manager/src/main/res/values/themes.xml new file mode 100644 index 0000000..02a439c --- /dev/null +++ b/manager/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 98e80da..02de81d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,3 +16,4 @@ include ':share' include ':appstub' include ':apkzlib' include ':imanager' +include ':manager' diff --git a/share/src/main/java/org/lsposed/lspatch/share/Constants.java b/share/src/main/java/org/lsposed/lspatch/share/Constants.java index a6c676b..2a34610 100644 --- a/share/src/main/java/org/lsposed/lspatch/share/Constants.java +++ b/share/src/main/java/org/lsposed/lspatch/share/Constants.java @@ -1,6 +1,7 @@ package org.lsposed.lspatch.share; public class Constants { + final static public String MANAGER_PACKAGE_NAME = "org.lsposed.lspatch"; final static public String CONFIG_NAME_SIGBYPASSLV = "lspatch_sigbypasslv"; final static public int SIGBYPASS_LV_DISABLE = 0; final static public int SIGBYPASS_LV_PM = 1;