[core] Cache & check module

This commit is contained in:
LoveSy 2021-02-20 19:41:38 +08:00 committed by tehcneko
parent f56cf01e9f
commit a12336f69b
4 changed files with 81 additions and 19 deletions

View File

@ -15,7 +15,6 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
static IBinder serviceBinder = null;
static String baseCachePath = null;
static String basePrefsPath = null;
static String processName = null;
public static LSPApplicationServiceClient serviceClient = null;
@ -99,16 +98,14 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
return new String[0];
}
public String[] getModulesList(){
public String[] getModulesList() {
return getModulesList(processName);
}
@Override
public String getPrefsPath(String packageName) {
try {
if (basePrefsPath == null)
basePrefsPath = service.getPrefsPath("");
return basePrefsPath + File.separator + packageName;
return service.getPrefsPath(packageName);
} catch (RemoteException | NullPointerException ignored) {
}
return null;

View File

@ -29,6 +29,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.XResources;
import android.os.IBinder;
import io.github.lsposed.lspd.util.Hookers;
import io.github.lsposed.lspd.util.MetaDataReader;
@ -68,12 +69,6 @@ public class HandleBindAppHooker extends XC_MethodHook {
Utils.logD("processName=" + appProcessName +
", packageName=" + reportedPackageName + ", appDataDir=" + appDataDir);
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
if (instrumentationName != null) {
Hookers.logD("Instrumentation detected, disabling framework for");
XposedBridge.disableHooks = true;
return;
}
CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo");
if (appInfo.sourceDir == null) {
return;
@ -87,14 +82,14 @@ public class HandleBindAppHooker extends XC_MethodHook {
String processName = (String) XposedHelpers.getObjectField(bindData, "processName");
boolean isModule = false;
IBinder moduleBinder = serviceClient.requestModuleBinder();
boolean isModule = moduleBinder != null;
int xposedminversion = -1;
boolean xposedsharedprefs = false;
boolean xposedmigrateprefs = false;
try {
Map<String, Object> metaData = MetaDataReader.getMetaData(new File(appInfo.sourceDir));
isModule = metaData.containsKey("xposedmodule");
if (isModule) {
Map<String, Object> metaData = MetaDataReader.getMetaData(new File(appInfo.sourceDir));
Object minVersionRaw = metaData.get("xposedminversion");
if (minVersionRaw instanceof Integer) {
xposedminversion = (Integer) minVersionRaw;

View File

@ -33,7 +33,6 @@ 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;
@ -83,6 +82,7 @@ public class ConfigManager {
public void onEvent(int event, @Nullable String path) {
updateConfig();
cacheScopes();
cacheModules();
}
};
@ -126,6 +126,8 @@ public class ConfigManager {
private final ConcurrentHashMap<ProcessScope, Set<String>> cachedScope = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, String> cachedModule = new ConcurrentHashMap<>();
// 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)) {
@ -214,6 +216,7 @@ public class ConfigManager {
Log.d(TAG, "pm is ready, updating cache");
instance.packageStarted = true;
instance.cacheScopes();
instance.cacheModules();
instance.updateManager();
}
}
@ -226,6 +229,7 @@ public class ConfigManager {
isPermissive = readInt(selinuxPath, 1) == 0;
configObserver.startWatching();
cacheScopes();
cacheModules();
}
private void createTables() {
@ -242,6 +246,41 @@ public class ConfigManager {
return processes;
}
private synchronized void cacheModules() {
// skip caching when pm is not yet available
if (!packageStarted) return;
cachedModule.clear();
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"},
"enabled = 1", 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<>();
while (cursor.moveToNext()) {
String packageName = cursor.getString(pkgNameIdx);
try {
PackageInfo pkgInfo = PackageService.getPackageInfo(packageName, 0, 0);
if (pkgInfo != null && pkgInfo.applicationInfo != null) {
cachedModule.put(pkgInfo.applicationInfo.uid, pkgInfo.packageName);
} else {
obsoleteModules.add(packageName);
}
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
for (String obsoleteModule : obsoleteModules) {
removeModule(obsoleteModule);
}
}
Log.d(TAG, "cached modules");
for (int uid : cachedModule.keySet()) {
Log.d(TAG, cachedModule.get(uid) + "/" + uid);
}
}
private synchronized void cacheScopes() {
// skip caching when pm is not yet available
if (!packageStarted) return;
@ -524,6 +563,34 @@ public class ConfigManager {
}
}
public boolean isModule(int uid) {
return cachedModule.containsKey(uid);
}
private void recursivelyChown(File file, int uid, int gid) throws ErrnoException {
Os.chown(file.toString(), uid, gid);
if (file.isDirectory()) {
for (File subFile : file.listFiles()) {
recursivelyChown(subFile, uid, gid);
}
}
}
public boolean ensureModulePrefsPermission(int uid) {
String packageName = cachedModule.get(uid);
if (packageName == null) return false;
File path = new File(getPrefsPath(packageName));
try {
if (path.exists() && !path.isDirectory()) path.delete();
if (!path.exists()) Files.createDirectories(path.toPath());
recursivelyChown(path, uid, 1000);
return true;
} catch (IOException | ErrnoException e) {
Log.e(TAG, Log.getStackTraceString(e));
return false;
}
}
// migrate setting
@Keep
public static void main(String[] args) {
@ -541,9 +608,9 @@ public class ConfigManager {
int userId = Integer.parseInt(dir.getName());
System.out.println("Processing user: " + userId);
File conf = new File(dir, "conf");
if (!conf.exists()) System.exit(0);
if (!conf.exists()) continue;
File enabledModules = new File(conf, "enabled_modules.list");
if (!enabledModules.exists()) System.exit(0);
if (!enabledModules.exists()) continue;
System.out.println("updating modules...");
@ -577,6 +644,7 @@ public class ConfigManager {
}
}
System.out.println("Applying scope");
for (HashMap.Entry<String, List<Application>> entry : modulesScope.entrySet()) {
getInstance().setModuleScope(entry.getKey(), entry.getValue());
}

View File

@ -75,11 +75,13 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
return ConfigManager.getInstance().getModulesLog(ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
}
// TODO: check if module
@Override
public IBinder requestModuleBinder() throws RemoteException {
ensureRegistered();
return ServiceManager.getModuleService();
if (ConfigManager.getInstance().isModule(Binder.getCallingUid())) {
ConfigManager.getInstance().ensureModulePrefsPermission(Binder.getCallingUid());
return ServiceManager.getModuleService();
} else return null;
}
@Override