[core] Fix caching logic
This commit is contained in:
parent
bde6b6dbc3
commit
56504a5f3b
|
|
@ -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,13 +268,13 @@ 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");
|
||||||
for(ProcessScope ps : cachedScope.keySet()) {
|
for (ProcessScope ps : cachedScope.keySet()) {
|
||||||
Log.d(TAG, ps.processName + "/" + ps.uid);
|
Log.d(TAG, ps.processName + "/" + ps.uid);
|
||||||
for(String apk: cachedScope.get(ps)) {
|
for (String apk : cachedScope.get(ps)) {
|
||||||
Log.d(TAG, "\t" + apk);
|
Log.d(TAG, "\t" + apk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue