[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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
@ -304,30 +306,46 @@ public class ConfigManager {
|
||||||
if (lastModuleCacheTime >= requestModuleCacheTime) return;
|
if (lastModuleCacheTime >= requestModuleCacheTime) return;
|
||||||
else lastModuleCacheTime = SystemClock.elapsedRealtime();
|
else lastModuleCacheTime = SystemClock.elapsedRealtime();
|
||||||
cachedModule.clear();
|
cachedModule.clear();
|
||||||
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"},
|
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)) {
|
"enabled = 1", null, null, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
Log.e(TAG, "db cache failed");
|
Log.e(TAG, "db cache failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int pkgNameIdx = cursor.getColumnIndex("module_pkg_name");
|
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()) {
|
while (cursor.moveToNext()) {
|
||||||
String packageName = cursor.getString(pkgNameIdx);
|
String packageName = cursor.getString(pkgNameIdx);
|
||||||
try {
|
int userId = cursor.getInt(userIdIdx);
|
||||||
PackageInfo pkgInfo = PackageService.getPackageInfoFromAllUsers(packageName, PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_UNINSTALLED_PACKAGES);
|
var pkgInfo = modules.computeIfAbsent(packageName, m -> {
|
||||||
if (pkgInfo != null && pkgInfo.applicationInfo != null) {
|
try {
|
||||||
cachedModule.put(pkgInfo.applicationInfo.uid % PER_USER_RANGE, pkgInfo.packageName);
|
return PackageService.getPackageInfoFromAllUsers(m, PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_UNINSTALLED_PACKAGES);
|
||||||
} else {
|
} catch (Throwable e) {
|
||||||
obsoleteModules.add(packageName);
|
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);
|
removeModuleWithoutCache(obsoleteModule);
|
||||||
}
|
}
|
||||||
|
for (var obsoleteScope : obsoleteScopes) {
|
||||||
|
removeModuleScopeWithoutCache(obsoleteScope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Log.d(TAG, "cached modules");
|
Log.d(TAG, "cached modules");
|
||||||
for (int uid : cachedModule.keySet()) {
|
for (int uid : cachedModule.keySet()) {
|
||||||
|
|
@ -518,6 +536,19 @@ public class ConfigManager {
|
||||||
return true;
|
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) {
|
public boolean disableModule(String packageName) {
|
||||||
int mid = getModuleId(packageName);
|
int mid = getModuleId(packageName);
|
||||||
if (mid == -1) return false;
|
if (mid == -1) return false;
|
||||||
|
|
@ -553,6 +584,11 @@ public class ConfigManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateCache() {
|
||||||
|
// Called by oneway binder
|
||||||
|
updateCaches(true);
|
||||||
|
}
|
||||||
|
|
||||||
public void updateAppCache() {
|
public void updateAppCache() {
|
||||||
// Called by oneway binder
|
// Called by oneway binder
|
||||||
cacheScopes();
|
cacheScopes();
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,10 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
case Intent.ACTION_UID_REMOVED: {
|
case Intent.ACTION_UID_REMOVED: {
|
||||||
// when a package is removed (rather than hide) for a single user
|
// when a package is removed (rather than hide) for a single user
|
||||||
// (apk may still be there because of multi-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
|
// it will automatically remove obsolete app from database
|
||||||
ConfigManager.getInstance().updateAppCache();
|
ConfigManager.getInstance().updateAppCache();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ import android.os.ServiceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.lsposed.lspd.Application;
|
import org.lsposed.lspd.Application;
|
||||||
import org.lsposed.lspd.BuildConfig;
|
import org.lsposed.lspd.BuildConfig;
|
||||||
import org.lsposed.lspd.util.InstallerVerifier;
|
import org.lsposed.lspd.util.InstallerVerifier;
|
||||||
|
|
@ -56,8 +58,10 @@ import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
@ -102,14 +106,15 @@ public class PackageService {
|
||||||
return pm.getPackageInfo(packageName, flags, userId);
|
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();
|
IPackageManager pm = getPackageManager();
|
||||||
if (pm == null) return null;
|
Map<Integer, PackageInfo> res = new HashMap<>();
|
||||||
|
if (pm == null) return res;
|
||||||
for (int userId : UserService.getUsers()) {
|
for (int userId : UserService.getUsers()) {
|
||||||
var info = pm.getPackageInfo(packageName, flags, userId);
|
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 {
|
public static ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) throws RemoteException {
|
||||||
|
|
@ -328,4 +333,5 @@ public class PackageService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@ public interface IPackageManager extends IInterface {
|
||||||
PackageInfo getPackageInfo(String packageName, int flags, int userId)
|
PackageInfo getPackageInfo(String packageName, int flags, int userId)
|
||||||
throws RemoteException;
|
throws RemoteException;
|
||||||
|
|
||||||
int getPackageUid(String packageName, int userId)
|
int getPackageUid(String packageName, int flags, int userId) throws RemoteException;
|
||||||
throws RemoteException;
|
|
||||||
|
|
||||||
String[] getPackagesForUid(int uid)
|
String[] getPackagesForUid(int uid)
|
||||||
throws RemoteException;
|
throws RemoteException;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue