记录下 Java 8 policy tool 升级导致编译安卓时 Jack server 出错,主要是其中的java启动参数 -Djavax.net.debug=ssl 调试方法,以后遇到类似问题好快速的解决。

另外仅Android6~Android8.1使用jack编译,8.1之后已废弃该工具,详情可看下 https://source.android.google...

背景

大家的电脑升级后,编译安卓8.1的源码出错,communication error with Jack server, SSL_ERROR_SYSCALLcommunication error with Jack server (35), try 'jack-diagnose' or see Jack server log

curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8077

然后就解决吧,结果按照网上之前出现问题的方案解决都不行,这个也浪费了大家好几天的时间。

我之前是按照笨方法对比替换解决的,之后网上查资料才找到调试方法(原网页已不记得是哪个了,见谅),如果按该方法调试,应该可以很快就可以解决问题。

调试方法

jack server的日志存放在 ~/.jack-server/logs , 然而日志里没有错误日志。

通过分析 prebuilts/sdk/tools/jack-admin , 发现可以用 curl -v https://127.0.0.1:8076 命令去测试,这样方便快速调试。

然而呢就是https连接,第二阶段握不上手,# 连接jack端口握手失败

$ curl -v https://127.0.0.1:8076
* Trying 127.0.0.1:8076...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8076 (#0)
...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8076
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8076

正常情况下,第一阶段 Client hello 后会有第二阶段 Server hello, 但就是没出现这样的语句TLS handshake, Server hello (2):

使用不同的tls版本也同样的结果# 使用不同tls版本连接

for args in "tlsv1.3" "tlsv1.2" "tlsv1" ;do curl -v --$args https://127.0.0.1:8076;echo ----; done

反正折腾了一大圈,到解决该问题后,其实正确的调试方式应该是,

分析jack-admin里start-server和日志,

自己手动启动,其中关键的是添加 -Djavax.net.debug=ssl 调试参数,当然ssl也可改为all,这样日志会全一些。# 手动启动jack-server并加调试参数

$ prebuilts/sdk/tools/jack-admin kill-server # 注意需要把之前已经起来的jack server杀了
# 添加 -Djavax.net.debug=ssl
$ cd ~/.jack-server
$ java -XX:MaxJavaStackTraceDepth=-1 -Djavax.net.debug=ssl -Djava.io.tmpdir=/tmp -Dfile.encoding=UTF-8 -cp ~/.jack-server/launcher.jar com.android.jack.launcher.ServerLauncher
这个时候再用命令行 curl...去连接在终端就会出现错误日志 protocol is disabled or cipher suites are inappropriate"throwable" : {
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.HandshakeContext.(HandshakeContext.java:171)
at sun.security.ssl.ServerHandshakeContext.(ServerHandshakeContext.java:62)
at sun.security.ssl.TransportContext.kickstart(TransportContext.java:220)

顺着这个错误日志去网上搜索其实就可以很快解决问题了。

修复方法

修复方法倒想着有几个,可选择自己喜欢的方案,有别的方案也欢迎评论。使能 TLSv1

将禁用的TLSv1启用,最好也启用SSLv3, 反正源码里写的是SSLv3。

(关于TLS, SSL区别这些可网上查查,这里不列出)# 使用TLSv1

/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security
--- java.security 2021-04-30 13:44:46.922768831 +0800
+++ java.security.NG 2021-04-30 13:31:38.754028864 +0800
@@ -716,7 +716,7 @@
#
# Example:
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, TLSv1.1, RC4, DES, MD5withRSA, \
+jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \使用安卓源码自带JDK

可通过设置JAVA_HOME等方式,使用自带的JDK prebuilts/jdk/jdk8/ 。

事实上,安卓后续的版本都用的自带的JDK。修改源码

jack源码在 https://android.googlesource.... , 需要想办法访问。

最新分支应该为 ub-jack , 17年就不再维护了。# 下载jack源码

$ git clone https://android.googlesource.com/toolchain/jack -b ub-jack --depth 1
修改的源码示例:---
.../android/jack/server/JackHttpServer.java | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/server/jack-server/src/com/android/jack/server/JackHttpServer.java b/server/jack-server/src/com/android/jack/server/JackHttpServer.java
index 4e5e75c3..7aa602ee 100644
--- a/server/jack-server/src/com/android/jack/server/JackHttpServer.java
+++ b/server/jack-server/src/com/android/jack/server/JackHttpServer.java
@@ -1391,6 +1391,7 @@ public class JackHttpServer implements HasVersion {
FileInputStream keystoreServerIn = null;
FileInputStream keystoreClientIn = null;
SSLContext sslContext = null;
+ String[] httpsProtocols = {"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"};
try {
File keystoreServerFile = new File(serverDir, KEYSTORE_SERVER);
@@ -1416,12 +1417,29 @@ public class JackHttpServer implements HasVersion {
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tm.init(keystoreClient);
- sslContext = SSLContext.getInstance("SSLv3");
+ logger.log(Level.INFO, "Java version " + System.getProperty("java.version"));
+ logger.log(Level.INFO, "Supported protocols " + Arrays.toString(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()));
+ for (String protocol : httpsProtocols) {
+ try {
+ sslContext = SSLContext.getInstance(protocol);
+ } catch (NoSuchAlgorithmException e) {
+ continue;
+ }
+ logger.log(Level.INFO, "Found protocols " + protocol);
+ break;
+ }
+
+ if (sslContext == null) {
+ throw new NoSuchAlgorithmException();
+ }
+
sslContext.init(keyManagerFactory.getKeyManagers(), tm.getTrustManagers(), null);
} catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException
| UnrecoverableKeyException | KeyManagementException | CannotCreateFileException
| CannotChangePermissionException e) {
throw new ServerException("Failed to setup ssl context", e);
+ } catch (Exception e) {
+ logger.log(Level.INFO, "Ssl error " + e);
} finally {
if (keystoreClientIn != null) {
try {
--

2.31.1

之后把 prebuilts/sdk/tools/Android.mk 里jack相关的去掉后,编译jack-server源码,

替换 prebuilts/sdk/tools/jack-server-4.11.ALPHA.jar ~/.jack-server/server-*.jar

随后 jack-admin kill-server,再编译安卓即可正常。