diff --git a/meta-loader/src/main/java/org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub.java b/meta-loader/src/main/java/org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub.java index 83b7412..9640684 100644 --- a/meta-loader/src/main/java/org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub.java +++ b/meta-loader/src/main/java/org/lsposed/lspatch/metaloader/LSPAppComponentFactoryStub.java @@ -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)); diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java index 9b5fc7f..e499603 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java @@ -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 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) {