Skip to content

AndroidAppInspector

Jordan Samhi edited this page Oct 23, 2026 · 2 revisions

AndroidAppInspector

AndroidAppInspector is the deprecated visitor adapter over the current Soot scene. New code should use Inspection, which registers only needed callbacks and composes class, method, and library predicates.

The adapter remains an abstract class for subclassing, but its callbacks have default no-op implementations. Override only the callbacks needed. The current signatures are:

public void examineClass(SootClass clazz)
public void examineMethod(SootClass clazz, SootMethod method)
public void examineStatement(SootClass clazz, SootMethod method, Unit unit)

These are API signatures, not a complete class; their types are soot.SootClass, soot.SootMethod, and soot.Unit. There are no shouldExamineClass, shouldExamineMethod, or shouldExamineStatement hooks in the current adapter. Use the new inspection builder for traversal filtering.

Complete legacy example

Save as LegacyInspectorExample.java. Arguments are <apk> <platforms>. The managed session initializes Soot; the adapter borrows its context and cancellation policy.

import com.jordansamhi.androspecter.AndroidAppInspector;
import com.jordansamhi.androspecter.analysis.AndroidAnalysis;
import java.nio.file.Path;
import soot.SootClass;
import soot.SootMethod;

/**
 * Command-line example adapting the legacy inspector to a managed analysis context.
 * The default constructor performs no analysis; invoke {@link #main(String[])} to run it.
 */
public final class LegacyInspectorExample {
    private static final class MethodNames extends AndroidAppInspector {
        /**
         * Prints the method signature only when its declaring class is marked as an application class.
         * Both arguments are borrowed from the current Soot scene and are not retained.
         *
         * @param clazz declaring class supplied by the inspector
         * @param method method being visited, including abstract or native methods
         */
        @Override
        public void examineMethod(SootClass clazz, SootMethod method) {
            if (clazz.isApplicationClass()) {
                System.out.println(method.getSignature());
            }
        }
    }

    /**
     * Opens the APK and visits method signatures without requesting statement-body traversal.
     * The inspector uses the session's existing context and the session closes on this thread.
     *
     * @param args APK path followed by the Android SDK platforms directory
     * @throws IllegalArgumentException if the argument count or input paths are invalid
     * @throws RuntimeException if backend initialization or inspection fails
     */
    public static void main(String[] args) {
        if (args.length != 2) {
            throw new IllegalArgumentException("Usage: LegacyInspectorExample <apk> <platforms>");
        }
        try (var analysis = AndroidAnalysis.open(Path.of(args[0]), Path.of(args[1]))) {
            var inspector = new MethodNames();
            inspector.setExaminationCriteria(false, true, false);
            inspector.runIn(analysis.context());
        }
    }
}

The application-class condition selects what the callback prints; it does not prune the adapter's traversal. Abstract and native methods can reach a method callback.

Callback levels and body loading

All three callback levels are enabled initially. setExaminationCriteria(classes, methods, statements) replaces the enabled levels for subsequent runs. The levels are independent: disabling class callbacks does not suppress method or statement traversal.

Disable statement callbacks when they are not needed. Enabling them loads bodies of concrete methods even if examineStatement is left as a no-op. Method callbacks alone do not load bodies. Disabling every level makes a run only validate its context.

Class callbacks precede method callbacks, which precede statement callbacks for each concrete method. Statement callbacks receive Jimple units, including identities and returns.

Running and lifetime

runIn(context) uses an existing valid AnalysisContext without closing it. run() instead captures a temporary context for the current Soot state and closes that view afterward; it does not initialize Soot or reset the scene. Use runIn(analysis.context()) to retain a managed session's cancellation policy.

Callbacks receive borrowed mutable Soot objects. Use them on the owning thread and only while the scene remains valid. Callback and body-loading failures propagate. Collection snapshots tolerate structural edits, but new objects may not be visited and removed objects may still be visited. The adapter does not invalidate cached analysis graphs after mutations; use an explicit transformation through analysis.apply(...) for such work.

Source: AndroidAppInspector.java.

Clone this wiki locally