Update core & Listen app change broadcast & Crash when cannot connect to manager
This commit is contained in:
parent
cb1ba36514
commit
8498da904c
|
|
@ -37,7 +37,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
|
||||||
String path = cl.getResource("assets/lspatch/so/" + arch + "/liblspatch.so").getPath().substring(5);
|
String path = cl.getResource("assets/lspatch/so/" + arch + "/liblspatch.so").getPath().substring(5);
|
||||||
System.load(path);
|
System.load(path);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e("LSPatch", "load lspd error", e);
|
throw new ExceptionInInitializerError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
core
2
core
|
|
@ -1 +1 @@
|
||||||
Subproject commit f3055202da32051de3508407d08838a7df62e872
|
Subproject commit 6ced1460180d61c647d2ae91e719e8598ca71b94
|
||||||
|
|
@ -7,6 +7,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||||
|
import org.lsposed.lspatch.manager.AppBroadcastReceiver
|
||||||
import org.lsposed.lspatch.util.LSPPackageManager
|
import org.lsposed.lspatch.util.LSPPackageManager
|
||||||
import org.lsposed.lspatch.util.ShizukuApi
|
import org.lsposed.lspatch.util.ShizukuApi
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -25,10 +26,10 @@ class LSPApplication : Application() {
|
||||||
HiddenApiBypass.addHiddenApiExemptions("");
|
HiddenApiBypass.addHiddenApiExemptions("");
|
||||||
lspApp = this
|
lspApp = this
|
||||||
filesDir.mkdir()
|
filesDir.mkdir()
|
||||||
tmpApkDir = cacheDir.resolve("apk")
|
tmpApkDir = cacheDir.resolve("apk").also { it.mkdir() }
|
||||||
tmpApkDir.mkdirs()
|
|
||||||
prefs = lspApp.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
prefs = lspApp.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||||
ShizukuApi.init()
|
ShizukuApi.init()
|
||||||
|
AppBroadcastReceiver.register(this)
|
||||||
globalScope.launch { LSPPackageManager.fetchAppList() }
|
globalScope.launch { LSPPackageManager.fetchAppList() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.lsposed.lspatch.manager
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.util.Log
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.lsposed.lspatch.util.LSPPackageManager
|
||||||
|
|
||||||
|
class AppBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "AppBroadcastReceiver"
|
||||||
|
|
||||||
|
private val actions = setOf(
|
||||||
|
Intent.ACTION_PACKAGE_ADDED,
|
||||||
|
Intent.ACTION_PACKAGE_REMOVED,
|
||||||
|
Intent.ACTION_PACKAGE_REPLACED
|
||||||
|
)
|
||||||
|
|
||||||
|
fun register(context: Context) {
|
||||||
|
val filter = IntentFilter().apply {
|
||||||
|
actions.forEach(::addAction)
|
||||||
|
addDataScheme("package")
|
||||||
|
}
|
||||||
|
context.registerReceiver(AppBroadcastReceiver(), filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action in actions) {
|
||||||
|
runBlocking {
|
||||||
|
Log.i(TAG, "Received intent: $intent")
|
||||||
|
LSPPackageManager.fetchAppList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -343,7 +343,6 @@ private fun DoPatchBody(modifier: Modifier, navigator: DestinationsNavigator) {
|
||||||
var installing by remember { mutableStateOf(false) }
|
var installing by remember { mutableStateOf(false) }
|
||||||
if (installing) InstallDialog(viewModel.patchApp) { status, message ->
|
if (installing) InstallDialog(viewModel.patchApp) { status, message ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
LSPPackageManager.fetchAppList()
|
|
||||||
installing = false
|
installing = false
|
||||||
if (status == PackageInstaller.STATUS_SUCCESS) {
|
if (status == PackageInstaller.STATUS_SUCCESS) {
|
||||||
lspApp.globalScope.launch { snackbarHost.showSnackbar(installSuccessfully) }
|
lspApp.globalScope.launch { snackbarHost.showSnackbar(installSuccessfully) }
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import com.ramcosta.composedestinations.result.NavResult
|
import com.ramcosta.composedestinations.result.NavResult
|
||||||
import com.ramcosta.composedestinations.result.ResultRecipient
|
import com.ramcosta.composedestinations.result.ResultRecipient
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.lsposed.lspatch.BuildConfig
|
||||||
import org.lsposed.lspatch.R
|
import org.lsposed.lspatch.R
|
||||||
import org.lsposed.lspatch.config.ConfigManager
|
import org.lsposed.lspatch.config.ConfigManager
|
||||||
import org.lsposed.lspatch.config.Configs
|
import org.lsposed.lspatch.config.Configs
|
||||||
|
|
@ -99,7 +100,6 @@ fun AppManageBody(
|
||||||
val copyError = stringResource(R.string.copy_error)
|
val copyError = stringResource(R.string.copy_error)
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
it.onSuccess {
|
it.onSuccess {
|
||||||
LSPPackageManager.fetchAppList()
|
|
||||||
snackbarHost.showSnackbar(updateSuccessfully)
|
snackbarHost.showSnackbar(updateSuccessfully)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
val result = snackbarHost.showSnackbar(updateFailed, copyError)
|
val result = snackbarHost.showSnackbar(updateFailed, copyError)
|
||||||
|
|
@ -143,7 +143,7 @@ fun AppManageBody(
|
||||||
)
|
)
|
||||||
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
||||||
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
val shizukuUnavailable = stringResource(R.string.shizuku_unavailable)
|
||||||
if (it.second.lspConfig.VERSION_CODE >= 319 && it.second.lspConfig.VERSION_CODE < LSPConfig.instance.VERSION_CODE) {
|
if (it.second.lspConfig.VERSION_CODE < LSPConfig.instance.VERSION_CODE || BuildConfig.DEBUG) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.manage_update_loader)) },
|
text = { Text(stringResource(R.string.manage_update_loader)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -194,7 +194,6 @@ fun AppManageBody(
|
||||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
LSPPackageManager.fetchAppList()
|
|
||||||
snackbarHost.showSnackbar(uninstallSuccessfully)
|
snackbarHost.showSnackbar(uninstallSuccessfully)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import java.io.InputStreamReader;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.PosixFilePermissions;
|
import java.nio.file.attribute.PosixFilePermissions;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -82,15 +83,15 @@ public class LSPApplication {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "Initialize service client");
|
|
||||||
ILSPApplicationService service;
|
|
||||||
if (config.useManager) {
|
|
||||||
service = new RemoteApplicationService(context);
|
|
||||||
} else {
|
|
||||||
service = new LocalApplicationService(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Log.d(TAG, "Initialize service client");
|
||||||
|
ILSPApplicationService service;
|
||||||
|
if (config.useManager) {
|
||||||
|
service = new RemoteApplicationService(context);
|
||||||
|
} else {
|
||||||
|
service = new LocalApplicationService(context);
|
||||||
|
}
|
||||||
|
|
||||||
disableProfile(context);
|
disableProfile(context);
|
||||||
Startup.initXposed(false, ActivityThread.currentProcessName(), service);
|
Startup.initXposed(false, ActivityThread.currentProcessName(), service);
|
||||||
Log.i(TAG, "Bootstrap Xposed");
|
Log.i(TAG, "Bootstrap Xposed");
|
||||||
|
|
@ -106,7 +107,7 @@ public class LSPApplication {
|
||||||
switchClassLoader("mClassLoader");
|
switchClassLoader("mClassLoader");
|
||||||
doSigBypass(context);
|
doSigBypass(context);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e(TAG, "Do hook", e);
|
throw new RuntimeException("Do hook", e);
|
||||||
}
|
}
|
||||||
Log.i(TAG, "LSPatch bootstrap completed");
|
Log.i(TAG, "LSPatch bootstrap completed");
|
||||||
}
|
}
|
||||||
|
|
@ -130,22 +131,22 @@ public class LSPApplication {
|
||||||
Log.i(TAG, "Use manager: " + config.useManager);
|
Log.i(TAG, "Use manager: " + config.useManager);
|
||||||
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
||||||
|
|
||||||
String originPath = appInfo.dataDir + "/cache/lspatch/origin/";
|
Path originPath = Paths.get(appInfo.dataDir, "cache/lspatch/origin/");
|
||||||
String cacheApkPath;
|
Path cacheApkPath;
|
||||||
try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) {
|
try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) {
|
||||||
cacheApkPath = originPath + sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk";
|
cacheApkPath = originPath.resolve(sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk");
|
||||||
}
|
}
|
||||||
|
|
||||||
appInfo.sourceDir = cacheApkPath;
|
appInfo.sourceDir = cacheApkPath.toString();
|
||||||
appInfo.publicSourceDir = cacheApkPath;
|
appInfo.publicSourceDir = cacheApkPath.toString();
|
||||||
appInfo.appComponentFactory = config.appComponentFactory;
|
appInfo.appComponentFactory = config.appComponentFactory;
|
||||||
|
|
||||||
if (!Files.exists(Paths.get(cacheApkPath))) {
|
if (!Files.exists(cacheApkPath)) {
|
||||||
Log.i(TAG, "Extract original apk");
|
Log.i(TAG, "Extract original apk");
|
||||||
FileUtils.deleteFolderIfExists(Paths.get(originPath));
|
FileUtils.deleteFolderIfExists(originPath);
|
||||||
Files.createDirectories(Paths.get(originPath));
|
Files.createDirectories(originPath);
|
||||||
try (InputStream is = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) {
|
try (InputStream is = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) {
|
||||||
Files.copy(is, Paths.get(cacheApkPath));
|
Files.copy(is, cacheApkPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.lsposed.lspd.models.Module;
|
import org.lsposed.lspd.models.Module;
|
||||||
import org.lsposed.lspd.service.ILSPApplicationService;
|
import org.lsposed.lspd.service.ILSPApplicationService;
|
||||||
|
|
@ -22,15 +22,17 @@ public class RemoteApplicationService implements ILSPApplicationService {
|
||||||
|
|
||||||
private static final Uri PROVIDER = Uri.parse("content://" + MANAGER_PACKAGE_NAME + ".provider");
|
private static final Uri PROVIDER = Uri.parse("content://" + MANAGER_PACKAGE_NAME + ".provider");
|
||||||
|
|
||||||
private ILSPApplicationService service;
|
private final ILSPApplicationService service;
|
||||||
|
|
||||||
public RemoteApplicationService(Context context) {
|
public RemoteApplicationService(Context context) throws RemoteException {
|
||||||
try {
|
try {
|
||||||
Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null);
|
Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null);
|
||||||
service = ILSPApplicationService.Stub.asInterface(back.getBinder("binder"));
|
service = ILSPApplicationService.Stub.asInterface(back.getBinder("binder"));
|
||||||
if (service == null) throw new RemoteException("Binder is null");
|
} catch (IllegalArgumentException | NullPointerException e) {
|
||||||
} catch (Throwable e) {
|
Toast.makeText(context, "Manager died", Toast.LENGTH_SHORT).show();
|
||||||
Log.e("LSPatch", "Error when initializing RemoteApplicationServiceClient", e);
|
var r = new RemoteException("Failed to get manager binder");
|
||||||
|
r.initCause(e);
|
||||||
|
throw r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,8 @@ namespace lspd {
|
||||||
auto stub = JNI_FindClass(env, "org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub");
|
auto stub = JNI_FindClass(env, "org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub");
|
||||||
auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B");
|
auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B");
|
||||||
|
|
||||||
auto array = (jbyteArray) env->GetStaticObjectField(stub, dex_field);
|
ScopedLocalRef<jbyteArray> array = JNI_GetStaticObjectField(env, stub, dex_field);
|
||||||
auto dex = PreloadedDex {env->GetByteArrayElements(array, nullptr), static_cast<size_t>(JNI_GetArrayLength(env, array))};
|
auto dex = PreloadedDex {env->GetByteArrayElements(array.get(), nullptr), static_cast<size_t>(JNI_GetArrayLength(env, array))};
|
||||||
|
|
||||||
InitArtHooker(env, initInfo);
|
InitArtHooker(env, initInfo);
|
||||||
LoadDex(env, std::move(dex));
|
LoadDex(env, std::move(dex));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue