android 18 footjob,Android 8/9 default trust manager: OOM when getting “https://icloud.com”[通俗易懂]

android 18 footjob,Android 8/9 default trust manager: OOM when getting "https://icloud.com"[通俗易懂]Whenusingokhttp(whichusestheplatformdefaultcustommanager,whichseemstobeprovidedbyConscrypt)toGET(orPROPFIND)https://icloud.com(withoutwww)withcodelikethat://compileSdkVersi...

When using okhttp (which uses the platform default custom manager, which seems to be provided by Conscrypt) to GET (or PROPFIND) https://icloud.com (without www) with code like that:

// compileSdkVersion 27

// buildToolsVersion '28.0.1'

// targetSdkVersion 27

// Kotlin 1.2.51

class ClientTest {

@Test

fun testIcloud() {

val client = OkHttpClient()

client.newCall(Request.Builder()

.get()

.url("https://icloud.com")

.build())

.execute()

}

}

it takes a long time until the process is killed with OOM and the test fails:

Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V (light greylist, reflection)

Background concurrent copying GC freed 12119(2MB) AllocSpace objects, 2(40KB) LOS objects, 53% free, 1347KB/2MB, paused 5.288ms total 13.790ms

Background concurrent copying GC freed 255556(7MB) AllocSpace objects, 0(0B) LOS objects, 3% free, 153MB/159MB, paused 160us total 1.134s

Waiting for a blocking GC Alloc

Background concurrent copying GC freed 1659257(48MB) AllocSpace objects, 0(0B) LOS objects, 4% free, 143MB/149MB, paused 166us total 751.739ms

WaitForGcToComplete blocked Alloc on ProfileSaver for 84.800ms

Starting a blocking GC Alloc

Waiting for a blocking GC Alloc

NativeAlloc concurrent copying GC freed 613455(17MB) AllocSpace objects, 0(0B) LOS objects, 3% free, 171MB/177MB, paused 715us total 800.326ms

WaitForGcToComplete blocked Alloc on HeapTrim for 78.698ms

Starting a blocking GC Alloc

Starting a blocking GC Alloc

Starting a blocking GC Alloc

Alloc concurrent copying GC freed 1471248(40MB) AllocSpace objects, 11(26MB) LOS objects, 4% free, 120MB/126MB, paused 617us total 440.035ms

Waiting for a blocking GC Alloc

Background concurrent copying GC freed 212754(4MB) AllocSpace objects, 1(4MB) LOS objects, 3% free, 179MB/185MB, paused 1.906ms total 414.292ms

WaitForGcToComplete blocked Alloc on HeapTrim for 378.426ms

Starting a blocking GC Alloc

Waiting for a blocking GC Alloc

Background concurrent copying GC freed 116(286KB) AllocSpace objects, 14(45MB) LOS objects, 3% free, 146MB/152MB, paused 759us total 705.920ms

WaitForGcToComplete blocked Alloc on HeapTrim for 631.676ms

Starting a blocking GC Alloc

Waiting for a blocking GC Alloc

Starting a blocking GC Alloc

Throwing OutOfMemoryError "Failed to allocate a 32 byte allocation with 16 free bytes and 16B until OOM, max allowed footprint 201326592, growth limit 201326592" (recursive case)

"Instr: android.support.test.runner.AndroidJUnitRunner" prio=5 tid=13 Runnable

| group="main" sCount=0 dsCount=0 flags=2 obj=0x12c40a80 self=0x7377c9337400

| sysTid=9630 nice=-8 cgrp=default sched=0/0 handle=0x7377b11934f0

| state=R schedstat=( 17608058590 1326008400 7326 ) utm=1681 stm=79 core=1 HZ=100

| stack=0x7377b1090000-0x7377b1092000 stackSize=1041KB

| held mutexes= "mutator lock"(shared held)

at libcore.util.NativeAllocationRegistry.registerNativeAllocation(NativeAllocationRegistry.java:129)

at java.math.BigInt.makeValid(BigInt.java:48)

at java.math.BigInt.putBigEndianTwosComplement(BigInt.java:179)

at java.math.BigInteger.(BigInteger.java:304)

at sun.security.util.DerInputBuffer.getBigInteger(DerInputBuffer.java:170)

at sun.security.util.DerValue.getBigInteger(DerValue.java:529)

at sun.security.x509.SerialNumber.construct(SerialNumber.java:44)

