How to Capture and Gracefully Stop Android Logcat in UiAutomator

This guide explains how to use Java's Runtime API within a UiAutomator test to start, filter, and safely terminate an adb logcat process, including a complete Logcat thread implementation and tips for preventing oversized log files.

FunTester
FunTester
FunTester
How to Capture and Gracefully Stop Android Logcat in UiAutomator

When using UiAutomator to automate Android testing, developers often need to collect device logs automatically. Directly invoking adb logcat via Runtime.exec works, but stopping the spawned process is tricky; common suggestions like killing the PID are cumbersome, and calling Thread.destroy() throws NoSuchMethodError because the method destroys the Java thread, not the underlying OS process.

Solution Overview

The author introduces a custom Logcat class that extends Thread. It starts a logcat process, optionally filters output, writes matching lines to a file, and provides a flag‑based mechanism to stop the process cleanly by calling Process.destroy().

Key Implementation Details

package monkeytest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import source.Common;

public class Logcat extends Thread {
    private static boolean LogKey = false;

    @Override
    public void run() {
        execCmdAdb("adb logcat -c");
        execCmdAdb("adb logcat", "logcat" + getNow() + ".log", "happyjuzi", true);
    }

    /** Execute adb command with optional filtering */
    private void execCmdAdb(String cmd, String fileName, String filter, boolean key) {
        System.out.println(cmd);
        String OSname = System.getProperty("os.name");
        try {
            Process p = null;
            if (OSname.contains("Mac")) {
                p = Runtime.getRuntime().exec(Common.ADB_PATH + cmd);
            } else {
                p = Runtime.getRuntime().exec("cmd /c " + cmd);
            }
            // Standard output handling
            InputStream input = p.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String line;
            while ((line = reader.readLine()) != null) {
                if (LogKey) {
                    p.destroy();
                    reader.close();
                    input.close();
                    return;
                }
                if (key) {
                    if (line.contains(filter)) {
                        Common.getInstance().saveToFile(line, fileName, false);
                    }
                } else {
                    if (!line.contains(filter)) {
                        Common.getInstance().saveToFile(line, fileName, false);
                    }
                }
            }
            reader.close();
            input.close();
            // Error output handling
            InputStream errorInput = p.getErrorStream();
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));
            String eline;
            while ((eline = errorReader.readLine()) != null) {
                if (LogKey) {
                    p.destroy();
                    errorReader.close();
                    errorInput.close();
                    return;
                }
                if (key) {
                    if (eline.contains(filter)) {
                        Common.getInstance().saveToFile(line, fileName, false);
                    }
                } else {
                    if (!eline.contains(filter)) {
                        Common.getInstance().saveToFile(line, fileName, false);
                    }
                }
            }
            errorReader.close();
            errorInput.close();
        } catch (IOException e) {
            Common.getInstance().output("执行" + cmd + "失败!");
            e.printStackTrace();
        }
    }

    /** Overload for commands without filtering */
    private void execCmdAdb(String cmd) {
        System.out.println(cmd);
        String OSname = System.getProperty("os.name");
        try {
            if (OSname.contains("Mac")) {
                Runtime.getRuntime().exec(Common.ADB_PATH + cmd);
            } else {
                Runtime.getRuntime().exec("cmd /c " + cmd);
            }
        } catch (IOException e) {
            Common.getInstance().output("执行" + cmd + "失败!");
            e.printStackTrace();
        }
    }

    /** Stop the logcat thread */
    public void stopLoacat() {
        Logcat.LogKey = true;
    }

    /** Get current timestamp for file naming */
    private String getNow() {
        Date time = new Date();
        SimpleDateFormat now = new SimpleDateFormat("MMdd-HHmm");
        return now.format(time);
    }
}

Usage Tips

Call new Logcat().start() from your test script to begin logging. When you need to stop, invoke stopLoacat(), which sets the static flag LogKey to true; the next read loop iteration will destroy the process and close streams.

Be careful not to let the thread run indefinitely, as log files can grow large and consume resources. You can embed the Logcat thread inside a larger test loop or manage its lifecycle externally, as demonstrated by the author.

The provided implementation works on both macOS and Windows environments by checking System.getProperty("os.name") and adjusting the command invocation accordingly.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAndroidmobile testingThreadprocesslogcatUIAutomator
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.