0

Using ADB in a java application to monitor android device status every three seconds. Height adb commands are used :

adb shell settings get global airplane_mode_on
adb shell settings get system system_locales
adb shell dumpsys telephony.registry
adb shell "dumpsys content | grep ^Account | grep @ | grep com.google"
adb shell getprop gsm.network.type adb shell getprop gsm.operator.alpha
adb shell settings get system screen_off_timeout
adb shell settings get global wifi_on

Except for the dumpsys commands, the replies are one line values and take 200 msec each for readline() execution to complete.

"dumpsys telephony.registry" returns about 5000 lines and takes 500 msec.

"dumpsys content | grep ^Account .." returns three or four lines and takes 300 msec.

I have no problem with the delays, but server CPU is severely impacted during that time. Sending those height commands increased CPU by 30%. The application is required to monitor up to height different devices simultaneously and it causes 100% CPU peaks with as little as two devices connected.

The java application is not the issue because I do reproduce the CPU impact while sending the ADB commands from DOS prompt.

Things I tried with no benefit observed :

  • Send commands separately
  • Send one multiple commands line : adb shell command1 && adb shell command2 && adb shell command3 .."
  • Put delays between commands (10, 100, 200, 500 msec)
  • Use ADB connection over Wifi instead of USB
  • Compared different Android device models and vendors (Samsung, Google, ..)
  • Installed latest Android SDK platform-tools :
>adb version
Android Debug Bridge version 1.0.41
Version 35.0.2-12147458
Installed as C:\Windows\SysWOW64\platform-tools\adb.exe
Running on Windows 10.0.19045

Edit : Comment from Robert and answer from Martin Zeitler suggest to include all commands in one single ADB session. I tried it like this :

tResult = adb_shell_method("command1 && echo WWW && command2 && echo WWW && ..");
resultArray = tResult.split("WWW");

Collecting the height commands like this takes ~320 msec and hits CPU by less than 5%.

Now I understand that each "adb shell" execution is more complex than I thought. Therefore, it would be best to create one adb session with the device for and use it as long as it is connected. Collecting data from the UE with a method like

String executeADBCommand(String command, <adb session class> ADBSession);
2
  • 1
    The best way would be merging all commands into one shell script on Android side. That way you would have one command to execute and the script could add separators into output for easier parsing. On PC side I would try to directly talk to adb server instance via TCP instead if using adb command. I assume Android Studio should contain a library that can directly connect to adb. Alternatively for testing I remember a pure python version that is capable of sending adb commands without executing adb. And for stability I would periodically kill and restart adb server. Commented Jan 1 at 21:46
  • I agree, Robert. That makes a practical workaround 1) tResult = adb shell "command1 && echo WWW && commande2 && echo WWW .. "; 2) resultArray = tResult.split("WWW"); Collecting the height commands like this takes ~320 msec and hits CPU by 5% Commented Jan 3 at 0:23

2 Answers 2

2

That's not monitoring, but a stress test.

Instead of opening 7 terminals every 3 seconds, why not open one terminal and close it again?

adb shell "settings get global airplane_mode_on && settings get system system_locales && ... && exit"

One can as well use SSH2 for that; just try connecting with PuTTY ...

Or write a simple foreground-service agent app, which sends the desired values.

Sign up to request clarification or add additional context in comments.

2 Comments

I didn't realize every "adb shell" interaction would be so complex. That explains the CPU impact. Best would be to open one session that I could use as long as the UE is connected with a method like String executedADBCommand(String command, .. AdbSession)
Don't hammer SSHd, but a local HTTPd ...then you can monitor thousands of devices. Pulling data with adb shell is generally a bad idea, when one can push it via HTTP.
0

Cause for CPU is creating new ADB session with client device upon every interaction.

Solution is to create one ADB session for each device connected and and use those to send commands.

Create a new ADB session :

        ProcessBuilder pb = new ProcessBuilder("adb", "-s", serialNumber, "shell");
        pb.redirectErrorStream(true);
        Process process = pb.start();
        
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        BufferedReader processReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        
        adbSessions.put(serialNumber, process);
        sessionWriters.put(serialNumber, writer);
        sessionReaders.put(serialNumber, processReader);

Execute commands :

        BufferedWriter writer = sessionWriters.get(serialNumber);
        BufferedReader reader = sessionReaders.get(serialNumber);
        
        writer.write(command + "\n");
        writer.flush();
        
        Thread.sleep(100);
        
        StringBuilder response = new StringBuilder();
        while (reader.ready()) {
            response.append(reader.readLine()).append("\n");
        }
        
        return response.toString().trim();

Plus a method to check if a session exists for a given device Serial number and an other one to terminate it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.