at sun.security.x509.SerialNumber.(SerialNumber.java:86)

at sun.security.x509.X509CRLEntryImpl.parse(X509CRLEntryImpl.java:460)

at sun.security.x509.X509CRLEntryImpl.(X509CRLEntryImpl.java:133)

at sun.security.x509.X509CRLImpl.parse(X509CRLImpl.java:1161)

at sun.security.x509.X509CRLImpl.(X509CRLImpl.java:146)

at sun.security.provider.X509Factory.intern(X509Factory.java:206)

at sun.security.x509.X509CRLImpl.toImpl(X509CRLImpl.java:1235)

at sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:396)

at sun.security.provider.certpath.DistributionPointFetcher.verifyCRL(DistributionPointFetcher.java:667)

at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:209)

at sun.security.provider.certpath.DistributionPointFetcher.getCRLs(DistributionPointFetcher.java:121)

at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:552)

at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)

at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)

at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)

at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)

at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:222)

at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140)

at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)

at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)

at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:703)

at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)

at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:560)

at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)

at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)

at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)

at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)

at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)

at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)

at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:208)

at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)

at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native method)

at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)

at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:224)

at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:318)

at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:282)

at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)

at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)

at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)

at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)

at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)

at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)

at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)

at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)

at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)

at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)

at okhttp3.RealCall.execute(RealCall.java:77)

at at.bitfire.davdroid.ClientTest.testIcloud(ClientTest.kt:24)

at java.lang.reflect.Method.invoke(Native method)

at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)

at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)

at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

at org.junit.runners.Suite.runChild(Suite.java:128)

at org.junit.runners.Suite.runChild(Suite.java:27)

at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

at org.junit.runner.JUnitCore.run(JUnitCore.java:137)

at org.junit.runner.JUnitCore.run(JUnitCore.java:115)

at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)

at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)

at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)

Waiting for a blocking GC Alloc

Clamp target GC heap from 198MB to 192MB

Alloc concurrent copying GC freed 0(0B) AllocSpace objects, 0(0B) LOS objects, 0% free, 192MB/192MB, paused 179us total 576.416ms

Starting a blocking GC Alloc

Waiting for a blocking GC Alloc

Alloc concurrent copying GC freed 4321630(114MB) AllocSpace objects, 7(51MB) LOS objects, 19% free, 25MB/31MB, paused 147us total 245.441ms

WaitForGcToComplete blocked Alloc on HeapTrim for 807.852ms

Starting a blocking GC Alloc

07-16 14:23:09.335 9513-9630/at.bitfire.cloudsync I/TestRunner: failed: testIcloud(at.bitfire.davdroid.ClientTest)

----- begin exception -----

java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available

----- end exception -----

07-16 14:23:09.336 9513-9630/at.bitfire.cloudsync I/TestRunner: finished: testIcloud(at.bitfire.davdroid.ClientTest)

07-16 14:23:09.339 9513-9513/at.bitfire.cloudsync I/MonitoringInstr: Activities that are still in CREATED to STOPPED: 0

07-16 14:23:09.340 9513-9630/at.bitfire.cloudsync I/TestRunner: run finished: 1 tests, 1 failed, 0 ignored

07-16 14:23:09.494 9513-9630/at.bitfire.cloudsync I/MonitoringInstr: waitForActivitiesToComplete() took: 1ms

07-16 14:23:09.494 9513-9513/at.bitfire.cloudsync I/MonitoringInstr: Activities that are still in CREATED to STOPPED: 0

