Update core & Listen app change broadcast & Crash when cannot connect to manager

This commit is contained in:
Nullptr 2022-07-10 23:25:23 +08:00
parent cb1ba36514
commit 8498da904c
No known key found for this signature in database
GPG Key ID: 0B9D02052FF536BD
9 changed files with 75 additions and 34 deletions

View File

@ -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

@ -1 +1 @@
Subproject commit f3055202da32051de3508407d08838a7df62e872 Subproject commit 6ced1460180d61c647d2ae91e719e8598ca71b94

View File

@ -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() }
} }
} }

View File

@ -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()
}
}
}
}

View File

@ -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) }

View File

@ -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)
} }
} }

View File

@ -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,6 +83,7 @@ public class LSPApplication {
return; return;
} }
try {
Log.d(TAG, "Initialize service client"); Log.d(TAG, "Initialize service client");
ILSPApplicationService service; ILSPApplicationService service;
if (config.useManager) { if (config.useManager) {
@ -90,7 +92,6 @@ public class LSPApplication {
service = new LocalApplicationService(context); service = new LocalApplicationService(context);
} }
try {
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);
} }
} }

View File

@ -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;
} }
} }

View File

@ -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));