diff --git a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt index 6f8479c..b715ca0 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt @@ -1,11 +1,9 @@ package im.angry.openeuicc.core -import net.typeblog.lpac_jni.EuiccConfiguredAddresses import net.typeblog.lpac_jni.EuiccInfo2 import net.typeblog.lpac_jni.LocalProfileAssistant import net.typeblog.lpac_jni.LocalProfileInfo import net.typeblog.lpac_jni.LocalProfileNotification -import net.typeblog.lpac_jni.ProfileDiscoveryCallback import net.typeblog.lpac_jni.ProfileDownloadCallback class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) : @@ -31,8 +29,6 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) : get() = lpa.eID override val euiccInfo2: EuiccInfo2? get() = lpa.euiccInfo2 - override val euiccConfiguredAddresses: EuiccConfiguredAddresses - get() = lpa.euiccConfiguredAddresses override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss) @@ -52,9 +48,6 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) : callback: ProfileDownloadCallback ) = lpa.downloadProfile(smdp, matchingId, imei, confirmationCode, callback) - override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) = - lpa.discoveryProfile(smds, imei, callback) - override fun deleteNotification(seqNumber: Long): Boolean = lpa.deleteNotification(seqNumber) override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber) diff --git a/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt b/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt index e95d1b2..9957f30 100644 --- a/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt +++ b/app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt @@ -380,18 +380,6 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { getString(R.string.task_profile_download_failure), R.drawable.ic_task_sim_card_download ) { - val callback = object : ProfileDownloadCallback { - override var isCancelled: Boolean = false - - override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) { - if (state.progress == 0) return - foregroundTaskState.value = ForegroundTaskState.InProgress(state.progress) - } - - override fun onProfileMetadata(metadata: ProfileDownloadCallback.ProfileMetadata) { - Log.d(TAG, "Downloaded profile metadata: $metadata") - } - } euiccChannelManager.beginTrackedOperation(slotId, portId) { euiccChannelManager.withEuiccChannel(slotId, portId) { channel -> channel.lpa.downloadProfile( @@ -399,8 +387,13 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker { matchingId, imei, confirmationCode, - callback - ) + object : ProfileDownloadCallback { + override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) { + if (state.progress == 0) return + foregroundTaskState.value = + ForegroundTaskState.InProgress(state.progress) + } + }) } preferenceRepository.notificationDownloadFlow.first() diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt index 5b7b21e..12995ff 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt @@ -43,7 +43,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext -import net.typeblog.lpac_jni.ProfileClass open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, EuiccChannelFragmentMarker { @@ -388,9 +387,9 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, profileClass.isVisible = unfilteredProfileListFlow.value profileClass.setText( when (profile.profileClass) { - ProfileClass.Testing -> R.string.profile_class_testing - ProfileClass.Provisioning -> R.string.profile_class_provisioning - ProfileClass.Operational -> R.string.profile_class_operational + LocalProfileInfo.Clazz.Testing -> R.string.profile_class_testing + LocalProfileInfo.Clazz.Provisioning -> R.string.profile_class_provisioning + LocalProfileInfo.Clazz.Operational -> R.string.profile_class_operational } ) iccid.text = profile.iccid diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt index 02cdac8..21a2d40 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/NotificationsActivity.kt @@ -26,7 +26,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import net.typeblog.lpac_jni.LocalProfileNotification -import net.typeblog.lpac_jni.ProfileManagementOperation class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { private lateinit var swipeRefresh: SwipeRefreshLayout @@ -164,13 +163,13 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker { } - private fun operationToLocalizedText(operation: ProfileManagementOperation) = + private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) = root.context.getText( when (operation) { - ProfileManagementOperation.Install -> R.string.profile_notification_operation_download - ProfileManagementOperation.Delete -> R.string.profile_notification_operation_delete - ProfileManagementOperation.Enable -> R.string.profile_notification_operation_enable - ProfileManagementOperation.Disable -> R.string.profile_notification_operation_disable + LocalProfileNotification.Operation.Install -> R.string.profile_notification_operation_download + LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete + LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable + LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable }) fun updateNotification(value: LocalProfileNotificationWrapper) { diff --git a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt index cc1001b..9f95412 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt @@ -5,8 +5,6 @@ import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import net.typeblog.lpac_jni.LocalProfileAssistant import net.typeblog.lpac_jni.LocalProfileInfo -import net.typeblog.lpac_jni.ProfileClass -import net.typeblog.lpac_jni.ProfileState const val TAG = "LPAUtils" @@ -15,10 +13,10 @@ val LocalProfileInfo.displayName: String val LocalProfileInfo.isEnabled: Boolean - get() = state == ProfileState.Enabled + get() = state == LocalProfileInfo.State.Enabled val List.operational: List - get() = filter { it.profileClass == ProfileClass.Operational } + get() = filter { it.profileClass == LocalProfileInfo.Clazz.Operational } val List.enabled: LocalProfileInfo? get() = find { it.isEnabled } diff --git a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt index 8ce7958..02b3baf 100644 --- a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt +++ b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt @@ -15,8 +15,6 @@ import im.angry.openeuicc.util.* import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking -import net.typeblog.lpac_jni.ProfileClass -import net.typeblog.lpac_jni.ProfileState import kotlin.IllegalStateException class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { @@ -202,15 +200,15 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker { setServiceProviderName(it.providerName) setState( when (it.state) { - ProfileState.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED - ProfileState.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED + LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED + LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED } ) setProfileClass( when (it.profileClass) { - ProfileClass.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING - ProfileClass.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING - ProfileClass.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL + LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING + LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING + LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL } ) }.build() diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccConfiguredAddresses.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccConfiguredAddresses.kt deleted file mode 100644 index 65048f0..0000000 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/EuiccConfiguredAddresses.kt +++ /dev/null @@ -1,29 +0,0 @@ -package net.typeblog.lpac_jni - -import android.util.Patterns - -// example address in GSMA SGP.26, some chips use addresses like this -@Suppress("SpellCheckingInspection") -private val invalidDPAddresses = setOf( - "testrootsmds.gsma.com", - "testrootsmds.example.com", -) - -class EuiccConfiguredAddresses(defaultDPAddress: String?, rootDSAddress: String?) { - val defaultDPAddress: String? = defaultDPAddress.takeUnless(::isInvalidDPAddress) - val rootDSAddress = rootDSAddress.takeUnless(::isInvalidDSAddress) - - val discoverable: Boolean - get() = !defaultDPAddress.isNullOrBlank() || !rootDSAddress.isNullOrBlank() -} - -private fun isInvalidDPAddress(address: String?): Boolean { - if (address.isNullOrBlank()) return true - return !Patterns.DOMAIN_NAME.matcher(address).matches() -} - -private fun isInvalidDSAddress(address: String?): Boolean { - if (address.isNullOrBlank()) return true - if (address in invalidDPAddresses) return true - return !Patterns.DOMAIN_NAME.matcher(address).matches() -} \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt index df9f714..48ab1c5 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt @@ -12,18 +12,9 @@ interface LocalProfileAssistant { val lastApduException: Exception?, ) : Exception("Failed to download profile") - @Suppress("ArrayInDataClass") - data class ProfileDiscoveryException( - val lpaErrorReason: String, - val lastHttpResponse: HttpResponse?, - val lastHttpException: Exception?, - val lastApduResponse: ByteArray?, - val lastApduException: Exception?, - ) : Exception("Failed to discover profile") - - class ProfileRenameException : Exception("Failed to rename profile") - class ProfileNameTooLongException : Exception("Profile name too long") - class ProfileNameIsInvalidUTF8Exception : Exception("Profile name is invalid UTF-8") + class ProfileRenameException() : Exception("Failed to rename profile") + class ProfileNameTooLongException() : Exception("Profile name too long") + class ProfileNameIsInvalidUTF8Exception() : Exception("Profile name is invalid UTF-8") val valid: Boolean val profiles: List @@ -31,7 +22,6 @@ interface LocalProfileAssistant { val eID: String // Extended EuiccInfo for use with LUIs, containing information such as firmware version val euiccInfo2: EuiccInfo2? - val euiccConfiguredAddresses: EuiccConfiguredAddresses /** * Set the max segment size (mss) for all es10x commands. This can help with removable @@ -49,8 +39,6 @@ interface LocalProfileAssistant { fun downloadProfile(smdp: String, matchingId: String?, imei: String?, confirmationCode: String?, callback: ProfileDownloadCallback) - fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) - fun deleteNotification(seqNumber: Long): Boolean fun handleNotification(seqNumber: Long): Boolean diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt index 96e16ef..a7e296f 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileInfo.kt @@ -2,14 +2,42 @@ package net.typeblog.lpac_jni data class LocalProfileInfo( val iccid: String, - val state: ProfileState, + val state: State, val name: String, val nickName: String, val providerName: String, val isdpAID: String, - val profileClass: ProfileClass -) + val profileClass: Clazz +) { + enum class State { + Enabled, + Disabled; -enum class ProfileState { Enabled, Disabled } + companion object { + @JvmStatic + fun fromString(str: String?) = + when (str?.lowercase()) { + "enabled" -> Enabled + "disabled" -> Disabled + else -> Disabled + } + } + } -enum class ProfileClass { Testing, Provisioning, Operational } + enum class Clazz { + Testing, + Provisioning, + Operational; + + companion object { + @JvmStatic + fun fromString(str: String?) = + when (str?.lowercase()) { + "test" -> Testing + "provisioning" -> Provisioning + "operational" -> Operational + else -> Operational + } + } + } +} \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt index 3ecb65b..57cc8cf 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileNotification.kt @@ -2,11 +2,26 @@ package net.typeblog.lpac_jni data class LocalProfileNotification( val seqNumber: Long, - val profileManagementOperation: ProfileManagementOperation, + val profileManagementOperation: Operation, val notificationAddress: String, val iccid: String, -) +) { + enum class Operation { + Install, + Enable, + Disable, + Delete; -enum class ProfileManagementOperation { - Install, Enable, Disable, Delete + companion object { + @JvmStatic + fun fromString(str: String?) = + when (str?.lowercase()) { + "install" -> Install + "enable" -> Enable + "disable" -> Disable + "delete" -> Delete + else -> throw IllegalArgumentException("Unknown operation $str") + } + } + } } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 6f70bc4..fa9474f 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -19,22 +19,16 @@ internal object LpacJni { // es10c // null returns signify errors external fun es10cGetEid(handle: Long): String? - external fun es10cGetProfilesInfo(handle: Long, profiles: List): Long + external fun es10cGetProfilesInfo(handle: Long): Long external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDeleteProfile(handle: Long, iccid: String): Int external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int // es10b - external fun es10bListNotification(handle: Long, elements: List): Int + external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null) external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int - // es10a - external fun es10aGetEuiccConfiguredAddresses(handle: Long): EuiccConfiguredAddresses - - // es9p + es11 - external fun discoveryProfile(handle: Long, address: String, imei: String?, callback: ProfileDiscoveryCallback): Int - // es9p + es10b // We do not expose all of the functions because of tediousness :) external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?, @@ -47,5 +41,40 @@ internal object LpacJni { // ES10c external fun es10cEuiccMemoryReset(handle: Long): Int // es10cex (actually part of es10b) - external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2? + external fun es10cexGetEuiccInfo2(handle: Long): Long + + // C <-> Java struct / linked list handling + // C String arrays + external fun stringArrNext(curr: Long): Long + external fun stringDeref(curr: Long): String + // Profiles + external fun profilesNext(curr: Long): Long + external fun profilesFree(head: Long): Long + external fun profileGetIccid(curr: Long): String + external fun profileGetIsdpAid(curr: Long): String + external fun profileGetName(curr: Long): String + external fun profileGetNickname(curr: Long): String + external fun profileGetServiceProvider(curr: Long): String + external fun profileGetStateString(curr: Long): String + external fun profileGetClassString(curr: Long): String + // Notifications + external fun notificationsNext(curr: Long): Long + external fun notificationGetSeq(curr: Long): Long + external fun notificationGetOperationString(curr: Long): String + external fun notificationGetAddress(curr: Long): String + external fun notificationGetIccid(curr: Long): String + external fun notificationsFree(head: Long) + // EuiccInfo2 + external fun euiccInfo2Free(info: Long) + external fun euiccInfo2GetSGP22Version(info: Long): String + external fun euiccInfo2GetProfileVersion(info: Long): String + external fun euiccInfo2GetEuiccFirmwareVersion(info: Long): String + external fun euiccInfo2GetGlobalPlatformVersion(info: Long): String + external fun euiccInfo2GetSasAcreditationNumber(info: Long): String + external fun euiccInfo2GetPpVersion(info: Long): String + external fun euiccInfo2GetFreeNonVolatileMemory(info: Long): Long + external fun euiccInfo2GetFreeVolatileMemory(info: Long): Long + // C String Arrays + external fun euiccInfo2GetEuiccCiPKIdListForSigning(info: Long): Long + external fun euiccInfo2GetEuiccCiPKIdListForVerification(info: Long): Long } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDiscoveryCallback.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDiscoveryCallback.kt deleted file mode 100644 index 4cd7761..0000000 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDiscoveryCallback.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.typeblog.lpac_jni - -import java.util.ArrayList - -interface ProfileDiscoveryCallback { - fun onDiscovered(servers: ArrayList) -} diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadCallback.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadCallback.kt index 692583b..289ddf6 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadCallback.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ProfileDownloadCallback.kt @@ -2,14 +2,15 @@ package net.typeblog.lpac_jni interface ProfileDownloadCallback { companion object { - fun lookupStateFromProgress(progress: Int): DownloadState = when (progress) { - 0 -> DownloadState.Preparing - 20 -> DownloadState.Connecting - 40 -> DownloadState.Authenticating - 60 -> DownloadState.Downloading - 80 -> DownloadState.Finalizing - else -> throw IllegalArgumentException("Unknown state") - } + fun lookupStateFromProgress(progress: Int): DownloadState = + when (progress) { + 0 -> DownloadState.Preparing + 20 -> DownloadState.Connecting + 40 -> DownloadState.Authenticating + 60 -> DownloadState.Downloading + 80 -> DownloadState.Finalizing + else -> throw IllegalArgumentException("Unknown state") + } } enum class DownloadState(val progress: Int) { @@ -20,18 +21,5 @@ interface ProfileDownloadCallback { Finalizing(80), // load bpp } - data class ProfileMetadata( - val iccid: String, - val serviceProviderName: String, - val profileName: String, - val iconType: String, - val icon: String, - val profileClass: ProfileClass, - ) - - var isCancelled: Boolean - fun onStateUpdate(state: DownloadState) - - fun onProfileMetadata(metadata: ProfileMetadata) } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 01a8b9d..3674f4f 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -3,14 +3,12 @@ package net.typeblog.lpac_jni.impl import android.util.Log import net.typeblog.lpac_jni.LpacJni import net.typeblog.lpac_jni.ApduInterface -import net.typeblog.lpac_jni.EuiccConfiguredAddresses import net.typeblog.lpac_jni.EuiccInfo2 import net.typeblog.lpac_jni.HttpInterface import net.typeblog.lpac_jni.HttpInterface.HttpResponse import net.typeblog.lpac_jni.LocalProfileAssistant import net.typeblog.lpac_jni.LocalProfileInfo import net.typeblog.lpac_jni.LocalProfileNotification -import net.typeblog.lpac_jni.ProfileDiscoveryCallback import net.typeblog.lpac_jni.ProfileDownloadCallback import net.typeblog.lpac_jni.Version @@ -109,19 +107,45 @@ class LocalProfileAssistantImpl( override val profiles: List @Synchronized get() { - val profiles = mutableListOf() - val ret = LpacJni.es10cGetProfilesInfo(contextHandle, profiles) - if (ret < 0) throw IllegalStateException("Failed to get profiles") - return profiles + val head = LpacJni.es10cGetProfilesInfo(contextHandle) + var curr = head + val ret = mutableListOf() + while (curr != 0L) { + val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr)) + val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr)) + ret.add(LocalProfileInfo( + LpacJni.profileGetIccid(curr), + state, + LpacJni.profileGetName(curr), + LpacJni.profileGetNickname(curr), + LpacJni.profileGetServiceProvider(curr), + LpacJni.profileGetIsdpAid(curr), + clazz + )) + curr = LpacJni.profilesNext(curr) + } + + LpacJni.profilesFree(curr) + return ret } override val notifications: List @Synchronized get() { - val notifications = mutableListOf() - val ret = LpacJni.es10bListNotification(contextHandle, notifications) - check(ret > 0) { "Failed to get notifications" } - return notifications.sortedBy { it.seqNumber }.reversed() + val head = LpacJni.es10bListNotification(contextHandle) + var curr = head + val ret = mutableListOf() + while (curr != 0L) { + ret.add(LocalProfileNotification( + LpacJni.notificationGetSeq(curr), + LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)), + LpacJni.notificationGetAddress(curr), + LpacJni.notificationGetIccid(curr), + )) + curr = LpacJni.notificationsNext(curr) + } + LpacJni.notificationsFree(head) + return ret.sortedBy { it.seqNumber }.reversed() } override val eID: String @@ -130,9 +154,39 @@ class LocalProfileAssistantImpl( override val euiccInfo2: EuiccInfo2? @Synchronized - get() = LpacJni.es10cexGetEuiccInfo2(contextHandle) - override val euiccConfiguredAddresses: EuiccConfiguredAddresses - get() = LpacJni.es10aGetEuiccConfiguredAddresses(contextHandle) + get() { + val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle) + if (cInfo == 0L) return null + + val ret = EuiccInfo2( + Version(LpacJni.euiccInfo2GetSGP22Version(cInfo)), + Version(LpacJni.euiccInfo2GetProfileVersion(cInfo)), + Version(LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo)), + Version(LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo)), + LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo), + Version(LpacJni.euiccInfo2GetPpVersion(cInfo)), + LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(), + LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(), + buildSet { + var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo) + while (cursor != 0L) { + add(LpacJni.stringDeref(cursor)) + cursor = LpacJni.stringArrNext(cursor) + } + }, + buildSet { + var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo) + while (cursor != 0L) { + add(LpacJni.stringDeref(cursor)) + cursor = LpacJni.stringArrNext(cursor) + } + }, + ) + + LpacJni.euiccInfo2Free(cInfo) + + return ret + } @Synchronized override fun enableProfile(iccid: String, refresh: Boolean): Boolean = @@ -158,31 +212,21 @@ class LocalProfileAssistantImpl( callback ) - if (res == 0) return - // Construct the error now to store any error information we _can_ access - val err = LocalProfileAssistant.ProfileDownloadException( - lpaErrorReason = LpacJni.downloadErrCodeToString(-res), - httpInterface.lastHttpResponse, - httpInterface.lastHttpException, - apduInterface.lastApduResponse, - apduInterface.lastApduException, - ) - // Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces. - LpacJni.cancelSessions(contextHandle) - throw err - } + if (res != 0) { + // Construct the error now to store any error information we _can_ access + val err = LocalProfileAssistant.ProfileDownloadException( + lpaErrorReason = LpacJni.downloadErrCodeToString(-res), + httpInterface.lastHttpResponse, + httpInterface.lastHttpException, + apduInterface.lastApduResponse, + apduInterface.lastApduException, + ) - override fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback) { - val ret = LpacJni.discoveryProfile(contextHandle, smds, imei, callback) - if (ret == 0) return - // Construct the error now to store any error information we _can_ access - throw LocalProfileAssistant.ProfileDiscoveryException( - lpaErrorReason = LpacJni.downloadErrCodeToString(-ret), - httpInterface.lastHttpResponse, - httpInterface.lastHttpException, - apduInterface.lastApduResponse, - apduInterface.lastApduException, - ) + // Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces. + LpacJni.cancelSessions(contextHandle) + + throw err + } } @Synchronized diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c index 702ba45..a61fc96 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c @@ -1,20 +1,20 @@ #include #include #include "interface-wrapper.h" -#include "lpac-convertor.h" -static jmethodID method_apdu_connect; -static jmethodID method_apdu_disconnect; -static jmethodID method_apdu_logical_channel_open; -static jmethodID method_apdu_logical_channel_close; -static jmethodID method_apdu_transmit; +jmethodID method_apdu_connect; +jmethodID method_apdu_disconnect; +jmethodID method_apdu_logical_channel_open; +jmethodID method_apdu_logical_channel_close; +jmethodID method_apdu_transmit; -static jmethodID method_http_transmit; +jmethodID method_http_transmit; -static jfieldID field_resp_rcode; -static jfieldID field_resp_data; +jfieldID field_resp_rcode; +jfieldID field_resp_data; -void interface_wrapper_init(JNIEnv *env) { +void interface_wrapper_init() { + LPAC_JNI_SETUP_ENV; jclass apdu_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/ApduInterface"); method_apdu_connect = (*env)->GetMethodID(env, apdu_class, "connect", "()V"); method_apdu_disconnect = (*env)->GetMethodID(env, apdu_class, "disconnect", "()V"); @@ -80,7 +80,7 @@ apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, c LPAC_JNI_EXCEPTION_RETURN; *rx_len = (*env)->GetArrayLength(env, ret); *rx = calloc(*rx_len, sizeof(uint8_t)); - (*env)->GetByteArrayRegion(env, ret, 0, (jsize) *rx_len, (jbyte *) *rx); + (*env)->GetByteArrayRegion(env, ret, 0, *rx_len, *rx); (*env)->DeleteLocalRef(env, txArr); (*env)->DeleteLocalRef(env, ret); return 0; @@ -92,8 +92,8 @@ http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode, const char **headers) { LPAC_JNI_SETUP_ENV; jstring jurl = toJString(env, url); - jbyteArray txArr = (*env)->NewByteArray(env, (jsize) tx_len); - (*env)->SetByteArrayRegion(env, txArr, 0, (jsize) tx_len, (const jbyte *) tx); + jbyteArray txArr = (*env)->NewByteArray(env, tx_len); + (*env)->SetByteArrayRegion(env, txArr, 0, tx_len, (const jbyte *) tx); int num_headers = 0; while (headers[num_headers] != NULL) { @@ -113,7 +113,7 @@ http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode, jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data); *rx_len = (*env)->GetArrayLength(env, rxArr); *rx = calloc(*rx_len, sizeof(uint8_t)); - (*env)->GetByteArrayRegion(env, rxArr, 0, (jsize) *rx_len, (jbyte *) *rx); + (*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, *rx); (*env)->DeleteLocalRef(env, txArr); (*env)->DeleteLocalRef(env, rxArr); (*env)->DeleteLocalRef(env, headersArr); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.h b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.h index fec3869..e22837b 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.h @@ -5,7 +5,7 @@ #include #include "lpac-jni.h" -void interface_wrapper_init(JNIEnv *env); +void interface_wrapper_init(); extern struct euicc_apdu_interface lpac_jni_apdu_interface; extern struct euicc_http_interface lpac_jni_http_interface; diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c deleted file mode 100644 index 19f4010..0000000 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.c +++ /dev/null @@ -1,202 +0,0 @@ -#include "lpac-convertor.h" -#include -#include -#include - -static jobject profile_state_enabled; -static jobject profile_state_disabled; -static jobject profile_class_operational; -static jobject profile_class_provisioning; -static jobject profile_class_testing; -static jobject profile_management_operation_install; -static jobject profile_management_operation_enable; -static jobject profile_management_operation_disable; -static jobject profile_management_operation_delete; - -static jclass version_class; -static jmethodID version_constructor; - -static jstring empty_string; -jclass string_class; -static jmethodID string_constructor; - -jobject bind_static_field(JNIEnv *env, jclass clazz, const char *name, const char *sig) { - jfieldID field = (*env)->GetStaticFieldID(env, clazz, name, sig); - jobject bound = (*env)->GetStaticObjectField(env, clazz, field); - return (*env)->NewGlobalRef(env, bound); -} - -#define BIND_PROFILE_STATE_STATIC_FIELD(NAME, FIELD) \ - profile_state_##NAME = bind_static_field(env, profile_state_class, FIELD, "L" PROFILE_STATE_CLASS ";") - -#define BIND_PROFILE_CLASS_STATIC_FIELD(NAME, FIELD) \ - profile_class_##NAME = bind_static_field(env, profile_class_class, FIELD, "L" PROFILE_CLASS_CLASS ";") - -#define BIND_NOTIFICATION_OPERATION_FIELD(NAME, FIELD) \ - profile_management_operation_##NAME = bind_static_field(env, profile_management_operation_class, FIELD, "L" PROFILE_MANAGEMENT_OPERATION_CLASS ";") - -static void init_string_class(JNIEnv *env) { - string_class = (*env)->FindClass(env, "java/lang/String"); - string_class = (*env)->NewGlobalRef(env, string_class); - string_constructor = (*env)->GetMethodID(env, string_class, "", - "([BLjava/lang/String;)V"); - const jchar _unused[1]; - empty_string = (*env)->NewString(env, _unused, 0); - empty_string = (*env)->NewGlobalRef(env, empty_string); -} - -void lpac_convertor_init(JNIEnv *env) { - init_string_class(env); - - version_class = (*env)->FindClass(env, VERSION_CLASS); - version_class = (*env)->NewGlobalRef(env, version_class); - version_constructor = (*env)->GetMethodID( - env, version_class, "", "(Ljava/lang/String;)V"); - - jclass profile_state_class = (*env)->FindClass( - env, PROFILE_STATE_CLASS); - BIND_PROFILE_STATE_STATIC_FIELD(enabled, "Enabled"); - BIND_PROFILE_STATE_STATIC_FIELD(disabled, "Disabled"); - - jclass profile_class_class = (*env)->FindClass( - env, PROFILE_CLASS_CLASS); - BIND_PROFILE_CLASS_STATIC_FIELD(operational, "Operational"); - BIND_PROFILE_CLASS_STATIC_FIELD(provisioning, "Provisioning"); - BIND_PROFILE_CLASS_STATIC_FIELD(testing, "Testing"); - - jclass profile_management_operation_class = (*env)->FindClass( - env, PROFILE_MANAGEMENT_OPERATION_CLASS); - BIND_NOTIFICATION_OPERATION_FIELD(install, "Install"); - BIND_NOTIFICATION_OPERATION_FIELD(delete, "Delete"); - BIND_NOTIFICATION_OPERATION_FIELD(enable, "Enable"); - BIND_NOTIFICATION_OPERATION_FIELD(disable, "Disable"); -} - -jstring toJString(JNIEnv *env, const char *pat) { - jbyteArray bytes = NULL; - jstring encoding = NULL; - jstring jstr = NULL; - jsize len; - - if (pat == NULL) - return (*env)->NewLocalRef(env, empty_string); - - len = (jsize) strlen(pat); - bytes = (*env)->NewByteArray(env, len); - (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) pat); - encoding = (*env)->NewStringUTF(env, "utf-8"); - jstr = (jstring) (*env)->NewObject(env, string_class, - string_constructor, bytes, encoding); - (*env)->DeleteLocalRef(env, encoding); - (*env)->DeleteLocalRef(env, bytes); - return jstr; -} - -jobject to_profile_state(enum es10c_profile_state profile_state) { - switch (profile_state) { - case ES10C_PROFILE_STATE_ENABLED: - return profile_state_enabled; - case ES10C_PROFILE_STATE_DISABLED: - return profile_state_disabled; - default: - return NULL; - } -} - -jobject to_profile_class(enum es10c_profile_class profile_class) { - switch (profile_class) { - case ES10C_PROFILE_CLASS_OPERATIONAL: - return profile_class_operational; - case ES10C_PROFILE_CLASS_PROVISIONING: - return profile_class_provisioning; - case ES10C_PROFILE_CLASS_TEST: - return profile_class_testing; - default: - return NULL; - } -} - -jstring to_icon_type(JNIEnv *env, enum es10c_icon_type icon_type) { - switch (icon_type) { - case ES10C_ICON_TYPE_JPEG: - return toJString(env, "jpeg"); - case ES10C_ICON_TYPE_PNG: - return toJString(env, "png"); - default: - return NULL; - } -} - -jobject to_version(JNIEnv *env, const char *version) { - jstring value = toJString(env, version); - return (*env)->NewObject(env, version_class, version_constructor, value); -} - -jobject to_string_list(JNIEnv *env, char **values) { - jclass array_class = (*env)->FindClass(env, ARRAY_LIST_CLASS); - jmethodID array_constructor = (*env)->GetMethodID(env, array_class, "", "()V"); - jobject elements = (*env)->NewObject(env, array_class, array_constructor); - jmethodID add_element = (*env)->GetMethodID(env, array_class, "add", "(Ljava/lang/Object;)Z"); - jstring element = NULL; - for (jsize index = 0; values[index] != NULL; index++) { - element = toJString(env, values[index]); - (*env)->CallBooleanMethod(env, elements, add_element, element); - } - return elements; -} - -jobject to_string_set(JNIEnv *env, char **values) { - jclass set_class = (*env)->FindClass(env, HASH_SET_CLASS); - jmethodID set_constructor = (*env)->GetMethodID(env, set_class, "", "()V"); - jobject elements = (*env)->NewObject(env, set_class, set_constructor); - jmethodID add_element = (*env)->GetMethodID(env, set_class, "add", "(Ljava/lang/Object;)Z"); - jstring element = NULL; - for (jsize index = 0; values[index] != NULL; index++) { - element = toJString(env, values[index]); - (*env)->CallBooleanMethod(env, elements, add_element, element); - } - return elements; -} - -jobject build_profile_metadata(JNIEnv *env, struct es8p_metadata *metadata) { - if (metadata == NULL) return NULL; - - jclass profile_metadata_class = (*env)->FindClass(env, PROFILE_METADATA_CLASS); - jmethodID profile_metadata_constructor = (*env)->GetMethodID( - env, profile_metadata_class, "", - "(" - "Ljava/lang/String;" // iccid - "Ljava/lang/String;" // serviceProviderName - "Ljava/lang/String;" // profileName - "Ljava/lang/String;" // iconType - "Ljava/lang/String;" // icon (base64-encoded) - "L" PROFILE_CLASS_CLASS ";" // profileClass - ")" - "V" // (returns) void - ); - - return (*env)->NewObject( - env, profile_metadata_class, profile_metadata_constructor, - toJString(env, metadata->iccid), - toJString(env, metadata->serviceProviderName), - toJString(env, metadata->profileName), - to_icon_type(env, metadata->iconType), - toJString(env, metadata->icon), - to_profile_class(metadata->profileClass) - ); -} - -jobject to_profile_management_operation(enum es10b_profile_management_operation operation) { - switch (operation) { - case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL: - return profile_management_operation_install; - case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE: - return profile_management_operation_delete; - case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE: - return profile_management_operation_enable; - case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE: - return profile_management_operation_disable; - default: - return NULL; - } -} diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h deleted file mode 100644 index 79cbe8d..0000000 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-convertor.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include - -#define PACKAGE_NAME "net/typeblog/lpac_jni" -#define PROFILE_STATE_CLASS PACKAGE_NAME "/ProfileState" -#define PROFILE_CLASS_CLASS PACKAGE_NAME "/ProfileClass" -#define DOWNLOAD_CALLBACK_CLASS PACKAGE_NAME "/ProfileDownloadCallback" -#define DOWNLOAD_STATE_CLASS DOWNLOAD_CALLBACK_CLASS "$DownloadState" -#define PROFILE_METADATA_CLASS DOWNLOAD_CALLBACK_CLASS "$ProfileMetadata" -#define LOCAL_PROFILE_NOTIFICATION_CLASS PACKAGE_NAME "/LocalProfileNotification" -#define PROFILE_MANAGEMENT_OPERATION_CLASS PACKAGE_NAME "/ProfileManagementOperation" -#define EUICC_CONFIGURED_ADDRESSES_CLASS PACKAGE_NAME "/EuiccConfiguredAddresses" -#define DISCOVERY_CALLBACK_CLASS PACKAGE_NAME "/ProfileDiscoveryCallback" -#define VERSION_CLASS PACKAGE_NAME "/Version" -#define HASH_SET_CLASS "java/util/HashSet" -#define ARRAY_LIST_CLASS "java/util/ArrayList" - -jclass string_class; - -void lpac_convertor_init(JNIEnv *env); - -jstring toJString(JNIEnv *env, const char *pat); - -jobject bind_static_field(JNIEnv *env, jclass clazz, const char *name, const char *sig); - -jobject to_profile_state(enum es10c_profile_state profile_state); - -jobject to_profile_class(enum es10c_profile_class profile_class); - -jobject to_version(JNIEnv *env, const char *version); - -jobject to_string_list(JNIEnv *env, char **values); - -jobject to_string_set(JNIEnv *env, char **values); - -jobject build_profile_metadata(JNIEnv *env, struct es8p_metadata *metadata); - -jobject to_profile_management_operation(enum es10b_profile_management_operation operation); \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c deleted file mode 100644 index 3e9ff69..0000000 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "lpac-convertor.h" -#include "lpac-discovery.h" - -jclass euicc_configured_addresses_class; -jmethodID euicc_configured_addresses_constructor; - -jmethodID on_discovered; - -void lpac_discovery_init(JNIEnv *env) { - jclass download_callback_class = (*env)->FindClass(env, DISCOVERY_CALLBACK_CLASS); - on_discovered = (*env)->GetMethodID(env, download_callback_class, "onDiscovered", - "(Ljava/util/ArrayList;)V"); - - euicc_configured_addresses_class = (*env)->FindClass(env, EUICC_CONFIGURED_ADDRESSES_CLASS); - euicc_configured_addresses_class = (*env)->NewGlobalRef(env, euicc_configured_addresses_class); - euicc_configured_addresses_constructor = (*env)->GetMethodID( - env, euicc_configured_addresses_class, "", - "(Ljava/lang/String;Ljava/lang/String;)V"); -} - -JNIEXPORT jobject JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10aGetEuiccConfiguredAddresses( - JNIEnv *env, - __attribute__((unused)) jobject thiz, - jlong handle -) { - struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10a_euicc_configured_addresses addresses; - jobject ret = NULL; - if (es10a_get_euicc_configured_addresses(ctx, &addresses) < 0) { - goto out; - } - jstring default_dp_address = toJString(env, addresses.defaultDpAddress); - jstring root_ds_address = toJString(env, addresses.rootDsAddress); - ret = (*env)->NewObject(env, euicc_configured_addresses_class, - euicc_configured_addresses_constructor, - default_dp_address, root_ds_address); - out: - es10a_euicc_configured_addresses_free(&addresses); - return ret; -} - -JNIEXPORT jint JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_discoveryProfile( - JNIEnv *env, - __attribute__((unused)) jobject thiz, - jlong handle, - jstring address, - jstring imei, - jobject callback -) { - struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - - const char *_address = (*env)->GetStringUTFChars(env, address, NULL); - const char *_imei = NULL; - - if (imei != NULL) { - _imei = (*env)->GetStringUTFChars(env, address, NULL); - } - - ctx->http.server_address = _address; - - char **smdp_list = NULL; - - int ret; - - ret = es10b_get_euicc_challenge_and_info(ctx); - syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret); - if (ret < 0) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } - - ret = es9p_initiate_authentication(ctx); - syslog(LOG_INFO, "es9p_initiate_authentication %d", ret); - if (ret < 0) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } - - ret = es10b_authenticate_server(ctx, NULL, _imei); - syslog(LOG_INFO, "es10b_authenticate_server %d", ret); - if (ret < 0) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } - - ret = es11_authenticate_client(ctx, &smdp_list); - syslog(LOG_INFO, "es11_authenticate_client %d", ret); - if (ret < 0) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } - - (*env)->CallVoidMethod(env, callback, on_discovered, to_string_list(env, smdp_list)); - - out: - - if (_imei != NULL) (*env)->ReleaseStringUTFChars(env, imei, _imei); - (*env)->ReleaseStringUTFChars(env, address, _address); - es11_smdp_list_free_all(smdp_list); - return ret; -} \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h deleted file mode 100644 index d66e1c2..0000000 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -#include "lpac-jni.h" - -void lpac_discovery_init(JNIEnv *env); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c index e069383..bae2ee8 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c @@ -3,56 +3,72 @@ #include #include #include -#include "lpac-convertor.h" #include "lpac-download.h" -static jobject download_state_preparing; -static jobject download_state_connecting; -static jobject download_state_authenticating; -static jobject download_state_downloading; -static jobject download_state_finalizing; +jobject download_state_preparing; +jobject download_state_connecting; +jobject download_state_authenticating; +jobject download_state_downloading; +jobject download_state_finalizing; -#define BIND_DOWNLOAD_STATE_STATIC_FIELD(NAME, FIELD) \ - download_state_##NAME = bind_static_field(env, download_state_class, FIELD, "L" DOWNLOAD_STATE_CLASS ";") +jmethodID on_state_update; -void lpac_download_init(JNIEnv *env) { - jclass download_state_class = (*env)->FindClass(env, DOWNLOAD_STATE_CLASS); +void lpac_download_init() { + LPAC_JNI_SETUP_ENV; - BIND_DOWNLOAD_STATE_STATIC_FIELD(preparing, "Preparing"); - BIND_DOWNLOAD_STATE_STATIC_FIELD(connecting, "Connecting"); - BIND_DOWNLOAD_STATE_STATIC_FIELD(authenticating, "Authenticating"); - BIND_DOWNLOAD_STATE_STATIC_FIELD(downloading, "Downloading"); - BIND_DOWNLOAD_STATE_STATIC_FIELD(finalizing, "Finalizing"); + jclass download_state_class = (*env)->FindClass(env, + "net/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState"); + jfieldID download_state_preparing_field = (*env)->GetStaticFieldID(env, download_state_class, + "Preparing", + "Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;"); + download_state_preparing = (*env)->GetStaticObjectField(env, download_state_class, + download_state_preparing_field); + download_state_preparing = (*env)->NewGlobalRef(env, download_state_preparing); + jfieldID download_state_connecting_field = (*env)->GetStaticFieldID(env, download_state_class, + "Connecting", + "Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;"); + download_state_connecting = (*env)->GetStaticObjectField(env, download_state_class, + download_state_connecting_field); + download_state_connecting = (*env)->NewGlobalRef(env, download_state_connecting); + jfieldID download_state_authenticating_field = (*env)->GetStaticFieldID(env, + download_state_class, + "Authenticating", + "Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;"); + download_state_authenticating = (*env)->GetStaticObjectField(env, download_state_class, + download_state_authenticating_field); + download_state_authenticating = (*env)->NewGlobalRef(env, download_state_authenticating); + jfieldID download_state_downloading_field = (*env)->GetStaticFieldID(env, download_state_class, + "Downloading", + "Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;"); + download_state_downloading = (*env)->GetStaticObjectField(env, download_state_class, + download_state_downloading_field); + download_state_downloading = (*env)->NewGlobalRef(env, download_state_downloading); + jfieldID download_state_finalizng_field = (*env)->GetStaticFieldID(env, download_state_class, + "Finalizing", + "Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;"); + download_state_finalizing = (*env)->GetStaticObjectField(env, download_state_class, + download_state_finalizng_field); + download_state_finalizing = (*env)->NewGlobalRef(env, download_state_finalizing); + + jclass download_callback_class = (*env)->FindClass(env, + "net/typeblog/lpac_jni/ProfileDownloadCallback"); + on_state_update = (*env)->GetMethodID(env, download_callback_class, "onStateUpdate", + "(Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;)V"); } JNIEXPORT jint JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( - JNIEnv *env, - __attribute__((unused)) jobject thiz, - jlong handle, - jstring smdp, - jstring matching_id, - jstring imei, - jstring confirmation_code, - jobject callback -) { +Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, jlong handle, + jstring smdp, jstring matching_id, + jstring imei, jstring confirmation_code, + jobject callback) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct es10b_load_bound_profile_package_result es10b_load_bound_profile_package_result; - struct es8p_metadata *profile_metadata = NULL; const char *_confirmation_code = NULL; const char *_matching_id = NULL; const char *_smdp = NULL; const char *_imei = NULL; int ret; - jclass callback_class = (*env)->GetObjectClass(env, callback); - jmethodID on_state_update = (*env)->GetMethodID(env, callback_class, "onStateUpdate", "(L" DOWNLOAD_STATE_CLASS ";)V"); - jmethodID on_profile_metadata = (*env)->GetMethodID(env, callback_class, "onProfileMetadata", "(L" PROFILE_METADATA_CLASS ";)V"); - jmethodID is_cancelled = (*env)->GetMethodID(env, callback_class, "isCancelled", "()Z"); - jmethodID set_cancelled = (*env)->GetMethodID(env, callback_class, "setCancelled", "(Z)V"); - -#define IS_CANCELLED (*env)->CallBooleanMethod(env, callback, is_cancelled) - if (confirmation_code != NULL) _confirmation_code = (*env)->GetStringUTFChars(env, confirmation_code, NULL); if (matching_id != NULL) @@ -63,10 +79,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( ctx->http.server_address = _smdp; - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } (*env)->CallVoidMethod(env, callback, on_state_update, download_state_preparing); ret = es10b_get_euicc_challenge_and_info(ctx); syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret); @@ -75,10 +87,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( goto out; } - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } (*env)->CallVoidMethod(env, callback, on_state_update, download_state_connecting); ret = es9p_initiate_authentication(ctx); syslog(LOG_INFO, "es9p_initiate_authentication %d", ret); @@ -87,10 +95,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( goto out; } - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } (*env)->CallVoidMethod(env, callback, on_state_update, download_state_authenticating); ret = es10b_authenticate_server(ctx, _matching_id, _imei); syslog(LOG_INFO, "es10b_authenticate_server %d", ret); @@ -99,31 +103,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( goto out; } - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } ret = es9p_authenticate_client(ctx); if (ret < 0) { ret = -ES10B_ERROR_REASON_UNDEFINED; goto out; } - const char *b64_profileMetadata = ctx->http._internal.prepare_download_param->b64_profileMetadata; - if (b64_profileMetadata != NULL) { - ret = es8p_metadata_parse(&profile_metadata, b64_profileMetadata); - if (ret < 0) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } - (*env)->CallVoidMethod(env, callback, on_profile_metadata, - build_profile_metadata(env, profile_metadata)); - } - - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } (*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading); ret = es10b_prepare_download(ctx, _confirmation_code); syslog(LOG_INFO, "es10b_prepare_download %d", ret); @@ -132,35 +117,21 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( goto out; } - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } ret = es9p_get_bound_profile_package(ctx); if (ret < 0) goto out; - if (IS_CANCELLED) { - ret = -ES10B_ERROR_REASON_UNDEFINED; - goto out; - } (*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing); ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result); - syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, - es10b_load_bound_profile_package_result.errorReason); + syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, es10b_load_bound_profile_package_result.errorReason); if (ret < 0) { - ret = -(int) es10b_load_bound_profile_package_result.errorReason; + ret = - (int) es10b_load_bound_profile_package_result.errorReason; goto out; } euicc_http_cleanup(ctx); out: - if (IS_CANCELLED == 0 && ret == -ES10B_ERROR_REASON_UNDEFINED) { - (*env)->CallVoidMethod(env, callback, set_cancelled, JNI_TRUE); - } - es8p_metadata_free(&profile_metadata); -#undef IS_CANCELLED // We expect Java side to call cancelSessions after any error -- thus, `euicc_http_cleanup` is done there // This is so that Java side can access the last HTTP and/or APDU errors when we return. if (_confirmation_code != NULL) @@ -173,6 +144,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile( return ret; } + JNIEXPORT void JNICALL Java_net_typeblog_lpac_1jni_LpacJni_cancelSessions(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; @@ -195,12 +167,15 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadErrCodeToString(JNIEnv *env, jobject ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_SCP03T_STRUCTURE_ERROR); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_SCP03T_SECURITY_ERROR); - ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC); - ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE); + ERRCODE_ENUM_TO_STRING( + ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC); + ERRCODE_ENUM_TO_STRING( + ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH); - ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_TEST_PROFILE_INSTALL_FAILED_DUE_TO_INVALID_NAA_KEY); + ERRCODE_ENUM_TO_STRING( + ES10B_ERROR_REASON_TEST_PROFILE_INSTALL_FAILED_DUE_TO_INVALID_NAA_KEY); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_PPR_NOT_ALLOWED); ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_UNKNOWN_ERROR); default: diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.h index b68bc99..7130f52 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.h @@ -3,4 +3,4 @@ #include #include "lpac-jni.h" -void lpac_download_init(JNIEnv *env); \ No newline at end of file +void lpac_download_init(); \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index e3dcdaf..ca319db 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -8,33 +8,38 @@ #include "lpac-jni.h" #include "lpac-download.h" #include "lpac-notifications.h" -#include "lpac-discovery.h" -#include "lpac-convertor.h" #include "interface-wrapper.h" JavaVM *jvm = NULL; -#define LOCAL_PROFILE_INFO_CLASS "net/typeblog/lpac_jni/LocalProfileInfo" +jstring empty_string; + +jclass string_class; +jmethodID string_constructor; jint JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; - LPAC_JNI_SETUP_ENV; + interface_wrapper_init(); + lpac_download_init(); - interface_wrapper_init(env); - lpac_convertor_init(env); - lpac_discovery_init(env); - lpac_download_init(env); + LPAC_JNI_SETUP_ENV; + string_class = (*env)->FindClass(env, "java/lang/String"); + string_class = (*env)->NewGlobalRef(env, string_class); + string_constructor = (*env)->GetMethodID(env, string_class, "", + "([BLjava/lang/String;)V"); + + const jchar _unused[1]; + empty_string = (*env)->NewString(env, _unused, 0); + empty_string = (*env)->NewGlobalRef(env, empty_string); return JNI_VERSION_1_6; } JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_createContext( - JNIEnv *env, jobject thiz, - jbyteArray isdr_aid, - jobject apdu_interface, - jobject http_interface -) { +Java_net_typeblog_lpac_1jni_LpacJni_createContext(JNIEnv *env, jobject thiz, + jbyteArray isdr_aid, + jobject apdu_interface, + jobject http_interface) { struct lpac_jni_ctx *jni_ctx = NULL; struct euicc_ctx *ctx = NULL; jbyte *isdr_java = NULL; @@ -91,6 +96,26 @@ Java_net_typeblog_lpac_1jni_LpacJni_euiccSetMss(JNIEnv *env, jobject thiz, jlong ctx->es10x_mss = (uint8_t) mss; } +jstring toJString(JNIEnv *env, const char *pat) { + jbyteArray bytes = NULL; + jstring encoding = NULL; + jstring jstr = NULL; + int len; + + if (pat == NULL) + return (*env)->NewLocalRef(env, empty_string); + + len = strlen(pat); + bytes = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) pat); + encoding = (*env)->NewStringUTF(env, "utf-8"); + jstr = (jstring) (*env)->NewObject(env, string_class, + string_constructor, bytes, encoding); + (*env)->DeleteLocalRef(env, encoding); + (*env)->DeleteLocalRef(env, bytes); + return jstr; +} + JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; @@ -105,56 +130,67 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong } JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo( - JNIEnv *env, - __attribute__((unused)) jobject thiz, - jlong handle, - jobject profiles -) { +Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct es10c_profile_info_list *info = NULL; - int ret = es10c_get_profiles_info(ctx, &info); - if (ret < 0) return ret; - jclass profile_list_class = (*env)->GetObjectClass(env, profiles); - jmethodID add_profile = (*env)->GetMethodID(env, profile_list_class, "add", - "(Ljava/lang/Object;)Z"); - - jclass profile_info_class = (*env)->FindClass(env, LOCAL_PROFILE_INFO_CLASS); - jmethodID profile_info_class_constructor = (*env)->GetMethodID( - env, profile_info_class, "", - "(" - "Ljava/lang/String;" // iccid - "Lnet/typeblog/lpac_jni/ProfileState;" - "Ljava/lang/String;" // name - "Ljava/lang/String;" // nickname - "Ljava/lang/String;" // provider name - "Ljava/lang/String;" // ISD-P AID - "Lnet/typeblog/lpac_jni/ProfileClass;" - ")" - "V" // (returns) void - ); - - jobject element = NULL; - while (info) { - element = (*env)->NewObject( - env, profile_info_class, profile_info_class_constructor, - toJString(env, info->iccid), - to_profile_state(info->profileState), - toJString(env, info->profileName), - toJString(env, info->profileNickname), - toJString(env, info->serviceProviderName), - toJString(env, info->isdpAid), - to_profile_class(info->profileClass) - ); - (*env)->CallBooleanMethod(env, profiles, add_profile, element); - info = info->next; + if (es10c_get_profiles_info(ctx, &info) < 0) { + return 0; } - es10c_profile_info_list_free_all(info); - return ret; + return (jlong) info; } +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_profileGetStateString(JNIEnv *env, jobject thiz, jlong curr) { + struct es10c_profile_info_list *info = (struct es10c_profile_info_list *) curr; + const char *profileStateStr = NULL; + + switch (info->profileState) { + case ES10C_PROFILE_STATE_ENABLED: + profileStateStr = "enabled"; + break; + case ES10C_PROFILE_STATE_DISABLED: + profileStateStr = "disabled"; + break; + default: + profileStateStr = "unknown"; + } + + return toJString(env, profileStateStr); +} + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_profileGetClassString(JNIEnv *env, jobject thiz, jlong curr) { + struct es10c_profile_info_list *info = (struct es10c_profile_info_list *) curr; + const char *profileClassStr = NULL; + + switch (info->profileClass) { + case ES10C_PROFILE_CLASS_TEST: + profileClassStr = "test"; + break; + case ES10C_PROFILE_CLASS_PROVISIONING: + profileClassStr = "provisioning"; + break; + case ES10C_PROFILE_CLASS_OPERATIONAL: + profileClassStr = "operational"; + break; + default: + profileClassStr = "unknown"; + break; + } + + return toJString(env, profileClassStr); +} + +LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10c_profile_info_list, profiles) +LPAC_JNI_STRUCT_FREE(struct es10c_profile_info_list, profiles, es10c_profile_info_list_free_all) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, iccid, Iccid) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, isdpAid, IsdpAid) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileName, Name) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileNickname, Nickname) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, serviceProviderName, ServiceProvider) + JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle, jstring iccid, jboolean refresh) { @@ -210,51 +246,48 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz return ret; } -JNIEXPORT jobject JNICALL +JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct es10c_ex_euiccinfo2 *info = malloc(sizeof(struct es10c_ex_euiccinfo2)); - jobject ret = NULL; - if (es10c_ex_get_euiccinfo2(ctx, info) < 0) goto out; - jclass euicc_info_class = (*env)->FindClass(env, PACKAGE_NAME "/EuiccInfo2"); - jmethodID euicc_info_constructor = (*env)->GetMethodID( - env, euicc_info_class, "", - "(" - "Lnet/typeblog/lpac_jni/Version;" // sgp22 version - "Lnet/typeblog/lpac_jni/Version;" // profile version - "Lnet/typeblog/lpac_jni/Version;" // euicc firmware version - "Lnet/typeblog/lpac_jni/Version;" // global platform version - "Ljava/lang/String;" // sas accreditation number - "Lnet/typeblog/lpac_jni/Version;" // protected profile version - "I" // freeNvram - "I" // freeRam - "Ljava/util/Set;" // euicc ci public id list (for signing) - "Ljava/util/Set;" // euicc ci public id list (for verification) - ")" - "V" // (returns) void - ); - ret = (*env)->NewObject( - env, euicc_info_class, euicc_info_constructor, - to_version(env, info->svn), - to_version(env, info->profileVersion), - to_version(env, info->euiccFirmwareVer), - to_version(env, info->globalplatformVersion), - toJString(env, info->sasAcreditationNumber), - to_version(env, info->ppVersion), - (jint) info->extCardResource.freeNonVolatileMemory, - (jint) info->extCardResource.freeVolatileMemory, - to_string_set(env, info->euiccCiPKIdListForSigning), - to_string_set(env, info->euiccCiPKIdListForVerification) - ); + if (es10c_ex_get_euiccinfo2(ctx, info) < 0) { + free(info); + return 0; + } - out: - es10c_ex_euiccinfo2_free(info); - return ret; + return (jlong) info; } + JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEuiccMemoryReset(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - return es10c_euicc_memory_reset(ctx); + int ret; + ret = es10c_euicc_memory_reset(ctx); + return ret; } + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_stringDeref(JNIEnv *env, jobject thiz, jlong curr) { + return toJString(env, *((char **) curr)); +} + +void lpac_jni_euiccinfo2_free(struct es10c_ex_euiccinfo2 *info) { + es10c_ex_euiccinfo2_free(info); + free(info); +} + +LPAC_JNI_STRUCT_GETTER_NULL_TERM_LIST_NEXT(char*, stringArr) +LPAC_JNI_STRUCT_FREE(struct es10c_ex_euiccinfo2, euiccInfo2, lpac_jni_euiccinfo2_free) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, svn, SGP22Version) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, profileVersion, ProfileVersion) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, euiccFirmwareVer, EuiccFirmwareVersion) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, globalplatformVersion, GlobalPlatformVersion) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, sasAcreditationNumber, SasAcreditationNumber) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, ppVersion, PpVersion) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, extCardResource.freeNonVolatileMemory, FreeNonVolatileMemory) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, extCardResource.freeVolatileMemory, FreeVolatileMemory) + +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForSigning, EuiccCiPKIdListForSigning) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForVerification, EuiccCiPKIdListForVerification) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index e062344..c2300be 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -19,4 +19,41 @@ struct lpac_jni_ctx { (*jvm)->AttachCurrentThread(jvm, &env, NULL) extern JavaVM *jvm; +extern jclass string_class; +jstring toJString(JNIEnv *env, const char *pat); + +#define LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(st, st_jname) \ + JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Next(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + if (p == NULL) return 0; \ + return (jlong) p->next; \ + } + +#define LPAC_JNI_STRUCT_GETTER_NULL_TERM_LIST_NEXT(st, st_jname) \ + JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Next(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + p++; \ + if (*p == NULL) return 0; \ + return (jlong) p; \ + } + +#define LPAC_JNI_STRUCT_FREE(st, st_jname, free_func) \ + JNIEXPORT void JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Free(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + if (p == NULL) return; \ + free_func(p); \ + } + +#define LPAC_JNI_STRUCT_GETTER_LONG(st, st_name, name, jname) \ + JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_name##Get##jname(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + if (p == NULL) return 0; \ + return (jlong) p->name; \ + } + +#define LPAC_JNI_STRUCT_GETTER_STRING(st, st_name, name, jname) \ + JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_name##Get##jname(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + return toJString(env, p->name); \ + } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index 4d4c293..cf402cf 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -1,56 +1,18 @@ +#include "lpac-notifications.h" #include #include #include #include -#include "lpac-convertor.h" -#include "lpac-notifications.h" -JNIEXPORT jint JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification( - JNIEnv *env, - jobject thiz, - jlong handle, - jobject notifications -) { +JNIEXPORT jlong JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10b_notification_metadata_list *metadata = NULL; - int ret = es10b_list_notification(ctx, &metadata); - if (ret < 0) goto out; + struct es10b_notification_metadata_list *info = NULL; - jclass local_profile_notification_class = (*env)->FindClass( - env, LOCAL_PROFILE_NOTIFICATION_CLASS); - jmethodID local_profile_notification_constructor = (*env)->GetMethodID( - env, local_profile_notification_class, "", - "(" - "J" // seqNumber - "L" PROFILE_MANAGEMENT_OPERATION_CLASS ";" - "Ljava/lang/String;" // notificationAddress - "Ljava/lang/String;" // iccid - ")" - "V" // (returns) void - ); - jmethodID add_notification = (*env)->GetMethodID( - env, - (*env)->GetObjectClass(env, notifications), - "add", "(Ljava/lang/Object;)Z" - ); + if (es10b_list_notification(ctx, &info) < 0) + return 0; - jobject element; - while (metadata) { - jlong sequence_number = metadata->seqNumber; - jobject operation = to_profile_management_operation(metadata->profileManagementOperation); - jstring address = toJString(env, metadata->notificationAddress); - jstring iccid = toJString(env, metadata->iccid); - element = (*env)->NewObject( - env, local_profile_notification_class, local_profile_notification_constructor, - sequence_number, operation, address, iccid); - (*env)->CallBooleanMethod(env, notifications, add_notification, element); - metadata = metadata->next; - } - - out: - es10b_notification_metadata_list_free_all(metadata); - return ret; + return (jlong) info; } JNIEXPORT jint JNICALL @@ -83,3 +45,35 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject struct euicc_ctx *ctx = (struct euicc_ctx *) handle; return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); } + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, jobject thiz, + jlong curr) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; + const char *profileManagementOperationStr = NULL; + switch (info->profileManagementOperation) { + case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL: + profileManagementOperationStr = "install"; + break; + case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE: + profileManagementOperationStr = "delete"; + break; + case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE: + profileManagementOperationStr = "enable"; + break; + case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE: + profileManagementOperationStr = "disable"; + break; + default: + profileManagementOperationStr = "unknown"; + break; + } + + return toJString(env, profileManagementOperationStr); +} + +LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications) +LPAC_JNI_STRUCT_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10b_notification_metadata_list, notification, seqNumber, Seq) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, notificationAddress, Address) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, iccid, Iccid)