Add ManagerResolver
This commit is contained in:
parent
cdf341b856
commit
919e44de56
|
|
@ -84,4 +84,5 @@ dependencies {
|
|||
implementation project(path: ':hiddenapi-bridge')
|
||||
compileOnly project(":hiddenapi-stubs")
|
||||
implementation project(':share')
|
||||
implementation project(':imanager')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,21 +8,19 @@ import android.app.LoadedApk;
|
|||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
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.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.lsposed.lspatch.loader.util.FileUtils;
|
||||
import org.lsposed.lspatch.loader.util.XLog;
|
||||
import org.lsposed.lspatch.share.Constants;
|
||||
|
|
@ -33,9 +31,7 @@ import org.lsposed.lspd.models.PreLoadedApk;
|
|||
import org.lsposed.lspd.nativebridge.SigBypass;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -44,15 +40,13 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
|
|
@ -67,11 +61,14 @@ import hidden.HiddenApiBridge;
|
|||
public class LSPApplication extends ApplicationServiceClient {
|
||||
private static final String ORIGINAL_APPLICATION_NAME_ASSET_PATH = "original_application_name.ini";
|
||||
private static final String ORIGINAL_SIGNATURE_ASSET_PATH = "original_signature_info.ini";
|
||||
private static final String USE_MANAGER_CONTROL_PATH = "use_manager.ini";
|
||||
private static final String TAG = "LSPatch";
|
||||
|
||||
private static boolean useManager;
|
||||
private static String originalApplicationName = null;
|
||||
private static String originalSignature = null;
|
||||
private static Application sOriginalApplication = null;
|
||||
private static ManagerResolver managerResolver = null;
|
||||
private static ClassLoader appClassLoader;
|
||||
private static Object activityThread;
|
||||
|
||||
|
|
@ -99,9 +96,16 @@ public class LSPApplication extends ApplicationServiceClient {
|
|||
return;
|
||||
}
|
||||
|
||||
useManager = Boolean.parseBoolean(Objects.requireNonNull(FileUtils.readTextFromAssets(context, USE_MANAGER_CONTROL_PATH)));
|
||||
originalApplicationName = FileUtils.readTextFromAssets(context, ORIGINAL_APPLICATION_NAME_ASSET_PATH);
|
||||
originalSignature = FileUtils.readTextFromAssets(context, ORIGINAL_SIGNATURE_ASSET_PATH);
|
||||
|
||||
if (useManager) try {
|
||||
managerResolver = new ManagerResolver(context);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to instantiate manager resolver", e);
|
||||
}
|
||||
|
||||
XLog.d(TAG, "original application class " + originalApplicationName);
|
||||
XLog.d(TAG, "original signature info " + originalSignature);
|
||||
|
||||
|
|
@ -169,98 +173,40 @@ public class LSPApplication extends ApplicationServiceClient {
|
|||
|
||||
}
|
||||
|
||||
|
||||
// TODO: set module config
|
||||
public static void loadModules(Context context) {
|
||||
var configFile = new File(context.getExternalFilesDir(null), "lspatch.json");
|
||||
JSONObject moduleConfigs = new JSONObject();
|
||||
try (var is = new FileInputStream(configFile)) {
|
||||
moduleConfigs = new JSONObject(FileUtils.readTextFromInputStream(is));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
var modules = moduleConfigs.optJSONArray("modules");
|
||||
if (modules == null) {
|
||||
modules = new JSONArray();
|
||||
if (useManager) {
|
||||
try {
|
||||
moduleConfigs.put("modules", modules);
|
||||
} catch (Throwable ignored) {
|
||||
|
||||
LSPApplication.modules.addAll(managerResolver.getModules());
|
||||
} catch (NullPointerException | RemoteException e) {
|
||||
Log.e(TAG, "Failed to get modules from manager", e);
|
||||
}
|
||||
}
|
||||
HashSet<String> embedded_modules = new HashSet<>();
|
||||
HashSet<String> disabled_modules = new HashSet<>();
|
||||
try {
|
||||
for (var name : context.getAssets().list("modules")) {
|
||||
String packageName = name.substring(0, name.length() - 4);
|
||||
String modulePath = context.getCacheDir() + "/lspatch/" + packageName + "/";
|
||||
String cacheApkPath;
|
||||
try (ZipFile sourceFile = new ZipFile(context.getApplicationInfo().sourceDir)) {
|
||||
cacheApkPath = modulePath + sourceFile.getEntry("assets/modules/" + name).getCrc();
|
||||
}
|
||||
|
||||
if (!Files.exists(Paths.get(cacheApkPath))) {
|
||||
Log.i(TAG, "extract module apk: " + packageName);
|
||||
FileUtils.deleteFolderIfExists(Paths.get(modulePath));
|
||||
Files.createDirectories(Paths.get(modulePath));
|
||||
try (var is = context.getAssets().open("modules/" + name)) {
|
||||
Files.copy(is, Paths.get(cacheApkPath));
|
||||
} else {
|
||||
try {
|
||||
for (var name : context.getAssets().list("modules")) {
|
||||
String packageName = name.substring(0, name.length() - 4);
|
||||
String modulePath = context.getCacheDir() + "/lspatch/" + packageName + "/";
|
||||
String cacheApkPath;
|
||||
try (ZipFile sourceFile = new ZipFile(context.getApplicationInfo().sourceDir)) {
|
||||
cacheApkPath = modulePath + sourceFile.getEntry("assets/modules/" + name).getCrc();
|
||||
}
|
||||
|
||||
if (!Files.exists(Paths.get(cacheApkPath))) {
|
||||
Log.i(TAG, "extract module apk: " + packageName);
|
||||
FileUtils.deleteFolderIfExists(Paths.get(modulePath));
|
||||
Files.createDirectories(Paths.get(modulePath));
|
||||
try (var is = context.getAssets().open("modules/" + name)) {
|
||||
Files.copy(is, Paths.get(cacheApkPath));
|
||||
}
|
||||
}
|
||||
|
||||
var module = new Module();
|
||||
module.apkPath = cacheApkPath;
|
||||
module.packageName = packageName;
|
||||
module.file = loadModule(context, cacheApkPath);
|
||||
modules.add(module);
|
||||
}
|
||||
|
||||
embedded_modules.add(packageName);
|
||||
var module = new Module();
|
||||
module.apkPath = cacheApkPath;
|
||||
module.packageName = packageName;
|
||||
LSPApplication.modules.add(module);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
|
||||
}
|
||||
for (int i = 0; i < modules.length(); ++i) {
|
||||
var module = modules.optJSONObject(i);
|
||||
var name = module.optString("name");
|
||||
var enabled = module.optBoolean("enabled", true);
|
||||
var useEmbed = module.optBoolean("use_embed", false);
|
||||
if (name.isEmpty()) continue;
|
||||
if (!enabled) disabled_modules.add(name);
|
||||
if (embedded_modules.contains(name) && !useEmbed) embedded_modules.remove(name);
|
||||
}
|
||||
|
||||
for (PackageInfo pkg : context.getPackageManager().getInstalledPackages(PackageManager.GET_META_DATA)) {
|
||||
ApplicationInfo app = pkg.applicationInfo;
|
||||
if (!app.enabled) {
|
||||
continue;
|
||||
}
|
||||
if (app.metaData != null && app.metaData.containsKey("xposedminversion") && !embedded_modules.contains(app.packageName)) {
|
||||
var module = new Module();
|
||||
module.apkPath = app.publicSourceDir;
|
||||
module.packageName = app.packageName;
|
||||
LSPApplication.modules.add(module);
|
||||
}
|
||||
}
|
||||
final var new_modules = new JSONArray();
|
||||
LSPApplication.modules.forEach(m -> {
|
||||
try {
|
||||
m.file = loadModule(context, m.apkPath);
|
||||
var module = new JSONObject();
|
||||
module.put("name", m.packageName);
|
||||
module.put("enabled", !disabled_modules.contains(m.packageName));
|
||||
module.put("use_embed", embedded_modules.contains(m.packageName));
|
||||
module.put("path", m.apkPath);
|
||||
new_modules.put(module);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
try {
|
||||
moduleConfigs.put("modules", new_modules);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
try (var is = new ByteArrayInputStream(moduleConfigs.toString(4).getBytes(StandardCharsets.UTF_8))) {
|
||||
Files.copy(is, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
for (var module : disabled_modules) {
|
||||
LSPApplication.modules.remove(module);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package org.lsposed.lspatch.loader;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.lsposed.lspatch.manager.IManagerService;
|
||||
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");
|
||||
|
||||
private final IManagerService service;
|
||||
|
||||
public ManagerResolver(Context context) throws RemoteException {
|
||||
super(context);
|
||||
try {
|
||||
Bundle back = call(BINDER_URI, "getBinder", null, null);
|
||||
service = IManagerService.Stub.asInterface(back.getBinder("binder"));
|
||||
} catch (Throwable t) {
|
||||
var e = new RemoteException("Failed to get manager binder");
|
||||
e.addSuppressed(t);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Module> getModules() throws RemoteException {
|
||||
return service.getModules();
|
||||
}
|
||||
}
|
||||
2
core
2
core
|
|
@ -1 +1 @@
|
|||
Subproject commit a2e57ddfe9477933e6540ce9dad4c1dac1991d32
|
||||
Subproject commit f955755ac40134f1b0a858f4e7df3b4a4eec78a8
|
||||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 31
|
||||
|
||||
defaultConfig {
|
||||
minSdk 27
|
||||
targetSdk 31
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':lspcore')
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.lsposed.lspatch.manager" />
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package org.lsposed.lspatch.manager;
|
||||
|
||||
import org.lsposed.lspd.models.Module;
|
||||
|
||||
interface IManagerService {
|
||||
List<Module> getModules();
|
||||
}
|
||||
|
|
@ -78,6 +78,9 @@ public class LSPatch {
|
|||
@Parameter(names = {"--v3"}, arity = 1, description = "Sign with v3 signature")
|
||||
private boolean v3 = true;
|
||||
|
||||
@Parameter(names = {"--manager"}, arity = 1, description = "Whether use manager (Cannot be true when has module embedded)")
|
||||
private boolean useManager = false;
|
||||
|
||||
@Parameter(names = {"-v", "--verbose"}, description = "Verbose output")
|
||||
private boolean verbose = false;
|
||||
|
||||
|
|
@ -90,6 +93,7 @@ public class LSPatch {
|
|||
private static final String APP_COMPONENT_FACTORY_ASSET_PATH = "assets/original_app_component_factory.ini";
|
||||
private static final String APPLICATION_NAME_ASSET_PATH = "assets/original_application_name.ini";
|
||||
private static final String SIGNATURE_INFO_ASSET_PATH = "assets/original_signature_info.ini";
|
||||
private static final String USE_MANAGER_CONTROL_PATH = "assets/use_manager.ini";
|
||||
private static final String ORIGINAL_APK_ASSET_PATH = "assets/origin_apk.bin";
|
||||
private static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml";
|
||||
private static final HashSet<String> ARCHES = new HashSet<>(Arrays.asList(
|
||||
|
|
@ -135,6 +139,11 @@ public class LSPatch {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!modules.isEmpty() && useManager) {
|
||||
jCommander.usage();
|
||||
return;
|
||||
}
|
||||
|
||||
for (var apk : apkPaths) {
|
||||
File srcApkFile = new File(apk).getAbsoluteFile();
|
||||
|
||||
|
|
@ -274,8 +283,9 @@ public class LSPatch {
|
|||
// save lspatch config to asset..
|
||||
try (var is = new ByteArrayInputStream("42".getBytes(StandardCharsets.UTF_8))) {
|
||||
dstZFile.add("assets/" + Constants.CONFIG_NAME_SIGBYPASSLV + sigbypassLevel, is);
|
||||
} catch (Throwable e) {
|
||||
throw new PatchError("Error when saving signature bypass level", e);
|
||||
}
|
||||
try (var is = new ByteArrayInputStream(Boolean.toString(useManager).getBytes(StandardCharsets.UTF_8))){
|
||||
dstZFile.add(USE_MANAGER_CONTROL_PATH, is);
|
||||
}
|
||||
|
||||
Set<String> apkArchs = new HashSet<>();
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ include ':axmlprinter'
|
|||
include ':share'
|
||||
include ':appstub'
|
||||
include ':apkzlib'
|
||||
include ':imanager'
|
||||
|
|
|
|||
Loading…
Reference in New Issue