Skip to content

TimeOut

Jordan Samhi edited this page Oct 25, 2026 · 3 revisions

TimeOut

com.jordansamhi.androspecter.TimeOut is the legacy seconds-based timer adapter. In the 2.0.0 API, it never terminates the JVM. Prefer Deadline and CancellationSource for new code; see Cancellation and logging.

Construction and lifecycle

API Behavior
new TimeOut(seconds) Deprecated. On expiration, signals its token and logs a warning; callers must observe the token
new TimeOut(seconds, action) On expiration, signals its token, then runs action on a daemon timer thread
launch() Starts the countdown once; construction alone does not start a timer
cancellationToken() Token signalled by expiration; pass it to a cooperative operation
cancel() / close() Disarms the timer without signalling its token; prevents later launch
getTimeout() Returns the effective duration in seconds

Zero means the legacy default of 60 seconds. Negative values are rejected. Each instance is one-shot: a second launch fails, including after expiration or cancellation. cancel() is safe to repeat and can be called before launch. It cannot undo expiration or stop a callback that has already begun.

This differs from CancellationSource.close(), which requests operation cancellation, and from Deadline.after(Duration.ZERO, action), which schedules immediately.

Use the token

This complete utility class applies the timer to opening an APK analysis. Its callback only reports expiration; the token carries the cancellation request.

import com.jordansamhi.androspecter.TimeOut;
import com.jordansamhi.androspecter.analysis.AndroidAnalysis;
import java.nio.file.Path;
import java.util.concurrent.CancellationException;

public final class LegacyTimeoutExample {
    /**
     * Reads the manifest package with a cooperative 30-second timeout request.
     * @param apk readable APK file
     * @param platforms Android SDK platforms directory
     */
    public static void readPackage(Path apk, Path platforms) {
        try (TimeOut timeout = new TimeOut(30,
                () -> System.err.println("Timeout: cancellation requested"))) {
            timeout.launch();
            try (AndroidAnalysis analysis = AndroidAnalysis.builder(apk, platforms)
                    .cancellationToken(timeout.cancellationToken())
                    .open()) {
                System.out.println(analysis.packageName());
            }
        } catch (CancellationException ex) {
            System.err.println("Analysis observed cancellation");
        }
    }
}

Cancellation is cooperative. A callback or call-graph phase can continue beyond 30 seconds before observing the request. The timer callback must not close the analysis or access live Soot state from its daemon thread. The example retains the session until the operation returns and closes it on the owning thread.

To actively cancel from a controlling thread independently of expiration, use a caller-owned CancellationSource. Calling TimeOut.cancel() only disarms the timer; it does not request cancellation of the operation.

Clone this wiki locally