如何销毁 Android 上的 golang 子进程?
How to destroy a golang sub process on Android?
最近,我正在尝试使用 Runtime.getRuntime().exec(command)
的 Android 子进程,发现我可以破坏 NodeJS http 服务器但不能破坏 Go http 服务器。
对于 node
和 go
二进制文件,可以从 Termux 获得;
- 节点 http 服务器:https://github.com/stallpool/halfbase/tree/master/nodejs/tinyserver/index.js
- 转到 http 服务器:https://github.com/stallpool/halfbase/blob/master/golang/tinyserver/main.go
对于节点子进程,可以在AndroidService
和p.waitFor()
中启动;到时候可以被p.destroy()
杀死
但是,对于go子进程,它可以启动但不能被p.destroy()
甚至p. destroyForcibly()
杀死;在这篇文章 https://medium.com/honestbee-tw-engineer/gracefully-shutdown-in-go-http-server-5f5e6b83da5a 中,它确保可以正常关闭 go 服务器,我试过了,但 p.destroy()
仍然不起作用。
如果有人能告诉我一个终止进程的方法,我将不胜感激。谢谢!
刚刚想出了一个破解方法;不优雅;指导我找到更好的解决方案!
Log.d("AppDebug", p.javaClass.getName())
// from above log
// we can know Android use "java.lang.UNIXProcess" as implementation of java.lang.Process
// to make sure the sub process is killed eventually
if (p.isAlive()) {
val klass = p.javaClass
if (klass.getName().equals("java.lang.UNIXProcess")) {
Log.d("AppDebug", "force terminate sub process ..")
try {
val f = klass.getDeclaredField("pid");
f.setAccessible(true);
val pid = f.getInt(p);
// XXX: buggy here, if getInt throw an error, the filed is exposed!
f.setAccessible(false);
android.os.Process.killProcess(pid);
Log.d("AppDebug", "force terminating done.")
} catch (e: Exception) {
Log.d("AppDebug", "force terminating failed.")
}
} else {
Log.d("AppDebug", "force terminating not supported.")
}
}
对不起我的误导。目前我完全理解为什么我添加了一些关于 ps -ef
before/after 终止进程的日志后无法终止我的 go 服务器。
实际上我使用go run main.go
来启动服务器;但是,go run main.go
将编译代码并在 tmp 文件夹中生成一个二进制文件;然后它将产生一个子进程(执行二进制文件);当我执行 p.destroy()
时,它只是终止了 go
进程,但子服务器进程仍然存在。
正确的解决方案是,像上面的代码一样得到pid
;并使用 ps -o pid= --ppid=<pid>
获取子树并终止所有进程进行清理。
最近,我正在尝试使用 Runtime.getRuntime().exec(command)
的 Android 子进程,发现我可以破坏 NodeJS http 服务器但不能破坏 Go http 服务器。
对于 node
和 go
二进制文件,可以从 Termux 获得;
- 节点 http 服务器:https://github.com/stallpool/halfbase/tree/master/nodejs/tinyserver/index.js
- 转到 http 服务器:https://github.com/stallpool/halfbase/blob/master/golang/tinyserver/main.go
对于节点子进程,可以在AndroidService
和p.waitFor()
中启动;到时候可以被p.destroy()
但是,对于go子进程,它可以启动但不能被p.destroy()
甚至p. destroyForcibly()
杀死;在这篇文章 https://medium.com/honestbee-tw-engineer/gracefully-shutdown-in-go-http-server-5f5e6b83da5a 中,它确保可以正常关闭 go 服务器,我试过了,但 p.destroy()
仍然不起作用。
如果有人能告诉我一个终止进程的方法,我将不胜感激。谢谢!
刚刚想出了一个破解方法;不优雅;指导我找到更好的解决方案!
Log.d("AppDebug", p.javaClass.getName())
// from above log
// we can know Android use "java.lang.UNIXProcess" as implementation of java.lang.Process
// to make sure the sub process is killed eventually
if (p.isAlive()) {
val klass = p.javaClass
if (klass.getName().equals("java.lang.UNIXProcess")) {
Log.d("AppDebug", "force terminate sub process ..")
try {
val f = klass.getDeclaredField("pid");
f.setAccessible(true);
val pid = f.getInt(p);
// XXX: buggy here, if getInt throw an error, the filed is exposed!
f.setAccessible(false);
android.os.Process.killProcess(pid);
Log.d("AppDebug", "force terminating done.")
} catch (e: Exception) {
Log.d("AppDebug", "force terminating failed.")
}
} else {
Log.d("AppDebug", "force terminating not supported.")
}
}
对不起我的误导。目前我完全理解为什么我添加了一些关于 ps -ef
before/after 终止进程的日志后无法终止我的 go 服务器。
实际上我使用go run main.go
来启动服务器;但是,go run main.go
将编译代码并在 tmp 文件夹中生成一个二进制文件;然后它将产生一个子进程(执行二进制文件);当我执行 p.destroy()
时,它只是终止了 go
进程,但子服务器进程仍然存在。
正确的解决方案是,像上面的代码一样得到pid
;并使用 ps -o pid= --ppid=<pid>
获取子树并终止所有进程进行清理。