[core] Fix caching logic

This commit is contained in:
LoveSy 2021-02-20 03:30:17 +08:00 committed by tehcneko
parent bde6b6dbc3
commit 56504a5f3b
4 changed files with 42 additions and 45 deletions

View File

@ -9,6 +9,7 @@ import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -40,6 +41,8 @@ public class ConfigManager {
static final private File configPath = new File(basePath, "config");
static final private SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(configPath, "modules_config.db"), null);
boolean packageStarted = false;
static final private File resourceHookSwitch = new File(configPath, "enable_resources");
private boolean resourceHook = false;
@ -114,15 +117,16 @@ public class ConfigManager {
private final ConcurrentHashMap<ProcessScope, Set<String>> cachedScope = new ConcurrentHashMap<>();
public static boolean shouldSkipSystemServer() {
try (Cursor cursor = db.query("scope", new String[]{"mid"}, "app_pkg_name=?", new String[]{"android"}, null, null, null)) {
// for system server, cache is not yet ready, we need to query database for it
public boolean shouldSkipSystemServer() {
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"modules.mid"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) {
return cursor == null || !cursor.moveToNext();
}
}
public static String[] getModulesPathForSystemServer() {
public String[] getModulesPathForSystemServer() {
HashSet<String> modules = new HashSet<>();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"apk_path"}, "app_pkg_name=?", new String[]{"android"}, null, null, null)) {
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"apk_path"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) {
int apkPathIdx = cursor.getColumnIndex("apk_path");
while (cursor.moveToNext()) {
modules.add(cursor.getString(apkPathIdx));
@ -176,6 +180,7 @@ public class ConfigManager {
}
public synchronized void updateManager() {
if (!packageStarted) return;
try {
PackageInfo info = PackageService.getPackageInfo(readText(managerPath, DEFAULT_MANAGER_PACKAGE_NAME), 0, 0);
if (info != null) {
@ -195,6 +200,14 @@ public class ConfigManager {
static ConfigManager getInstance() {
if (instance == null)
instance = new ConfigManager();
if (!instance.packageStarted) {
if (PackageService.getPackageManager() != null) {
Log.d(TAG, "pm is ready, updating cache");
instance.packageStarted = true;
instance.cacheScopes();
instance.updateManager();
}
}
return instance;
}
@ -212,20 +225,20 @@ public class ConfigManager {
}
private List<ProcessScope> getAssociatedProcesses(Application app) throws RemoteException {
PackageInfo pkgInfo = PackageService.getPackageInfo(app.packageName, 0, app.userId);
Pair<Set<String>, Integer> result = PackageService.fetchProcessesWithUid(app);
List<ProcessScope> processes = new ArrayList<>();
if (pkgInfo != null && pkgInfo.applicationInfo != null) {
for (String process : PackageService.getProcessesForUid(pkgInfo.applicationInfo.uid, app.userId)) {
processes.add(new ProcessScope(process, pkgInfo.applicationInfo.uid));
}
for (String processName : result.first) {
processes.add(new ProcessScope(processName, result.second));
}
return processes;
}
private synchronized void cacheScopes() {
// skip caching when pm is not yet available
if (!packageStarted) return;
cachedScope.clear();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "user_id", "apk_path"},
"enabled = ?", new String[]{"1"}, null, null, null)) {
"enabled = 1", null, null, null, null)) {
if (cursor == null) {
Log.e(TAG, "db cache failed");
return;
@ -238,6 +251,8 @@ public class ConfigManager {
Application app = new Application();
app.packageName = cursor.getString(appPkgNameIdx);
app.userId = cursor.getInt(userIdIdx);
// system server always loads database
if (app.packageName.equals("android")) continue;
String apk_path = cursor.getString(apkPathIdx);
try {
List<ProcessScope> processesScope = getAssociatedProcesses(app);
@ -253,13 +268,13 @@ public class ConfigManager {
}
for (Application obsoletePackage : obsoletePackages) {
Log.d(TAG, "removing obsolete package: " + obsoletePackage.packageName + "/" + obsoletePackage.userId);
removeAppWithoutCache(obsoletePackage);
removeApp(obsoletePackage);
}
}
Log.d(TAG, "cached Scope");
for(ProcessScope ps : cachedScope.keySet()) {
for (ProcessScope ps : cachedScope.keySet()) {
Log.d(TAG, ps.processName + "/" + ps.uid);
for(String apk: cachedScope.get(ps)) {
for (String apk : cachedScope.get(ps)) {
Log.d(TAG, "\t" + apk);
}
}
@ -309,9 +324,6 @@ public class ConfigManager {
if (count < 0) {
count = db.updateWithOnConflict("modules", values, "module_pkg_name=?", new String[]{packageName}, SQLiteDatabase.CONFLICT_IGNORE);
}
if (count >= 1) {
cacheScopes();
}
return count >= 0;
}
@ -351,12 +363,11 @@ public class ConfigManager {
db.setTransactionSuccessful();
db.endTransaction();
}
cacheScopes();
return true;
}
public String[] enabledModules() {
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, "enabled = 1", null, null, null, null)) {
if (cursor == null) {
Log.e(TAG, "query enabled modules failed");
return null;
@ -381,7 +392,6 @@ public class ConfigManager {
db.setTransactionSuccessful();
db.endTransaction();
}
cacheScopes();
return true;
}
@ -397,7 +407,6 @@ public class ConfigManager {
db.setTransactionSuccessful();
db.endTransaction();
}
cacheScopes();
return true;
}
@ -414,23 +423,14 @@ public class ConfigManager {
db.setTransactionSuccessful();
db.endTransaction();
}
cacheScopes();
return true;
}
public boolean removeAppWithoutCache(Application app) {
public boolean removeApp(Application app) {
int count = db.delete("scope", "app_pkg_name = ? AND user_id=?", new String[]{app.packageName, String.valueOf(app.userId)});
return count >= 1;
}
public boolean removeApp(Application scope) {
if (removeAppWithoutCache(scope)) {
cacheScopes();
return true;
}
return false;
}
public void setResourceHook(boolean resourceHook) {
writeInt(resourceHookSwitch, resourceHook ? 1 : 0);
this.resourceHook = resourceHook;

View File

@ -52,7 +52,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
ensureRegistered();
int callingUid = Binder.getCallingUid();
if (callingUid == 1000 && processName.equals("android")) {
ConfigManager.getModulesPathForSystemServer();
return ConfigManager.getInstance().getModulesPathForSystemServer();
}
return ConfigManager.getInstance().getModulesPathForProcess(processName, callingUid);
}

View File

@ -20,7 +20,7 @@ public class LSPosedService extends ILSPosedService.Stub {
return null;
}
if (uid == 1000 && processName.equals("android")) {
if (ConfigManager.shouldSkipSystemServer())
if (ConfigManager.getInstance().shouldSkipSystemServer())
return null;
else
return ServiceManager.getApplicationService();

View File

@ -8,11 +8,14 @@ import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import io.github.lsposed.lspd.Application;
import io.github.lsposed.lspd.utils.ParceledListSlice;
import static android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS;
@ -41,14 +44,6 @@ public class PackageService {
return pm.getPackagesForUid(uid);
}
public static Set<String> getProcessesForUid(int uid, int userId) throws RemoteException {
HashSet<String> processNames = new HashSet<>();
for (String packageName : getPackagesForUid(uid)) {
processNames.addAll(fetchProcesses(packageName, userId));
}
return processNames;
}
public static ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) throws RemoteException {
ArrayList<PackageInfo> res = new ArrayList<>();
IPackageManager pm = getPackageManager();
@ -82,12 +77,14 @@ public class PackageService {
return processNames;
}
public static Set<String> fetchProcesses(String packageName, int userId) throws RemoteException {
public static Pair<Set<String>, Integer> fetchProcessesWithUid(Application app) throws RemoteException {
IPackageManager pm = getPackageManager();
if (pm == null) return new HashSet<>();
PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.MATCH_DISABLED_COMPONENTS |
if (pm == null) return new Pair<>(Collections.emptySet(), -1);
PackageInfo pkgInfo = pm.getPackageInfo(app.packageName, PackageManager.MATCH_DISABLED_COMPONENTS |
PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE |
PackageManager.GET_SERVICES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS, userId);
return fetchProcesses(pkgInfo);
PackageManager.GET_SERVICES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS, app.userId);
if (pkgInfo == null || pkgInfo.applicationInfo == null)
return new Pair<>(Collections.emptySet(), -1);
return new Pair<>(fetchProcesses(pkgInfo), pkgInfo.applicationInfo.uid);
}
}