I'm trying to SSH from my Android app using Java. I get the following exception while trying to make a connection..
FATAL EXCEPTION: main
Process: com.example.atest, PID: 14392
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/management/ReflectionException;
at org.apache.sshd.common.util.GenericUtils.peelException(GenericUtils.java:728)
at org.apache.sshd.common.future.AbstractSshFuture.verifyResult(AbstractSshFuture.java:121)
at org.apache.sshd.client.future.DefaultConnectFuture.verify(DefaultConnectFuture.java:42)
at org.apache.sshd.client.future.DefaultConnectFuture.verify(DefaultConnectFuture.java:34)
at com.example.atest.MainActivity.sshConnect(MainActivity.java:372)
at com.example.atest.MainActivity.onResults(MainActivity.java:335)
at android.speech.SpeechRecognizer$InternalRecognitionListener$1.handleMessage(SpeechRecognizer.java:1062)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Caused by: java.lang.ClassNotFoundException: Didn't find class "javax.management.ReflectionException" on path: DexPathList[[dex file "/data/data/com.example.atest/code_cache/.overlay/base.apk/classes4.dex", dex file "/data/data/com.example.atest/code_cache/.overlay/base.apk/classes5.dex", zip file "/data/app/~~iTqpPkZDjYiDFfzmOJt2nQ==/com.example.atest-uHpPjOVd-8RZr-nUHh2kaw==/base.apk"],nativeLibraryDirectories=[/data/app/~~iTqpPkZDjYiDFfzmOJt2nQ==/com.example.atest-uHpPjOVd-8RZr-nUHh2kaw==/lib/arm64, /data/app/~~iTqpPkZDjYiDFfzmOJt2nQ==/com.example.atest-uHpPjOVd-8RZr-nUHh2kaw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at org.apache.sshd.common.util.GenericUtils.peelException(GenericUtils.java:728)
at org.apache.sshd.common.future.AbstractSshFuture.verifyResult(AbstractSshFuture.java:121)
at org.apache.sshd.client.future.DefaultConnectFuture.verify(DefaultConnectFuture.java:42)
at org.apache.sshd.client.future.DefaultConnectFuture.verify(DefaultConnectFuture.java:34)
at com.example.atest.MainActivity.sshConnect(MainActivity.java:372)
at com.example.atest.MainActivity.onResults(MainActivity.java:335)
at android.speech.SpeechRecognizer$InternalRecognitionListener$1.handleMessage(SpeechRecognizer.java:1062)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
This is my app/build.gradle..
dependencies {
implementation "org.apache.mina:mina-core:3.0.0-M2"
implementation "org.apache.sshd:sshd-core:2.1.0"
implementation "org.apache.sshd:sshd-putty:2.1.0"
implementation "org.apache.sshd:sshd-common:2.1.0"
implementation "org.slf4j:slf4j-api:1.7.5"
implementation "org.slf4j:slf4j-simple:1.6.4"
..and this is my ssh method..
public void sshConnect(String username, String password, String host, int port, long defaultTimeoutSeconds, String command) {
// create a client instance
try (SshClient client = SshClient.setUpDefaultClient()) {
client.start();
Log.d(TAG, "sshConnect(): client.start(): client started");
// connection and authentication
try (ClientSession session = client.connect(username, host, port).verify(TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds)).getSession()) {
Log.d(TAG, "ssh: client.connect()");
session.addPasswordIdentity(password);
session.auth().verify(TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds));
Log.d(TAG, "ssh: connection established");
// create a channel to communicate
channel = session.createChannel(Channel.CHANNEL_SHELL);
Log.d(TAG, "ssh: starting shell");
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
channel.setOut(responseStream);
// open channel
channel.open().verify(5, TimeUnit.SECONDS);
// open channel
channel.open().verify(5, TimeUnit.SECONDS);
try (OutputStream pipedIn = channel.getInvertedIn()) {
pipedIn.write(command.getBytes());
pipedIn.flush();
}
// close channel
channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED),
TimeUnit.SECONDS.toMillis(5));
// output after converting to string type
String responseString = responseStream.toString();
Log.d(TAG, "ssh: responseString == " + responseString);
} catch (Exception e) {
Log.d(TAG, "sshConnect(): client.connect(): Exception: " + e.toString());
e.printStackTrace();
}
} catch (Exception e) {
Log.d(TAG, "sshConnect(): client.start(): Exception: " + e.toString());
e.printStackTrace();
}
}
It feels like I may be missing an "implementation" from my gradle but my references only had what I took.
Android does not have the javax.management.*
packages and classes so that's why you get the ClassNotFoundException
. A possible fix is here. By adding following to your app level gradle:
implementation 'javax.management:jmx:1.2.1'
and this to your settings.gradle
under google()
maven {
url 'https://www.datanucleus.org/downloads/maven2/'
}
you get the necessary classes to allow you to build.