fix: 优化 manager 连接与禁用 profile 文件
修正 manager 连接失败时的回退逻辑,避免 service 为 null,统一本地服务处理。新增 disableProfile 方法,自动清理和禁用 profile 文件,防止 profile 干扰运行。
This commit is contained in:
parent
4d7f56c21c
commit
b076eed005
|
|
@ -1,8 +1,8 @@
|
|||
package org.lsposed.lspatch.metaloader;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AppComponentFactory;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AppComponentFactory;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.os.Build;
|
||||
|
|
@ -76,14 +76,16 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
|
|||
}
|
||||
}
|
||||
|
||||
int currentUserId = Process.myUid() / 100000;
|
||||
|
||||
if (useManager) {
|
||||
Log.i(TAG, "Bootstrap loader from manager");
|
||||
var ipm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
|
||||
ApplicationInfo manager;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
manager = (ApplicationInfo) HiddenApiBypass.invoke(IPackageManager.class, ipm, "getApplicationInfo", Constants.MANAGER_PACKAGE_NAME, 0L, Process.myUid() / 100000);
|
||||
manager = (ApplicationInfo) HiddenApiBypass.invoke(IPackageManager.class, ipm, "getApplicationInfo", Constants.MANAGER_PACKAGE_NAME, 0L, currentUserId);
|
||||
} else {
|
||||
manager = ipm.getApplicationInfo(Constants.MANAGER_PACKAGE_NAME, 0, Process.myUid() / 100000);
|
||||
manager = ipm.getApplicationInfo(Constants.MANAGER_PACKAGE_NAME, 0, currentUserId);
|
||||
}
|
||||
try (var zip = new ZipFile(new File(manager.sourceDir));
|
||||
var is = zip.getInputStream(zip.getEntry(Constants.LOADER_DEX_ASSET_PATH));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.content.pm.ApplicationInfo;
|
|||
import android.content.res.CompatibilityInfo;
|
||||
import android.os.Build;
|
||||
import android.os.RemoteException;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
|
@ -40,6 +41,7 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -72,15 +74,6 @@ public class LSPApplication {
|
|||
return (android.os.Process.myUid() % PER_USER_RANGE) >= FIRST_APP_ZYGOTE_ISOLATED_UID;
|
||||
}
|
||||
|
||||
private static boolean hasEmbeddedModules(Context context) {
|
||||
try {
|
||||
String[] list = context.getAssets().list("lspatch/modules");
|
||||
return list != null && list.length > 0;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLoad() throws RemoteException, IOException {
|
||||
if (isIsolated()) {
|
||||
XLog.d(TAG, "Skip isolated process");
|
||||
|
|
@ -94,8 +87,7 @@ public class LSPApplication {
|
|||
}
|
||||
|
||||
Log.d(TAG, "Initialize service client");
|
||||
ILSPApplicationService service = null;
|
||||
|
||||
ILSPApplicationService service;
|
||||
if (config.useManager) {
|
||||
try {
|
||||
service = new RemoteApplicationService(context);
|
||||
|
|
@ -107,28 +99,19 @@ public class LSPApplication {
|
|||
moduleObj.put("packageName", module.packageName);
|
||||
moduleArr.put(moduleObj);
|
||||
}
|
||||
SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE);
|
||||
shared.edit().putString("modules", moduleArr.toString()).apply();
|
||||
Log.i(TAG, "Success update module scope from Manager");
|
||||
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "Failed to connect to manager: " + e.getMessage());
|
||||
service = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (service == null) {
|
||||
|
||||
if (hasEmbeddedModules(context)) {
|
||||
Log.i(TAG, "Using Integrated Service (Embedded Modules Found)");
|
||||
service = new IntegrApplicationService(context);
|
||||
} else {
|
||||
Log.i(TAG, "Using NeoLocal Service (Cached Config)");
|
||||
SharedPreferences shared = context.getSharedPreferences("opatch", Context.MODE_PRIVATE);
|
||||
shared.edit().putString("modules",moduleArr.toString()).commit();
|
||||
Log.e(TAG, "Success update module scope");
|
||||
}catch (Exception e){
|
||||
Log.e(TAG, "Failed to connect to manager, fallback to fixed local service");
|
||||
service = new NeoLocalApplicationService(context);
|
||||
}
|
||||
|
||||
} else {
|
||||
service = new IntegrApplicationService(context);
|
||||
}
|
||||
|
||||
|
||||
disableProfile(context);
|
||||
Startup.initXposed(false, ActivityThread.currentProcessName(), context.getApplicationInfo().dataDir, service);
|
||||
Startup.bootstrapXposed();
|
||||
// WARN: Since it uses `XResource`, the following class should not be initialized
|
||||
|
|
@ -209,6 +192,7 @@ public class LSPApplication {
|
|||
appLoadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
|
||||
|
||||
|
||||
|
||||
if (config.injectProvider){
|
||||
ClassLoader loader = appLoadedApk.getClassLoader();
|
||||
Object dexPathList = XposedHelpers.getObjectField(loader, "pathList");
|
||||
|
|
@ -268,6 +252,53 @@ public class LSPApplication {
|
|||
}
|
||||
}
|
||||
|
||||
public static void disableProfile(Context context) {
|
||||
final ArrayList<String> codePaths = new ArrayList<>();
|
||||
var appInfo = context.getApplicationInfo();
|
||||
var pkgName = context.getPackageName();
|
||||
if (appInfo == null) return;
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
|
||||
codePaths.add(appInfo.sourceDir);
|
||||
}
|
||||
if (appInfo.splitSourceDirs != null) {
|
||||
Collections.addAll(codePaths, appInfo.splitSourceDirs);
|
||||
}
|
||||
|
||||
if (codePaths.isEmpty()) {
|
||||
// If there are no code paths there's no need to setup a profile file and register with
|
||||
// the runtime,
|
||||
return;
|
||||
}
|
||||
|
||||
var profileDir = HiddenApiBridge.Environment_getDataProfilesDePackageDirectory(appInfo.uid / PER_USER_RANGE, pkgName);
|
||||
|
||||
var attrs = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("r--------"));
|
||||
|
||||
for (int i = codePaths.size() - 1; i >= 0; i--) {
|
||||
String splitName = i == 0 ? null : appInfo.splitNames[i - 1];
|
||||
File curProfileFile = new File(profileDir, splitName == null ? "primary.prof" : splitName + ".split.prof").getAbsoluteFile();
|
||||
Log.d(TAG, "Processing " + curProfileFile.getAbsolutePath());
|
||||
try {
|
||||
if (!curProfileFile.canWrite() && Files.size(curProfileFile.toPath()) == 0) {
|
||||
Log.d(TAG, "Skip profile " + curProfileFile.getAbsolutePath());
|
||||
continue;
|
||||
}
|
||||
if (curProfileFile.exists() && !curProfileFile.delete()) {
|
||||
try (var writer = new FileOutputStream(curProfileFile)) {
|
||||
Log.d(TAG, "Failed to delete, try to clear content " + curProfileFile.getAbsolutePath());
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "Failed to delete and clear profile file " + curProfileFile.getAbsolutePath(), e);
|
||||
}
|
||||
Os.chmod(curProfileFile.getAbsolutePath(), 00400);
|
||||
} else {
|
||||
Files.createFile(curProfileFile.toPath(), attrs);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "Failed to disable profile file " + curProfileFile.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void switchAllClassLoader() {
|
||||
var fields = LoadedApk.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue