facebook / facebook-android-sdk

Used to integrate Android apps with Facebook Platform.
https://developers.facebook.com/docs/android
Other
6.17k stars 3.66k forks source link

OidcSecurityUtil.getRawKeyFromEndPoint results in a blocking HTTP call that can result in a ANR #1193

Open dbaker-bitwise opened 1 year ago

dbaker-bitwise commented 1 year ago

Checklist before submitting a bug report

Java version

8

Android version

SDK 31

Android SDK version

13.0.0

Installation platform & version

Gradle 7.0.0

Package

Core & AppEvents

Goals

No blocking HTTP calls on the main thread

Expected results

The application is free of ANRs.

Actual results

We occasionally see ANRs reported in our error collection service with the following relevant callstacks.

Thread 2 - MainThread-UE4 - (TIMED_WAITING)
        at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2211)
        at n1.c.c(OidcSecurityUtil.kt:7)
        at com.facebook.AuthenticationToken.a(AuthenticationToken.kt:1)
        at com.facebook.AuthenticationToken.<init>(AuthenticationToken.kt:13)
        at com.facebook.login.LoginMethodHandler$a.d(LoginMethodHandler.kt:4)
        at com.facebook.login.NativeAppLoginMethodHandler.w(NativeAppLoginMethodHandler.kt:4)
        at com.facebook.login.NativeAppLoginMethodHandler.x(NativeAppLoginMethodHandler.kt:3)
        at com.facebook.login.NativeAppLoginMethodHandler.j(NativeAppLoginMethodHandler.kt:15)
        at com.facebook.login.LoginClient.u(LoginClient.kt:8)
        at com.facebook.login.j.onActivityResult(LoginFragment.kt:2)
        at androidx.fragment.app.FragmentManager$j.b(FragmentManager.java:9)
        at androidx.fragment.app.FragmentManager$j.a(FragmentManager.java:1)
        at androidx.activity.result.ActivityResultRegistry.d(ActivityResultRegistry.java:3)
        at androidx.activity.result.ActivityResultRegistry.b(ActivityResultRegistry.java:2)
        at androidx.activity.ComponentActivity.onActivityResult(ComponentActivity.java:1)
        at androidx.fragment.app.d.onActivityResult(FragmentActivity.java:2)
        at android.app.Activity.dispatchActivityResult(Activity.java:8630)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:5446)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:5492)
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:54)
        at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2282)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:210)
        at android.os.Looper.loop(Looper.java:299)
        at android.app.ActivityThread.main(ActivityThread.java:8250)
        at java.lang.reflect.Method.invoke(Method.java:-2)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)

Thread 985 - pool-13-thread-1 - (RUNNABLE)
        at libcore.io.Linux.connect(Linux.java:-2)
        at libcore.io.ForwardingOs.connect(ForwardingOs.java:201)
        at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:158)
        at libcore.io.ForwardingOs.connect(ForwardingOs.java:201)
        at libcore.io.IoBridge.connectErrno(IoBridge.java:201)
        at libcore.io.IoBridge.connect(IoBridge.java:179)
        at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
        at java.net.Socket.connect(Socket.java:646)
        at com.android.okhttp.internal.Platform.connectSocket(Platform.java:182)
        at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:145)
        at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30)
        at com.facebook.GraphRequest$c.K(GraphRequest.kt:19)
        at com.facebook.GraphRequest$c.M(GraphRequest.kt:7)
        at com.facebook.GraphRequest$c.j(GraphRequest.kt:2)
        at com.facebook.GraphRequest$c.i(GraphRequest.kt:1)
        at com.facebook.GraphRequest$c.k(GraphRequest.kt:1)
        at com.facebook.GraphRequest$c.h(GraphRequest.kt:1)
        at com.facebook.GraphRequest.k(GraphRequest.kt:1)
        at p0.l.u(AppEventQueue.kt:11)
        at p0.l.n(AppEventQueue.kt:3)
        at p0.l.o(AppEventQueue.kt:3)
        at p0.l.b(Unknown)
        at p0.k.run(Unknown)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:463)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
        at java.lang.Thread.run(Thread.java:1012)

It appears that what is happening is that during a login attempt the following happens.

The OidcSecurityUtil.getRawKeyFromEndpoint() function looks like this:

  fun getRawKeyFromEndPoint(kid: String): String? {
    val host = "www.${FacebookSdk.getFacebookDomain()}"
    val openIdKeyUrl = URL("https", host, OPENID_KEYS_PATH)
    val lock = ReentrantLock()
    val condition = lock.newCondition()
    var result: String? = null
    FacebookSdk.getExecutor().execute {
      val connection = openIdKeyUrl.openConnection() as HttpURLConnection
      try {
        val data = connection.inputStream.bufferedReader().readText()
        connection.inputStream.close()
        result = JSONObject(data).optString(kid)
      } catch (_ex: Exception) {
        // return null if ANY exception happens
        Log.d(OidcSecurityUtil.javaClass.name, _ex.message ?: "Error getting public key")
      } finally {
        connection.disconnect()
        lock.withLock { condition.signal() }
      }
    }
    lock.withLock { condition.await(TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS) }
    return result
  }

This results in a blocking wait on the main thread until the HTTP request can be completed. It seems that this sometimes takes more than 5 seconds to complete and results in the reported ANR.

Steps to reproduce

No response

Code samples & details

No response