This happens with Android 8.0 and 9.0 (emulator from SDK), but not with Android 4.4 (haven't tested other versions yet).

The problem occurs with okhttp 3.10.0 and 3.11.0 (haven't tested other versions yet).

Everything is working for some other URLs I have tested, including www.icloud.com. It seems to be related to parsing the certificate. When using a custom trust manager (from https://gitlab.com/bitfireAT/cert4android), it works.

I don't know whether this is an okhttp problem (looks like an Android problem?), but I guess it's quite important to understand why a simple GET request causes the whole process to crash.

The questionable certificate seems to be:

Certificate:

Data:

Version: 3 (0x2)

Serial Number:

0e:5e:6b:72:54:37:4e:1d:9d:db:ca:97:64:cb:b7:4f

Signature Algorithm: ecdsa-with-SHA256

Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Extended Validation CA G3

Validity

Not Before: Jan 25 00:00:00 2018 GMT

Not After : Jan 25 12:00:00 2020 GMT

Subject: businessCategory = Private Organization, jurisdictionC = US, jurisdictionST = California, serialNumber = C0806592, C = US, ST = California, L = Cupertino, O = Apple Inc., OU = GNS Edge CDN, CN = images.apple.com

Subject Public Key Info:

Public Key Algorithm: id-ecPublicKey

Public-Key: (256 bit)

pub:

04:35:15:6a:1f:88:2c:f2:f6:55:1d:58:00:f3:fc:

0f:9f:cc:bc:58:a0:ec:f4:85:e8:c5:4f:83:03:86:

12:35:b8:c7:5a:47:9e:5f:24:9a:fa:a0:4c:8e:bf:

5f:7f:ce:01:ee:e3:91:29:f6:a3:80:27:54:f2:f0:

5b:ef:73:f8:ee

ASN1 OID: prime256v1

NIST CURVE: P-256

X509v3 extensions:

X509v3 Authority Key Identifier:

keyid:99:39:FF:5F:A4:B3:59:5F:81:C0:57:99:D1:A3:A4:47:AC:60:63:4D

X509v3 Subject Key Identifier:

FB:A4:3B:3E:F5:75:BF:23:3A:C2:FA:D4:86:16:DA:74:22:8A:5B:59

X509v3 Subject Alternative Name:

DNS:images.apple.com

X509v3 Key Usage: critical

Digital Signature

X509v3 Extended Key Usage:

TLS Web Server Authentication, TLS Web Client Authentication

X509v3 CRL Distribution Points:

Full Name:

URI:http://crl3.digicert.com/evca-g3-group1.crl

Full Name:

URI:http://crl4.digicert.com/evca-g3-group1.crl

X509v3 Certificate Policies:

Policy: 2.16.840.1.114412.2.1

CPS: https://www.digicert.com/CPS

Policy: 2.23.140.1.1

Authority Information Access:

OCSP - URI:http://ocsp.digicert.com

CA Issuers - URI:http://cacerts.digicert.com/DigiCertExtendedValidationCAG3.crt

X509v3 Basic Constraints:

CA:FALSE

CT Precertificate SCTs:

Signed Certificate Timestamp:

Version : v1 (0x0)

Log ID : A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:

3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10

Timestamp : Jan 25 05:00:40.359 2018 GMT

Extensions: none

Signature : ecdsa-with-SHA256

30:46:02:21:00:F5:5D:0E:80:D0:27:06:98:35:CB:57:

A0:82:00:85:2F:56:88:CA:BE:01:25:D7:0C:A3:D9:00:

12:4D:70:71:D1:02:21:00:F2:F2:5A:16:70:A5:AB:16:

AE:01:D1:BD:C4:C7:6C:32:D6:97:FE:67:2D:EF:D4:22:

DD:C1:23:21:41:23:52:CA

Signed Certificate Timestamp:

Version : v1 (0x0)

Log ID : 56:14:06:9A:2F:D7:C2:EC:D3:F5:E1:BD:44:B2:3E:C7:

46:76:B9:BC:99:11:5C:C0:EF:94:98:55:D6:89:D0:DD

Timestamp : Jan 25 05:00:40.557 2018 GMT

Extensions: none

Signature : ecdsa-with-SHA256

30:45:02:20:44:BF:1C:68:1B:70:24:59:DD:2F:3D:90:

8D:DE:76:01:D7:9C:B9:19:4F:E2:72:71:17:61:A0:0D:

0B:7C:19:D7:02:21:00:98:7C:8B:9F:9C:5F:01:7B:93:

52:24:FC:7C:A9:39:2E:F5:A9:68:C8:3F:45:A8:D1:F2:

9F:8A:C9:40:C3:65:1B

Signed Certificate Timestamp:

Version : v1 (0x0)

Log ID : BB:D9:DF:BC:1F:8A:71:B5:93:94:23:97:AA:92:7B:47:

38:57:95:0A:AB:52:E8:1A:90:96:64:36:8E:1E:D1:85

Timestamp : Jan 25 05:00:40.567 2018 GMT

Extensions: none

Signature : ecdsa-with-SHA256

30:44:02:20:39:8E:86:EA:59:94:A4:CF:08:A4:AA:F4:

28:21:DD:FC:A6:64:8C:80:7A:56:24:BF:34:7A:FB:65:

EA:31:75:6E:02:20:67:C0:44:59:68:38:1D:D1:AA:84:

49:F7:36:86:8C:23:05:68:42:03:34:3A:88:5D:FF:DE:

E0:DB:B7:C4:77:89

Signature Algorithm: ecdsa-with-SHA256

30:66:02:31:00:cc:95:55:b4:3c:4d:c1:32:25:bd:36:5d:a3:

40:69:e8:1f:66:5c:e7:ca:b4:d4:b3:00:ad:6d:2d:ca:f6:7a:

7d:c1:6c:f5:79:a4:c1:87:e9:98:23:fb:35:35:6b:85:57:02:

31:00:af:75:53:ec:4c:00:99:93:68:87:96:d9:d3:2e:36:c7:

f0:f9:f8:69:71:93:99:76:83:e9:57:0e:5e:d5:16:ed:89:c9:

dc:0b:b8:b5:48:31:e9:cb:2c:c7:a9:0b:9d:5e

-----BEGIN CERTIFICATE-----

MIIFzTCCBVKgAwIBAgIQDl5rclQ3Th2d28qXZMu3TzAKBggqhkjOPQQDAjBsMQsw

CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu

ZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBFeHRlbmRlZCBWYWxpZGF0

aW9uIENBIEczMB4XDTE4MDEyNTAwMDAwMFoXDTIwMDEyNTEyMDAwMFowgeExHTAb

BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT

MRswGQYLKwYBBAGCNzwCAQITCkNhbGlmb3JuaWExETAPBgNVBAUTCEMwODA2NTky

MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJQ3Vw

ZXJ0aW5vMRMwEQYDVQQKEwpBcHBsZSBJbmMuMRUwEwYDVQQLEwxHTlMgRWRnZSBD

RE4xGTAXBgNVBAMTEGltYWdlcy5hcHBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjO

PQMBBwNCAAQ1FWofiCzy9lUdWADz/A+fzLxYoOz0hejFT4MDhhI1uMdaR55fJJr6

oEyOv19/zgHu45Ep9qOAJ1Ty8Fvvc/juo4IDXjCCA1owHwYDVR0jBBgwFoAUmTn/

X6SzWV+BwFeZ0aOkR6xgY00wHQYDVR0OBBYEFPukOz71db8jOsL61IYW2nQiiltZ

MBsGA1UdEQQUMBKCEGltYWdlcy5hcHBsZS5jb20wDgYDVR0PAQH/BAQDAgeAMB0G

A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBvBgNVHR8EaDBmMDGgL6Athito

dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vZXZjYS1nMy1ncm91cDEuY3JsMDGgL6At

hitodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vZXZjYS1nMy1ncm91cDEuY3JsMEsG

A1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3

LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwgYAGCCsGAQUFBwEBBHQwcjAkBggr

BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5o

dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRFeHRlbmRlZFZhbGlk

YXRpb25DQUczLmNydDAJBgNVHRMEAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFq

AWgAdwCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWErsHYnAAAE

AwBIMEYCIQD1XQ6A0CcGmDXLV6CCAIUvVojKvgEl1wyj2QASTXBx0QIhAPLyWhZw

pasWrgHRvcTHbDLWl/5nLe/UIt3BIyFBI1LKAHYAVhQGmi/XwuzT9eG9RLI+x0Z2

ubyZEVzA75SYVdaJ0N0AAAFhK7B27QAABAMARzBFAiBEvxxoG3AkWd0vPZCN3nYB

15y5GU/icnEXYaANC3wZ1wIhAJh8i5+cXwF7k1Ik/HypOS71qWjIP0Wo0fKfislA

w2UbAHUAu9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YUAAAFhK7B29wAA

BAMARjBEAiA5jobqWZSkzwikqvQoId38pmSMgHpWJL80evtl6jF1bgIgZ8BEWWg4

HdGqhEn3NoaMIwVoQgM0Oohd/97g27fEd4kwCgYIKoZIzj0EAwIDaQAwZgIxAMyV

VbQ8TcEyJb02XaNAaegfZlznyrTUswCtbS3K9np9wWz1eaTBh+mYI/s1NWuFVwIx

AK91U+xMAJmTaIeW2dMuNsfw+fhpcZOZdoPpVw5e1RbticncC7i1SDHpyyzHqQud

Xg==

-----END CERTIFICATE-----

本文来源weixin_39927508,由架构君转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/209357
0

发表评论