From cb665d4eeb3170375297f9bf332cc71d8bfafe9b Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 18 May 2021 19:04:10 +0800 Subject: [PATCH] [core] Clean scope automatically for mutli-users (#620) --- .../lsposed/lspd/service/ConfigManager.java | 60 +++++++++++++++---- .../lsposed/lspd/service/LSPosedService.java | 5 +- .../lsposed/lspd/service/PackageService.java | 14 +++-- .../android/content/pm/IPackageManager.java | 3 +- 4 files changed, 63 insertions(+), 19 deletions(-) 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 aa311f30..68080af3 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -55,8 +55,10 @@ import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -304,30 +306,46 @@ public class ConfigManager { if (lastModuleCacheTime >= requestModuleCacheTime) return; else lastModuleCacheTime = SystemClock.elapsedRealtime(); cachedModule.clear(); - try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, - "enabled = 1", null, null, null, null)) { + try (Cursor cursor = db.query(true, "modules INNER JOIN scope ON scope.mid = modules.mid", new String[]{"module_pkg_name", "user_id"}, + "enabled = 1", null, null, null, null, null)) { if (cursor == null) { Log.e(TAG, "db cache failed"); return; } int pkgNameIdx = cursor.getColumnIndex("module_pkg_name"); - HashSet obsoleteModules = new HashSet<>(); + int userIdIdx = cursor.getColumnIndex("user_id"); + Map> modules = new HashMap<>(); + Set obsoleteModules = new HashSet<>(); + Set obsoleteScopes = new HashSet<>(); while (cursor.moveToNext()) { String packageName = cursor.getString(pkgNameIdx); - try { - PackageInfo pkgInfo = PackageService.getPackageInfoFromAllUsers(packageName, PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_UNINSTALLED_PACKAGES); - if (pkgInfo != null && pkgInfo.applicationInfo != null) { - cachedModule.put(pkgInfo.applicationInfo.uid % PER_USER_RANGE, pkgInfo.packageName); - } else { - obsoleteModules.add(packageName); + int userId = cursor.getInt(userIdIdx); + var pkgInfo = modules.computeIfAbsent(packageName, m -> { + try { + return PackageService.getPackageInfoFromAllUsers(m, PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_UNINSTALLED_PACKAGES); + } catch (Throwable e) { + Log.e(TAG, Log.getStackTraceString(e)); + return Collections.emptyMap(); } - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(e)); + }); + if (pkgInfo.isEmpty()) { + obsoleteModules.add(packageName); + } else if (!pkgInfo.containsKey(userId)) { + var module = new Application(); + module.packageName = packageName; + module.userId = userId; + obsoleteScopes.add(module); + } else { + var info = pkgInfo.get(userId); + cachedModule.computeIfAbsent(info.applicationInfo.uid % PER_USER_RANGE, k -> info.packageName); } } - for (String obsoleteModule : obsoleteModules) { + for (var obsoleteModule : obsoleteModules) { removeModuleWithoutCache(obsoleteModule); } + for (var obsoleteScope : obsoleteScopes) { + removeModuleScopeWithoutCache(obsoleteScope); + } } Log.d(TAG, "cached modules"); for (int uid : cachedModule.keySet()) { @@ -518,6 +536,19 @@ public class ConfigManager { return true; } + private boolean removeModuleScopeWithoutCache(Application module) { + int mid = getModuleId(module.packageName); + if (mid == -1) return false; + try { + db.beginTransaction(); + db.delete("scope", "mid = ? and user_id = ?", new String[]{String.valueOf(mid), String.valueOf(module.userId)}); + } finally { + db.setTransactionSuccessful(); + db.endTransaction(); + } + return true; + } + public boolean disableModule(String packageName) { int mid = getModuleId(packageName); if (mid == -1) return false; @@ -553,6 +584,11 @@ public class ConfigManager { return true; } + public void updateCache() { + // Called by oneway binder + updateCaches(true); + } + public void updateAppCache() { // Called by oneway binder cacheScopes(); 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 fb4c6cd5..9d5af353 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -115,7 +115,10 @@ public class LSPosedService extends ILSPosedService.Stub { case Intent.ACTION_UID_REMOVED: { // when a package is removed (rather than hide) for a single user // (apk may still be there because of multi-user) - if (ConfigManager.getInstance().isUidHooked(uid)) { + if (ConfigManager.getInstance().isModule(uid)) { + // it will automatically remove obsolete scope from database + ConfigManager.getInstance().updateCache(); + } else if (ConfigManager.getInstance().isUidHooked(uid)) { // it will automatically remove obsolete app from database ConfigManager.getInstance().updateAppCache(); } diff --git a/core/src/main/java/org/lsposed/lspd/service/PackageService.java b/core/src/main/java/org/lsposed/lspd/service/PackageService.java index 8b99c3f3..ab42df0f 100644 --- a/core/src/main/java/org/lsposed/lspd/service/PackageService.java +++ b/core/src/main/java/org/lsposed/lspd/service/PackageService.java @@ -43,6 +43,8 @@ import android.os.ServiceManager; import android.util.Log; import android.util.Pair; +import androidx.annotation.NonNull; + import org.lsposed.lspd.Application; import org.lsposed.lspd.BuildConfig; import org.lsposed.lspd.util.InstallerVerifier; @@ -56,8 +58,10 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; @@ -102,14 +106,15 @@ public class PackageService { return pm.getPackageInfo(packageName, flags, userId); } - public static PackageInfo getPackageInfoFromAllUsers(String packageName, int flags) throws RemoteException { + public static @NonNull Map getPackageInfoFromAllUsers(String packageName, int flags) throws RemoteException { IPackageManager pm = getPackageManager(); - if (pm == null) return null; + Map res = new HashMap<>(); + if (pm == null) return res; for (int userId : UserService.getUsers()) { var info = pm.getPackageInfo(packageName, flags, userId); - if (info != null) return info; + if (info != null && info.applicationInfo != null) res.put(userId, info); } - return null; + return res; } public static ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) throws RemoteException { @@ -328,4 +333,5 @@ public class PackageService { return false; } } + } diff --git a/hiddenapi-stubs/src/main/java/android/content/pm/IPackageManager.java b/hiddenapi-stubs/src/main/java/android/content/pm/IPackageManager.java index 751e6973..790e3a97 100644 --- a/hiddenapi-stubs/src/main/java/android/content/pm/IPackageManager.java +++ b/hiddenapi-stubs/src/main/java/android/content/pm/IPackageManager.java @@ -17,8 +17,7 @@ public interface IPackageManager extends IInterface { PackageInfo getPackageInfo(String packageName, int flags, int userId) throws RemoteException; - int getPackageUid(String packageName, int userId) - throws RemoteException; + int getPackageUid(String packageName, int flags, int userId) throws RemoteException; String[] getPackagesForUid(int uid) throws RemoteException;