Fix miscPath initialization order in daemon cache bootstrap#678
Fix miscPath initialization order in daemon cache bootstrap#678JingMatrix merged 1 commit intoJingMatrix:masterfrom
Conversation
|
I think the initialization of miscPath should not depend on PackageManager, as they don’t seem related. That’s why the initialization was moved out of the condition to the beginning of the method. The root cause is that the condition was not met at the moment when CorePatch attempted to read via XSharedPreferences. Here is the problematic line in the CorePatch repository. At the moment it is invoked, the condition in ensureCacheReady is not satisfied. |
|
@kiber-io Please upload the Vector log, for me to understand better why it only happens on certain device but not all. |
|
@JingMatrix Of course, but it won’t bring any benefit, since the error "Fatal: miscPath not initialized" is suppressed in VectorServiceClient.getPrefsPath and doesn’t appear in the logs. override fun getPrefsPath(packageName: String): String? {
return runCatching { service?.getPrefsPath(packageName) }.getOrNull()
}I’m attaching two log archives - one from the latest CI build of vector (before my PR, of course), and logs from my debug build with the issue described above fixed, along with some additional logging. diff --git a/xposed/src/main/kotlin/org/matrix/vector/impl/core/VectorServiceClient.kt b/xposed/src/main/kotlin/org/matrix/vector/impl/core/VectorServiceClient.kt
index fc70e909..f56cdb41 100644
--- a/xposed/src/main/kotlin/org/matrix/vector/impl/core/VectorServiceClient.kt
+++ b/xposed/src/main/kotlin/org/matrix/vector/impl/core/VectorServiceClient.kt
@@ -47,7 +47,23 @@ object VectorServiceClient : ILSPApplicationService, IBinder.DeathRecipient {
}
override fun getPrefsPath(packageName: String): String? {
- return runCatching { service?.getPrefsPath(packageName) }.getOrNull()
+ val appService = service
+ if (appService == null) {
+ Log.w(
+ TAG,
+ "getPrefsPath called with null service, package=$packageName, process=$processName",
+ )
+ return null
+ }
+ return runCatching { appService.getPrefsPath(packageName) }
+ .onFailure {
+ Log.e(
+ TAG,
+ "getPrefsPath failed for package=$packageName, process=$processName, binderAlive=${appService.asBinder()?.isBinderAlive == true}",
+ it,
+ )
+ }
+ .getOrNull()
}diff --git a/legacy/src/main/java/de/robv/android/xposed/XSharedPreferences.java b/legacy/src/main/java/de/robv/android/xposed/XSharedPreferences.java
index e3976013..08430e3b 100644
--- a/legacy/src/main/java/de/robv/android/xposed/XSharedPreferences.java
+++ b/legacy/src/main/java/de/robv/android/xposed/XSharedPreferences.java
@@ -153,8 +153,14 @@ public final class XSharedPreferences implements SharedPreferences {
* @param prefFileName The file name without ".xml".
*/
public XSharedPreferences(String packageName, String prefFileName) {
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "ctor(packageName=" + packageName + ", prefFileName=" + prefFileName + ")");
+ }
boolean newModule = false;
var m = XposedInit.getLoadedModules().getOrDefault(packageName, Optional.empty());
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "loadedModuleEntry present=" + m.isPresent() + (m.isPresent() ? ", apkPath=" + m.get() : ""));
+ }
if (m.isPresent()) {
boolean isModule = false;
int xposedminversion = -1;
@@ -171,17 +177,41 @@ public final class XSharedPreferences implements SharedPreferences {
}
xposedsharedprefs = metaData.containsKey("xposedsharedprefs");
}
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "moduleMeta: isModule=" + isModule
+ + ", xposedminversion=" + xposedminversion
+ + ", xposedsharedprefs=" + xposedsharedprefs);
+ }
} catch (NumberFormatException | IOException e) {
Log.w(TAG, "Apk parser fails: " + e);
}
newModule = isModule && (xposedminversion > 92 || xposedsharedprefs);
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "newModule decision=" + newModule
+ + " (isModule=" + isModule
+ + ", minVersion>92=" + (xposedminversion > 92)
+ + ", sharedPrefsFlag=" + xposedsharedprefs + ")");
+ }
+ } else if (BuildConfig.DEBUG) {
+ Log.d(TAG, "moduleMeta unavailable for package " + packageName + ", falling back to legacy path");
}
if (newModule) {
- mFile = new File(VectorServiceClient.INSTANCE.getPrefsPath(packageName), prefFileName + ".xml");
+ String prefsDir = VectorServiceClient.INSTANCE.getPrefsPath(packageName);
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "using VectorService prefs dir: " + prefsDir);
+ }
+ mFile = new File(prefsDir, prefFileName + ".xml");
} else {
mFile = new File(Environment.getDataDirectory(), "data/" + packageName + "/shared_prefs/" + prefFileName + ".xml");
}
mFilename = mFile.getAbsolutePath();
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "resolved prefs file=" + mFilename
+ + ", exists=" + mFile.exists()
+ + ", canRead=" + mFile.canRead()
+ + ", parent=" + (mFile.getParentFile() != null ? mFile.getParentFile().getAbsolutePath() : "null")
+ + ", parentExists=" + (mFile.getParentFile() != null && mFile.getParentFile().exists()));
+ }
init();
}Here is the actual error log from the second archive: P.S. My Pixel also decided to update itself again, ignoring disabled automatic updates, so now my system build is higher, but the issue from the PR is still present. LSPosed_2026-04-17T10_53_27.419731_my_custom_debug_build.zip |
|
As I suspected, the issue isn’t limited to one device - on my second device, a Xiaomi 14 running HyperOS 3 on Android 16, I’m experiencing the same problem with the same error. |
|
I see, on some devices, the |
The `ensureCacheReady` method waits for the 'package' service, which is often unavailable when modules inject into `system_server`. This leads to an uninitialized `miscPath` when `getPrefsPath` is called early. We thus call `setupMiscPath` directly in `getPrefsPath` to bypass the package service dependency, and add a null check to avoid redundant initialization.
|
@kiber-io I made a simpler change, please test if it solves the issue. |
Yes, it works |
I hit this issue while testing CorePatch on Pixel 7, build CP1A.260305.018 (Android 16), and I also saw similar behavior on older ROMs / older LSPosed versions.
This is specifically related to XSharedPreferences path resolution in hooked processes.
The module process itself could read/update settings and correctly wrote XML into /data/misc/.
But when a hooked process initialized XSharedPreferences, getPrefsPath() could return an uninitialized/invalid path state (effectively null path behavior), so preferences failed to load.
So the problem is initialization order around miscPath availability at the time XSharedPreferences requests preference path resolution.