Created
July 19, 2017 14:29
-
-
Save nhachicha/af37272b57320ae3421ea3aa518d7032 to your computer and use it in GitHub Desktop.
Dump Realms configuration and SyncUser Using Reflection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void dumpAllRealms() { | |
try { | |
StringBuilder report = | |
new StringBuilder("*******************************************************************************\n") | |
.append("********* D U M P I N G R E A L M I N S T A N C E S [ S T A R T ] **********\n") | |
.append("*******************************************************************************\n\n"); | |
int nbrRealm = 0; | |
Class<?> realmCacheClazz = Class.forName("io.realm.RealmCache"); | |
java.lang.reflect.Method getConfigurationMethod = realmCacheClazz.getMethod("getConfiguration"); | |
java.lang.reflect.Field cachesListField = realmCacheClazz.getDeclaredField("cachesList"); | |
java.lang.reflect.Field refAndCountMapField = realmCacheClazz.getDeclaredField("refAndCountMap"); | |
java.lang.reflect.Method getSyncUserMethod = SyncUser.class.getDeclaredMethod("getSyncUser"); | |
cachesListField.setAccessible(true); | |
refAndCountMapField.setAccessible(true); | |
getSyncUserMethod.setAccessible(true); | |
java.lang.reflect.Field typed_realm = null; | |
java.lang.reflect.Field dynamic_realm = null; | |
Class[] classes = realmCacheClazz.getDeclaredClasses(); | |
for (Class innerClass : classes) { | |
if (innerClass.getName().contains("RealmCacheType")) { | |
typed_realm = innerClass.getDeclaredField("TYPED_REALM"); | |
dynamic_realm = innerClass.getDeclaredField("DYNAMIC_REALM"); | |
typed_realm.setAccessible(true); | |
dynamic_realm.setAccessible(true); | |
break; | |
} | |
} | |
java.util.List<java.lang.ref.WeakReference<?>> cachesList = (java.util.List<java.lang.ref.WeakReference<?>>) cachesListField.get(null); | |
for (java.lang.ref.WeakReference<?> cache : cachesList) { | |
Object realmCache = cache.get(); | |
if (realmCache != null) { | |
io.realm.RealmConfiguration configuration = (io.realm.RealmConfiguration) getConfigurationMethod.invoke(realmCache); | |
java.util.EnumMap refAndCountMap = (java.util.EnumMap) refAndCountMapField.get(realmCache); | |
Object refAndCountTyped = refAndCountMap.get(typed_realm.get(realmCache)); | |
Object refAndCountDynamic = refAndCountMap.get(dynamic_realm.get(realmCache)); | |
report.append("\nRealm ").append(++nbrRealm).append(":\n"); | |
report.append("\tConfiguration: ").append(configuration.toString()); | |
java.lang.reflect.Field globalCountTypedField = refAndCountTyped.getClass().getDeclaredField("globalCount"); | |
java.lang.reflect.Field globalCountDynamicField = refAndCountDynamic.getClass().getDeclaredField("globalCount"); | |
globalCountTypedField.setAccessible(true); | |
globalCountDynamicField.setAccessible(true); | |
Integer globalCountTyped = (Integer) globalCountTypedField.get(refAndCountTyped); | |
Integer globalCountDynamic = (Integer) globalCountDynamicField.get(refAndCountDynamic); | |
if (globalCountTyped != null && globalCountTyped > 0) { | |
report.append("\n\tNumber of Threads opening the Realm: ").append(globalCountTyped).append("\n"); | |
} | |
if (globalCountDynamic != null && globalCountDynamic > 0) { | |
report.append("\tNumber of Threads opening the DynamicRealm: ").append(globalCountDynamic).append("\n"); | |
} | |
if (configuration instanceof SyncConfiguration) { | |
io.realm.internal.objectserver.ObjectServerUser syncUser = (io.realm.internal.objectserver.ObjectServerUser) getSyncUserMethod.invoke(((SyncConfiguration) configuration).getUser()); | |
report.append("\n\tSyncUser refreshToken=").append(syncUser.getUserToken().toJson()).append("\n\n"); | |
java.util.Collection<io.realm.internal.objectserver.ObjectServerUser.AccessDescription> realms = syncUser.getRealms(); | |
report.append("\tSyncUser associated Realms: \n"); | |
for (io.realm.internal.objectserver.ObjectServerUser.AccessDescription description : realms) { | |
report.append("\t\tdescription: ").append(description.toJson()).append("\n"); | |
} | |
} | |
} | |
} | |
report.append("\n Number of open Realms instances per Thread\n"); | |
// Walk up all the way to the root thread group | |
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); | |
ThreadGroup parent; | |
while ((parent = rootGroup.getParent()) != null) { | |
rootGroup = parent; | |
} | |
Thread[] threadArray = new Thread[100]; | |
int nbCopiedThreads = rootGroup.enumerate(threadArray, true); | |
java.util.HashSet<Thread> threads = new java.util.HashSet<Thread>(nbCopiedThreads); | |
threads.addAll(java.util.Arrays.asList(threadArray).subList(0, nbCopiedThreads)); | |
// add current thread | |
threads.add(Thread.currentThread()); | |
Class<?> baseRealmClazz = Class.forName("io.realm.BaseRealm"); | |
for (Thread t : threads) { | |
if (t == null) continue; | |
try { | |
java.lang.reflect.Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); | |
threadLocalsField.setAccessible(true); | |
Object threadLocals = threadLocalsField.get(t); | |
if (threadLocals != null) { | |
java.lang.reflect.Field tableField = threadLocals.getClass().getDeclaredField("table"); | |
tableField.setAccessible(true); | |
Object[] table = (Object[]) tableField.get(threadLocals); | |
boolean realmcacheFound = false; | |
java.util.ArrayList<Integer> instanceRefCounts = new java.util.ArrayList<Integer>(); | |
for (Object entry : table) { | |
if (entry != null) { | |
java.lang.reflect.Field field3 = entry.getClass().getDeclaredField("value"); | |
field3.setAccessible(true); | |
Object entryVal = field3.get(entry); | |
if (entryVal != null && baseRealmClazz.isAssignableFrom(entryVal.getClass())) { | |
realmcacheFound = true; | |
} else if (entryVal instanceof Integer) { | |
instanceRefCounts.add((Integer) entryVal); | |
} | |
} | |
} | |
if (realmcacheFound) { | |
report.append("\t\tname: ").append(t.getName()).append(" id: ").append(t.getId()); | |
if (instanceRefCounts.size() == 1) { | |
report.append(" number of open instances: ").append(instanceRefCounts.get(0)).append("\n"); | |
} else { | |
// multiple integers values stored as ThreadLocal, can't decide which one is the localRefCount. | |
report.append(" number of open instances: "); | |
for (int i : instanceRefCounts) { | |
report.append(i).append(", "); | |
} | |
report.append("\n"); | |
} | |
} | |
} | |
} catch (NoSuchFieldException e) { | |
e.printStackTrace(); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
report.append("***************************************************************************\n") | |
.append("********* D U M P I N G R E A L M I N S T A N C E S [ E N D ] **********\n") | |
.append("***************************************************************************\n\n"); | |
System.out.println(report.toString()); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} catch (java.lang.reflect.InvocationTargetException e) { | |
e.printStackTrace(); | |
} catch (NoSuchFieldException e) { | |
e.printStackTrace(); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} catch (NoSuchMethodException e) { | |
e.printStackTrace(); | |
} | |
} | |
// method to dump SyncUser Tokens & Description | |
public static void dumpSyncUser(SyncUser user) { | |
try { | |
StringBuilder report = new StringBuilder("*******************************************************************************\n") | |
.append("********* D U M P I N G R E A L M S Y N C - U S E R [ S T A R T ] **********\n") | |
.append("*******************************************************************************\n\n"); | |
java.lang.reflect.Method getSyncUserMethod = SyncUser.class.getDeclaredMethod("getSyncUser"); | |
getSyncUserMethod.setAccessible(true); | |
io.realm.internal.objectserver.ObjectServerUser syncUser = (io.realm.internal.objectserver.ObjectServerUser) getSyncUserMethod.invoke(user); | |
report.append("\trefreshToken=").append(syncUser.getUserToken().toJson()).append("\n\n"); | |
java.util.Collection<io.realm.internal.objectserver.ObjectServerUser.AccessDescription> realms = syncUser.getRealms(); | |
report.append("\tassociated Realms: \n"); | |
for (io.realm.internal.objectserver.ObjectServerUser.AccessDescription description : realms) { | |
report.append("\t\tdescription: ").append(description.toJson()).append("\n"); | |
} | |
report.append("*******************************************************************************\n") | |
.append("********* D U M P I N G R E A L M S Y N C - U S E R [ E N D ] **************\n") | |
.append("******************************************************************************\n\n"); | |
System.out.println(report.toString()); | |
} catch (java.lang.reflect.InvocationTargetException e) { | |
e.printStackTrace(); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} catch (NoSuchMethodException e) { | |
e.printStackTrace(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment