[core] Clean scope automatically for mutli-users (#620)
This commit is contained in:
parent
fd32c3107a
commit
cb665d4eeb
|
|
@ -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<String> obsoleteModules = new HashSet<>();
|
||||
int userIdIdx = cursor.getColumnIndex("user_id");
|
||||
Map<String, Map<Integer, PackageInfo>> modules = new HashMap<>();
|
||||
Set<String> obsoleteModules = new HashSet<>();
|
||||
Set<Application> 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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Integer, PackageInfo> getPackageInfoFromAllUsers(String packageName, int flags) throws RemoteException {
|
||||
IPackageManager pm = getPackageManager();
|
||||
if (pm == null) return null;
|
||||
Map<Integer, PackageInfo> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue