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

View File

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

View File

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

View File

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