Skip to content

Instantly share code, notes, and snippets.

@nhachicha
Created July 19, 2017 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nhachicha/af37272b57320ae3421ea3aa518d7032 to your computer and use it in GitHub Desktop.
Save nhachicha/af37272b57320ae3421ea3aa518d7032 to your computer and use it in GitHub Desktop.
Dump Realms configuration and SyncUser Using Reflection
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