Skip to content

Commit 3037c8e

Browse files
authored
Fix NoSuchMethodError of readMapXml on Android 17 Beta 3 (#626)
Starting with Android 17 Beta 3 (detected in framework.jar, though not yet published to AOSP), the internal API for XmlUtils has changed its method signature. Specifically, the return type of readMapXml was modified from HashMap to the more generic Map interface. Old signature: ``` Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap; ``` New signature: ``` Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/Map; ``` We migrate the call to use reflection.
1 parent 7ff7e06 commit 3037c8e

2 files changed

Lines changed: 33 additions & 17 deletions

File tree

hiddenapi/stubs/src/main/java/com/android/internal/util/XmlUtils.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

legacy/src/main/java/de/robv/android/xposed/XSharedPreferences.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import android.os.Environment;
77
import android.preference.PreferenceManager;
88

9-
import com.android.internal.util.XmlUtils;
10-
119
import org.lsposed.lspd.util.Utils.Log;
1210
import org.matrix.vector.impl.core.VectorServiceClient;
1311
import org.matrix.vector.impl.utils.VectorMetaDataReader;
@@ -18,6 +16,8 @@
1816
import java.io.FileNotFoundException;
1917
import java.io.IOException;
2018
import java.io.InputStream;
19+
import java.lang.reflect.InvocationTargetException;
20+
import java.lang.reflect.Method;
2121
import java.nio.file.AccessDeniedException;
2222
import java.nio.file.ClosedWatchServiceException;
2323
import java.nio.file.Path;
@@ -43,6 +43,7 @@ public final class XSharedPreferences implements SharedPreferences {
4343
private static final String TAG = "XSharedPreferences";
4444
private static final HashMap<WatchKey, PrefsData> sWatcherKeyInstances = new HashMap<>();
4545
private static final Object sContent = new Object();
46+
private static final Method sReadMapXmlMethod;
4647
private static Thread sWatcherDaemon = null;
4748
private static WatchService sWatcher;
4849

@@ -55,6 +56,19 @@ public final class XSharedPreferences implements SharedPreferences {
5556
private long mFileSize;
5657
private WatchKey mWatchKey;
5758

59+
static {
60+
Method method = null;
61+
try {
62+
// Find the class and method once during class initialization
63+
Class<?> xmlUtils = Class.forName("com.android.internal.util.XmlUtils");
64+
method = xmlUtils.getDeclaredMethod("readMapXml", InputStream.class);
65+
method.setAccessible(true);
66+
} catch (Exception e) {
67+
Log.e(TAG, "Failed to find com.android.internal.util.XmlUtils.readMapXml", e);
68+
}
69+
sReadMapXmlMethod = method;
70+
}
71+
5872
private static void initWatcherDaemon() {
5973
sWatcherDaemon = new Thread() {
6074
@Override
@@ -304,6 +318,22 @@ public void run() {
304318
}.start();
305319
}
306320

321+
private Map<?, ?> performReadMapXml(InputStream str) throws XmlPullParserException, IOException {
322+
try {
323+
if (sReadMapXmlMethod == null) throw new IOException("Internal API not found");
324+
return (Map<?, ?>) sReadMapXmlMethod.invoke(null, str);
325+
} catch (InvocationTargetException e) {
326+
// Unwrap and throw the real error
327+
Throwable cause = e.getCause();
328+
if (cause instanceof XmlPullParserException) throw (XmlPullParserException) cause;
329+
if (cause instanceof IOException) throw (IOException) cause;
330+
if (cause instanceof RuntimeException) throw (RuntimeException) cause;
331+
throw new RuntimeException(cause);
332+
} catch (IllegalAccessException e) {
333+
throw new IOException("Access denied to internal API", e);
334+
}
335+
}
336+
307337
@SuppressWarnings({"rawtypes", "unchecked"})
308338
private void loadFromDiskLocked() {
309339
if (mLoaded) {
@@ -315,7 +345,7 @@ private void loadFromDiskLocked() {
315345
try {
316346
result = SELinuxHelper.getAppDataFileService().getFileInputStream(mFilename, mFileSize, mLastModified);
317347
if (result.stream != null) {
318-
map = XmlUtils.readMapXml(result.stream);
348+
map = performReadMapXml(result.stream);
319349
result.stream.close();
320350
} else {
321351
// The file is unchanged, keep the current values

0 commit comments

Comments
 (0)