瀏覽代碼

lpa: Track last HTTP response on failure

We'll have a "error diagnosis" page for the new download wizard.

We'll probably want to do this for APDU too.
Peter Cai 1 年之前
父節點
當前提交
895cbdd53d

+ 12 - 6
app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt

@@ -35,6 +35,7 @@ import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeoutOrNull
 import kotlinx.coroutines.yield
+import net.typeblog.lpac_jni.HttpInterface
 import net.typeblog.lpac_jni.ProfileDownloadCallback
 
 /**
@@ -370,6 +371,10 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
             .collect()
     }
 
+    data class ProfileDownloadException(
+        val lastHttpResponse: HttpInterface.HttpResponse?
+    ) : Exception("Failed to download profile")
+
     fun launchProfileDownloadTask(
         slotId: Int,
         portId: Int,
@@ -384,8 +389,8 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
             R.drawable.ic_task_sim_card_download
         ) {
             euiccChannelManager.beginTrackedOperation(slotId, portId) {
-                val res = euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
-                    channel.lpa.downloadProfile(
+                euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
+                    val res = channel.lpa.downloadProfile(
                         smdp,
                         matchingId,
                         imei,
@@ -397,11 +402,12 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
                                     ForegroundTaskState.InProgress(state.progress)
                             }
                         })
-                }
 
-                if (!res) {
-                    // TODO: Provide more details on the error
-                    throw RuntimeException("Failed to download profile; this is typically caused by another error happened before.")
+                    if (!res) {
+                        throw ProfileDownloadException(
+                            channel.lpa.lastHttpResponse
+                        )
+                    }
                 }
 
                 preferenceRepository.notificationDownloadFlow.first()

+ 9 - 0
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/HttpInterface.kt

@@ -26,6 +26,15 @@ interface HttpInterface {
         }
     }
 
+    /**
+     * The last HTTP response we have received from the SM-DP+ server.
+     *
+     * This is intended for error diagnosis. However, note that most SM-DP+ servers
+     * respond with 200 even when there is an error. This needs to be taken into
+     * account when designing UI.
+     */
+    val lastHttpResponse: HttpResponse?
+
     fun transmit(url: String, tx: ByteArray, headers: Array<String>): HttpResponse
     // The LPA is supposed to pass in a list of pkIds supported by the eUICC.
     // HttpInterface is responsible for providing TrustManager implementations that

+ 3 - 0
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt

@@ -1,5 +1,7 @@
 package net.typeblog.lpac_jni
 
+import net.typeblog.lpac_jni.HttpInterface.HttpResponse
+
 interface LocalProfileAssistant {
     val valid: Boolean
     val profiles: List<LocalProfileInfo>
@@ -7,6 +9,7 @@ interface LocalProfileAssistant {
     val eID: String
     // Extended EuiccInfo for use with LUIs, containing information such as firmware version
     val euiccInfo2: EuiccInfo2?
+    val lastHttpResponse: HttpResponse?
 
     /**
      * Set the max segment size (mss) for all es10x commands. This can help with removable

+ 5 - 1
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/HttpInterfaceImpl.kt

@@ -23,6 +23,8 @@ class HttpInterfaceImpl(
 
     private lateinit var trustManagers: Array<TrustManager>
 
+    override var lastHttpResponse: HttpInterface.HttpResponse? = null
+
     override fun transmit(
         url: String,
         tx: ByteArray,
@@ -73,7 +75,9 @@ class HttpInterfaceImpl(
                 }
             }
 
-            return HttpInterface.HttpResponse(conn.responseCode, bytes)
+            return HttpInterface.HttpResponse(conn.responseCode, bytes).also {
+                lastHttpResponse = it
+            }
         } catch (e: Exception) {
             e.printStackTrace()
             throw e

+ 4 - 1
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt

@@ -12,7 +12,7 @@ import net.typeblog.lpac_jni.ProfileDownloadCallback
 
 class LocalProfileAssistantImpl(
     private val apduInterface: ApduInterface,
-    httpInterface: HttpInterface
+    private val httpInterface: HttpInterface
 ): LocalProfileAssistant {
     companion object {
         private const val TAG = "LocalProfileAssistantImpl"
@@ -34,6 +34,9 @@ class LocalProfileAssistantImpl(
         LpacJni.euiccSetMss(contextHandle, mss)
     }
 
+    override val lastHttpResponse: HttpInterface.HttpResponse?
+        get() = httpInterface.lastHttpResponse
+
     override val valid: Boolean
         get() = !finalized && apduInterface.valid && try {
             // If we can read both eID and euiccInfo2 properly, we are likely looking at