Repository navigation
SootUtils
SootUtils provides instance methods over the current global Soot scene. Create it with new SootUtils(); construction does not initialize or own Soot. For managed initialization and graph snapshots, use Analysis sessions and Call graphs and inspection.
Returned SootClass, SootMethod, and SootMethodRef values are live analysis objects. Fresh collection containers do not detach their contents: use them only while the relevant scene is valid and do not reuse them after G.reset() or session closure. Queries read the current scene/graph rather than retaining results across resets.
This complete SootClassSummary.java application takes <apk> <platforms> <class-name> <method-sub-signature>. The class and method must exist in the loaded model. Quote a sub-signature such as 'void onCreate(android.os.Bundle)' as one shell argument.
import com.jordansamhi.androspecter.SootUtils;
import com.jordansamhi.androspecter.analysis.AndroidAnalysis;
import java.nio.file.Path;
import soot.Scene;
/**
* Command-line example using live Soot utilities within a managed analysis lifetime.
* The default constructor performs no analysis; invoke {@link #main(String[])} to run it.
*/
public final class SootClassSummary {
/**
* Prints hierarchy, component, statement-count, and graph information for a loaded method.
* The requested class and declared method must exist in the processed model.
*
* @param args APK path, SDK platforms directory, class name, and full method sub-signature
* @throws IllegalArgumentException if the argument count or input paths are invalid
* @throws RuntimeException if initialization, class/method lookup, or body loading fails
*/
public static void main(String[] args) {
if (args.length != 4) {
throw new IllegalArgumentException(
"Usage: SootClassSummary <apk> <platforms> <class-name> <method-sub-signature>");
}
try (var analysis = AndroidAnalysis.open(Path.of(args[0]), Path.of(args[1]))) {
analysis.context().checkValid();
var utils = new SootUtils();
var clazz = Scene.v().getSootClass(args[2]);
var method = clazz.getMethod(args[3]);
System.out.println("Superclasses: "
+ utils.getClassNames(utils.getAllSuperClasses(clazz)));
System.out.println("Component kind: " + utils.getComponentType(clazz));
System.out.println("Processed Jimple units: " + utils.getNumberOfStmt(method));
System.out.println("In graph: " + utils.isInCallGraph(method, Scene.v().getCallGraph()));
}
}
}| Method | Scope and behavior |
|---|---|
getMethodRef(className, methodSubSignature) |
Looks up a declared method using its full sub-signature, including return and parameter types; logs resolution failure and returns null |
getAllSuperClasses(clazz) |
Returns the immediate superclass and its ancestors |
getAllInterfaces(clazz) |
Returns directly implemented interfaces and their superinterfaces; does not traverse the class's superclass chain |
getClassNames(classes) |
Copies class names into a set of strings |
getClasses() / getAllClasses()
|
Current scene classes except the exact dummy-main class; includes framework and library classes |
getAllMethods() |
All methods of those scene classes |
getMethodsFromPackage(prefix) |
Concrete methods of concrete classes whose class name starts with the supplied string; this is not a package-boundary match |
getNonLibraryClasses() / getAllMethodsExceptLibraries()
|
Excludes dummy main and classes classified by the current LibrariesManager policy |
getComponentType(clazz) |
Infers Activity, Service, BroadcastReceiver, or ContentProvider from the superclass chain; otherwise NON_COMPONENT
|
isDummyMainClass(clazz) |
Tests the exact dummy-main class name used by the library |
Component classification is a hierarchy check, not a check of manifest registration. Library classification is separate from Soot's application-class flag. For an explicit package-boundary or library predicate, use Inspection and LibraryFilter.
getNumberOfStmt(method) retrieves the active body of a concrete method and counts its Jimple units; nonconcrete methods contribute zero. getNumberOfStmt(methods) sums that measure for the supplied collection. Body loading can fail and can be expensive.
Despite their historical names:
-
getNumberOfStmtInApp()sums over the current scene, excluding dummy main. It can include loaded framework/library code. -
getNumberOfStmtInAppWithoutLibraries()excludes the legacy known-library policy as well as dummy main. It does not mean “only classes marked application by Soot.”
These are processed-model counts, potentially including generated helpers, identity statements, and returns. They are not original DEX instruction counts. Select an explicit class/method scope before counting when comparing APKs.
| Method | Behavior |
|---|---|
countEdgesInCallGraph(graph) |
Total graph edge count |
countEdgesWithNonLibraryTargets(graph) |
Edges whose target belongs to a current scene class outside dummy main and the known-library policy |
getMethodsInCallGraph(graph) |
Source/target methods incident to edges, excluding dummy-main methods |
getCountOfNodes(graph) |
Size of the preceding incident-method set |
getMethodsInCallGraphExceptLibraries(graph) |
Further restricts incident methods to current non-library classes |
isInCallGraph(method, graph) |
Tests incident membership, excluding dummy main |
isCalledInCallGraph(method, graph) |
Tests whether a current edge targets the method, excluding dummy main |
getCallGraphAdjacencyList(graph) |
New mutable map of source methods to target lists; one target entry per edge, including repeated targets; contents remain live Soot methods |
For repeated queries, prefer the indexed immutable CallGraphSnapshot. Its node set intentionally includes generated dummy-main nodes, so its count can differ from getCountOfNodes. Neither representation includes declared methods with no graph edge.
setupSoot(platformsPath, apkPath, wholeAnalysis) resets Soot, selects APK input, configures whole-program mode, allows phantom references, and loads necessary classes with output disabled. setupSootWithOutput(platformsPath, apkPath, outputPath, wholeAnalysis) additionally configures DEX output and overwrite behavior.
These methods configure and load Soot; they do not construct FlowDroid's Android lifecycle entry points, run the complete analysis packs, write/sign an APK, or produce a completed Android call graph by themselves. Use FlowdroidUtils or the managed session for Android-aware construction. Never call these reset-performing initializers inside an active managed session.
Source: SootUtils.java.
- Analysis sessions
- APK metadata
- Call graphs and inspection
- Graph export and comparison
- Taint analysis
- Instrumentation
- Cancellation and logging
- Migration and troubleshooting
- Publishing releases