diff --git a/app/src/main/java/org/lsposed/manager/App.java b/app/src/main/java/org/lsposed/manager/App.java index 89c930b1..25f1a5ce 100644 --- a/app/src/main/java/org/lsposed/manager/App.java +++ b/app/src/main/java/org/lsposed/manager/App.java @@ -38,7 +38,6 @@ import androidx.preference.PreferenceManager; import com.google.gson.JsonParser; import org.lsposed.hiddenapibypass.HiddenApiBypass; -import org.lsposed.manager.receivers.LSPManagerServiceHolder; import org.lsposed.manager.repo.RepoLoader; import org.lsposed.manager.ui.activity.CrashReportActivity; import org.lsposed.manager.util.DoHDNS; @@ -168,8 +167,9 @@ public class App extends Application { public void onReceive(Context context, Intent intent) { int userId = intent.getIntExtra(Intent.EXTRA_USER, 0); String packageName = intent.getStringExtra("android.intent.extra.PACKAGES"); + boolean packageFullyRemoved = intent.getBooleanExtra(Intent.ACTION_PACKAGE_FULLY_REMOVED, false); if (packageName != null) { - ModuleUtil.getInstance().reloadSingleModule(packageName, userId); + ModuleUtil.getInstance().reloadSingleModule(packageName, userId, packageFullyRemoved); } } }, new IntentFilter(Intent.ACTION_PACKAGE_CHANGED)); diff --git a/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java b/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java index c62a10e9..77479c42 100644 --- a/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java +++ b/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java @@ -108,6 +108,12 @@ public final class ModuleUtil { } public InstalledModule reloadSingleModule(String packageName, int userId) { + return reloadSingleModule(packageName, userId, false); + } + + public InstalledModule reloadSingleModule(String packageName, int userId, boolean packageFullyRemoved) { + if (packageFullyRemoved && isModuleEnabled(packageName)) + enabledModules.remove(packageName); PackageInfo pkg; try { @@ -115,7 +121,6 @@ public final class ModuleUtil { } catch (NameNotFoundException e) { InstalledModule old = installedModules.remove(Pair.create(packageName, userId)); if (old != null) { - enabledModules.remove(packageName); for (ModuleListener listener : listeners) { listener.onSingleInstalledModuleReloaded(); } diff --git a/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java index 9980b109..4bd266d2 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -670,7 +670,10 @@ public class ConfigManager { public boolean removeModule(String packageName) { if (removeModuleWithoutCache(packageName)) { // called by oneway binder - updateCaches(true); + // Called only when the application is completely uninstalled + // If it's a module we need to return as soon as possible to broadcast to the manager + // for updating the module status + updateCaches(false); return true; } return false; diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java b/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java index 66a09a40..f3addf0f 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java @@ -42,6 +42,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -59,7 +60,6 @@ import org.lsposed.lspd.ILSPManagerService; import org.lsposed.lspd.models.Application; import org.lsposed.lspd.models.UserInfo; import org.lsposed.lspd.util.FakeContext; -import android.os.Handler; import org.lsposed.lspd.util.Utils; import java.io.File; @@ -253,12 +253,13 @@ public class LSPManagerService extends ILSPManagerService.Stub { } } - public static void broadcastIntent(String modulePackageName, int moduleUserId) { + public static void broadcastIntent(String modulePackageName, int moduleUserId, boolean packageFullyRemoved) { Intent intent = new Intent(Intent.ACTION_PACKAGE_CHANGED); intent.addFlags(0x01000000); //Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND intent.addFlags(0x00400000); //Intent.FLAG_RECEIVER_FROM_SHELL intent.putExtra("android.intent.extra.PACKAGES", modulePackageName); intent.putExtra(Intent.EXTRA_USER, moduleUserId); + intent.putExtra(Intent.ACTION_PACKAGE_FULLY_REMOVED, packageFullyRemoved); intent.setPackage(BuildConfig.MANAGER_INJECTED_PKG_NAME); try { ActivityManagerService.broadcastIntentWithFeature(null, intent, @@ -277,7 +278,7 @@ public class LSPManagerService extends ILSPManagerService.Stub { public static void createOrUpdateShortcut(boolean force) { - workerHandler.post(()->createOrUpdateShortcutInternal(force)); + workerHandler.post(() -> createOrUpdateShortcutInternal(force)); } private synchronized static void createOrUpdateShortcutInternal(boolean force) { diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java b/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java index a6e25da2..2e0397c4 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -79,9 +79,9 @@ public class LSPosedService extends ILSPosedService.Stub { if (uid == AID_NOBODY || uid <= 0) return; int userId = intent.getIntExtra("android.intent.extra.user_handle", USER_NULL); if (userId == USER_NULL) userId = uid % PER_USER_RANGE; - + var configManager = ConfigManager.getInstance(); Uri uri = intent.getData(); - String moduleName = (uri != null) ? uri.getSchemeSpecificPart() : ConfigManager.getInstance().getModule(uid); + String moduleName = (uri != null) ? uri.getSchemeSpecificPart() : configManager.getModule(uid); ApplicationInfo applicationInfo = null; if (moduleName != null) { @@ -94,15 +94,13 @@ public class LSPosedService extends ILSPosedService.Stub { boolean isXposedModule = applicationInfo != null && applicationInfo.metaData != null && applicationInfo.metaData.containsKey("xposedminversion"); - - Log.d(TAG, "Package changed: uid=" + uid + " userId=" + userId + " action=" + intent.getAction() + " isXposedModule=" + isXposedModule); - - switch (intent.getAction()) { + var intentAction = intent.getAction(); + switch (intentAction) { case Intent.ACTION_PACKAGE_FULLY_REMOVED: { // for module, remove module // because we only care about when the apk is gone if (moduleName != null) - if (ConfigManager.getInstance().removeModule(moduleName)) + if (configManager.removeModule(moduleName)) isXposedModule = true; break; } @@ -116,10 +114,10 @@ public class LSPosedService extends ILSPosedService.Stub { } // when package is changed, we may need to update cache (module cache or process cache) if (isXposedModule) { - ConfigManager.getInstance().updateCache(); - } else if (ConfigManager.getInstance().isUidHooked(uid)) { + configManager.updateCache(); + } else if (configManager.isUidHooked(uid)) { // it will automatically remove obsolete app from database - ConfigManager.getInstance().updateAppCache(); + configManager.updateAppCache(); } break; } @@ -128,33 +126,36 @@ public class LSPosedService extends ILSPosedService.Stub { // (apk may still be there because of multi-user) if (isXposedModule) { // it will automatically remove obsolete scope from database - ConfigManager.getInstance().updateCache(); - } else if (ConfigManager.getInstance().isUidHooked(uid)) { + configManager.updateCache(); + } else if (configManager.isUidHooked(uid)) { // it will automatically remove obsolete app from database - ConfigManager.getInstance().updateAppCache(); + configManager.updateAppCache(); } break; } } - boolean removed = intent.getAction().equals(Intent.ACTION_PACKAGE_FULLY_REMOVED) || - intent.getAction().equals(Intent.ACTION_UID_REMOVED); + boolean removed = intentAction.equals(Intent.ACTION_PACKAGE_FULLY_REMOVED) || + intentAction.equals(Intent.ACTION_UID_REMOVED); + + Log.d(TAG, "Package changed: uid=" + uid + " userId=" + userId + " action=" + intent.getAction() + " isXposedModule=" + isXposedModule); + if (isXposedModule) { Log.d(TAG, "module " + moduleName + " changed, dispatching to manager"); - var enabledModules = ConfigManager.getInstance().enabledModules(); - var scope = ConfigManager.getInstance().getModuleScope(moduleName); + var enabledModules = configManager.enabledModules(); + var scope = configManager.getModuleScope(moduleName); boolean systemModule = scope != null && scope.parallelStream().anyMatch(app -> app.packageName.equals("android")); boolean enabled = Arrays.asList(enabledModules).contains(moduleName); if (!removed) { LSPManagerService.showNotification(moduleName, userId, enabled, systemModule); } - LSPManagerService.broadcastIntent(moduleName, userId); + LSPManagerService.broadcastIntent(moduleName, userId, intentAction.equals(Intent.ACTION_PACKAGE_FULLY_REMOVED)); } if (BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME.equals(moduleName) && userId == 0) { Log.d(TAG, "Manager updated"); try { - ConfigManager.getInstance().updateManager(removed); + configManager.updateManager(removed); LSPManagerService.createOrUpdateShortcut(false); } catch (Throwable e) { Log.e(TAG, Log.getStackTraceString(e));