diff --git a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java index 0d07f32..fe79cfd 100644 --- a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java +++ b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub.java @@ -37,7 +37,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory { String path = cl.getResource("assets/lspatch/so/" + arch + "/liblspatch.so").getPath().substring(5); System.load(path); } catch (Throwable e) { - Log.e("LSPatch", "load lspd error", e); + throw new ExceptionInInitializerError(e); } } } diff --git a/core b/core index f305520..6ced146 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit f3055202da32051de3508407d08838a7df62e872 +Subproject commit 6ced1460180d61c647d2ae91e719e8598ca71b94 diff --git a/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt index 96a65ec..6354f46 100644 --- a/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt +++ b/manager/src/main/java/org/lsposed/lspatch/LSPApplication.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.lsposed.hiddenapibypass.HiddenApiBypass +import org.lsposed.lspatch.manager.AppBroadcastReceiver import org.lsposed.lspatch.util.LSPPackageManager import org.lsposed.lspatch.util.ShizukuApi import java.io.File @@ -25,10 +26,10 @@ class LSPApplication : Application() { HiddenApiBypass.addHiddenApiExemptions(""); lspApp = this filesDir.mkdir() - tmpApkDir = cacheDir.resolve("apk") - tmpApkDir.mkdirs() + tmpApkDir = cacheDir.resolve("apk").also { it.mkdir() } prefs = lspApp.getSharedPreferences("settings", Context.MODE_PRIVATE) ShizukuApi.init() + AppBroadcastReceiver.register(this) globalScope.launch { LSPPackageManager.fetchAppList() } } } diff --git a/manager/src/main/java/org/lsposed/lspatch/manager/AppBroadcastReceiver.kt b/manager/src/main/java/org/lsposed/lspatch/manager/AppBroadcastReceiver.kt new file mode 100644 index 0000000..f222b28 --- /dev/null +++ b/manager/src/main/java/org/lsposed/lspatch/manager/AppBroadcastReceiver.kt @@ -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() + } + } + } +} diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchScreen.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchScreen.kt index d934649..e68df35 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchScreen.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/NewPatchScreen.kt @@ -343,7 +343,6 @@ private fun DoPatchBody(modifier: Modifier, navigator: DestinationsNavigator) { var installing by remember { mutableStateOf(false) } if (installing) InstallDialog(viewModel.patchApp) { status, message -> scope.launch { - LSPPackageManager.fetchAppList() installing = false if (status == PackageInstaller.STATUS_SUCCESS) { lspApp.globalScope.launch { snackbarHost.showSnackbar(installSuccessfully) } diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/page/manage/AppManagePage.kt b/manager/src/main/java/org/lsposed/lspatch/ui/page/manage/AppManagePage.kt index ea50970..8cee268 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/page/manage/AppManagePage.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/page/manage/AppManagePage.kt @@ -35,6 +35,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.result.NavResult import com.ramcosta.composedestinations.result.ResultRecipient import kotlinx.coroutines.launch +import org.lsposed.lspatch.BuildConfig import org.lsposed.lspatch.R import org.lsposed.lspatch.config.ConfigManager import org.lsposed.lspatch.config.Configs @@ -99,7 +100,6 @@ fun AppManageBody( val copyError = stringResource(R.string.copy_error) LaunchedEffect(Unit) { it.onSuccess { - LSPPackageManager.fetchAppList() snackbarHost.showSnackbar(updateSuccessfully) }.onFailure { val result = snackbarHost.showSnackbar(updateFailed, copyError) @@ -143,7 +143,7 @@ fun AppManageBody( ) DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { 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( text = { Text(stringResource(R.string.manage_update_loader)) }, onClick = { @@ -194,7 +194,6 @@ fun AppManageBody( val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == Activity.RESULT_OK) { scope.launch { - LSPPackageManager.fetchAppList() snackbarHost.showSnackbar(uninstallSuccessfully) } } diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java index 15ed576..fa9e4e3 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java @@ -38,6 +38,7 @@ import java.io.InputStreamReader; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; @@ -82,15 +83,15 @@ public class LSPApplication { return; } - Log.d(TAG, "Initialize service client"); - ILSPApplicationService service; - if (config.useManager) { - service = new RemoteApplicationService(context); - } else { - service = new LocalApplicationService(context); - } - try { + Log.d(TAG, "Initialize service client"); + ILSPApplicationService service; + if (config.useManager) { + service = new RemoteApplicationService(context); + } else { + service = new LocalApplicationService(context); + } + disableProfile(context); Startup.initXposed(false, ActivityThread.currentProcessName(), service); Log.i(TAG, "Bootstrap Xposed"); @@ -106,7 +107,7 @@ public class LSPApplication { switchClassLoader("mClassLoader"); doSigBypass(context); } catch (Throwable e) { - Log.e(TAG, "Do hook", e); + throw new RuntimeException("Do hook", e); } Log.i(TAG, "LSPatch bootstrap completed"); } @@ -130,22 +131,22 @@ public class LSPApplication { Log.i(TAG, "Use manager: " + config.useManager); Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel); - String originPath = appInfo.dataDir + "/cache/lspatch/origin/"; - String cacheApkPath; + Path originPath = Paths.get(appInfo.dataDir, "cache/lspatch/origin/"); + Path cacheApkPath; 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.publicSourceDir = cacheApkPath; + appInfo.sourceDir = cacheApkPath.toString(); + appInfo.publicSourceDir = cacheApkPath.toString(); appInfo.appComponentFactory = config.appComponentFactory; - if (!Files.exists(Paths.get(cacheApkPath))) { + if (!Files.exists(cacheApkPath)) { Log.i(TAG, "Extract original apk"); - FileUtils.deleteFolderIfExists(Paths.get(originPath)); - Files.createDirectories(Paths.get(originPath)); + FileUtils.deleteFolderIfExists(originPath); + Files.createDirectories(originPath); try (InputStream is = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) { - Files.copy(is, Paths.get(cacheApkPath)); + Files.copy(is, cacheApkPath); } } diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java b/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java index d5d3eb6..7e711fe 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java @@ -9,7 +9,7 @@ import android.os.Environment; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.util.Log; +import android.widget.Toast; import org.lsposed.lspd.models.Module; 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 ILSPApplicationService service; + private final ILSPApplicationService service; - public RemoteApplicationService(Context context) { + public RemoteApplicationService(Context context) throws RemoteException { try { Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null); service = ILSPApplicationService.Stub.asInterface(back.getBinder("binder")); - if (service == null) throw new RemoteException("Binder is null"); - } catch (Throwable e) { - Log.e("LSPatch", "Error when initializing RemoteApplicationServiceClient", e); + } catch (IllegalArgumentException | NullPointerException e) { + Toast.makeText(context, "Manager died", Toast.LENGTH_SHORT).show(); + var r = new RemoteException("Failed to get manager binder"); + r.initCause(e); + throw r; } } diff --git a/patch-loader/src/main/jni/src/patch_loader.cpp b/patch-loader/src/main/jni/src/patch_loader.cpp index 6bb5943..3937651 100644 --- a/patch-loader/src/main/jni/src/patch_loader.cpp +++ b/patch-loader/src/main/jni/src/patch_loader.cpp @@ -111,8 +111,8 @@ namespace lspd { auto stub = JNI_FindClass(env, "org/lsposed/lspatch/appstub/LSPAppComponentFactoryStub"); auto dex_field = JNI_GetStaticFieldID(env, stub, "dex", "[B"); - auto array = (jbyteArray) env->GetStaticObjectField(stub, dex_field); - auto dex = PreloadedDex {env->GetByteArrayElements(array, nullptr), static_cast(JNI_GetArrayLength(env, array))}; + ScopedLocalRef array = JNI_GetStaticObjectField(env, stub, dex_field); + auto dex = PreloadedDex {env->GetByteArrayElements(array.get(), nullptr), static_cast(JNI_GetArrayLength(env, array))}; InitArtHooker(env, initInfo); LoadDex(env, std::move(dex));