[core] Clean scope automatically for mutli-users (#620)

This commit is contained in:
LoveSy 2021-05-18 19:04:10 +08:00 committed by GitHub
parent fd32c3107a
commit cb665d4eeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 19 deletions

View File

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

View File

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

View File

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

View File

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