refactor: lpac-jni bridge #174
29 changed files with 921 additions and 612 deletions
|
@ -1,9 +1,11 @@
|
||||||
package im.angry.openeuicc.core
|
package im.angry.openeuicc.core
|
||||||
|
|
||||||
|
import net.typeblog.lpac_jni.EuiccConfiguredAddresses
|
||||||
import net.typeblog.lpac_jni.EuiccInfo2
|
import net.typeblog.lpac_jni.EuiccInfo2
|
||||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||||
|
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||||
|
|
||||||
class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
||||||
|
@ -29,6 +31,8 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
||||||
get() = lpa.eID
|
get() = lpa.eID
|
||||||
override val euiccInfo2: EuiccInfo2?
|
override val euiccInfo2: EuiccInfo2?
|
||||||
get() = lpa.euiccInfo2
|
get() = lpa.euiccInfo2
|
||||||
|
override val euiccConfiguredAddresses: EuiccConfiguredAddresses
|
||||||
|
get() = lpa.euiccConfiguredAddresses
|
||||||
|
|
||||||
override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss)
|
override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss)
|
||||||
|
|
||||||
|
@ -48,6 +52,9 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
|
||||||
callback: ProfileDownloadCallback
|
callback: ProfileDownloadCallback
|
||||||
) = lpa.downloadProfile(smdp, matchingId, imei, confirmationCode, callback)
|
) = 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 deleteNotification(seqNumber: Long): Boolean = lpa.deleteNotification(seqNumber)
|
||||||
|
|
||||||
override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber)
|
override fun handleNotification(seqNumber: Long): Boolean = lpa.handleNotification(seqNumber)
|
||||||
|
|
|
@ -36,6 +36,7 @@ import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||||
|
import net.typeblog.lpac_jni.ProfileMetadata
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Android Service wrapper for EuiccChannelManager.
|
* An Android Service wrapper for EuiccChannelManager.
|
||||||
|
@ -380,6 +381,18 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
|
||||||
getString(R.string.task_profile_download_failure),
|
getString(R.string.task_profile_download_failure),
|
||||||
R.drawable.ic_task_sim_card_download
|
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: ProfileMetadata) {
|
||||||
|
Log.d(TAG, "Downloaded profile metadata: $metadata")
|
||||||
|
}
|
||||||
|
}
|
||||||
euiccChannelManager.beginTrackedOperation(slotId, portId) {
|
euiccChannelManager.beginTrackedOperation(slotId, portId) {
|
||||||
euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
|
euiccChannelManager.withEuiccChannel(slotId, portId) { channel ->
|
||||||
channel.lpa.downloadProfile(
|
channel.lpa.downloadProfile(
|
||||||
|
@ -387,13 +400,8 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
|
||||||
matchingId,
|
matchingId,
|
||||||
imei,
|
imei,
|
||||||
confirmationCode,
|
confirmationCode,
|
||||||
object : ProfileDownloadCallback {
|
callback
|
||||||
override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
|
)
|
||||||
if (state.progress == 0) return
|
|
||||||
foregroundTaskState.value =
|
|
||||||
ForegroundTaskState.InProgress(state.progress)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceRepository.notificationDownloadFlow.first()
|
preferenceRepository.notificationDownloadFlow.first()
|
||||||
|
|
|
@ -43,6 +43,7 @@ import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import net.typeblog.lpac_jni.ProfileClass
|
||||||
|
|
||||||
open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
|
open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
|
||||||
EuiccChannelFragmentMarker {
|
EuiccChannelFragmentMarker {
|
||||||
|
@ -387,9 +388,10 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
|
||||||
profileClass.isVisible = unfilteredProfileListFlow.value
|
profileClass.isVisible = unfilteredProfileListFlow.value
|
||||||
profileClass.setText(
|
profileClass.setText(
|
||||||
when (profile.profileClass) {
|
when (profile.profileClass) {
|
||||||
LocalProfileInfo.Clazz.Testing -> R.string.profile_class_testing
|
ProfileClass.Testing -> R.string.profile_class_testing
|
||||||
LocalProfileInfo.Clazz.Provisioning -> R.string.profile_class_provisioning
|
ProfileClass.Provisioning -> R.string.profile_class_provisioning
|
||||||
LocalProfileInfo.Clazz.Operational -> R.string.profile_class_operational
|
ProfileClass.Operational -> R.string.profile_class_operational
|
||||||
|
else -> throw IllegalStateException("profile class should not be null")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
iccid.text = profile.iccid
|
iccid.text = profile.iccid
|
||||||
|
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||||
|
import net.typeblog.lpac_jni.ProfileManagementOperation
|
||||||
|
|
||||||
class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
private lateinit var swipeRefresh: SwipeRefreshLayout
|
private lateinit var swipeRefresh: SwipeRefreshLayout
|
||||||
|
@ -163,13 +164,13 @@ class NotificationsActivity: BaseEuiccAccessActivity(), OpenEuiccContextMarker {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun operationToLocalizedText(operation: LocalProfileNotification.Operation) =
|
private fun operationToLocalizedText(operation: ProfileManagementOperation?) =
|
||||||
root.context.getText(
|
root.context.getString(when (operation) {
|
||||||
when (operation) {
|
ProfileManagementOperation.Install -> R.string.profile_notification_operation_download
|
||||||
LocalProfileNotification.Operation.Install -> R.string.profile_notification_operation_download
|
ProfileManagementOperation.Delete -> R.string.profile_notification_operation_delete
|
||||||
LocalProfileNotification.Operation.Delete -> R.string.profile_notification_operation_delete
|
ProfileManagementOperation.Enable -> R.string.profile_notification_operation_enable
|
||||||
LocalProfileNotification.Operation.Enable -> R.string.profile_notification_operation_enable
|
ProfileManagementOperation.Disable -> R.string.profile_notification_operation_disable
|
||||||
LocalProfileNotification.Operation.Disable -> R.string.profile_notification_operation_disable
|
else -> throw IllegalStateException("Unknown operation: $operation")
|
||||||
})
|
})
|
||||||
|
|
||||||
fun updateNotification(value: LocalProfileNotificationWrapper) {
|
fun updateNotification(value: LocalProfileNotificationWrapper) {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import im.angry.openeuicc.core.EuiccChannel
|
||||||
import im.angry.openeuicc.core.EuiccChannelManager
|
import im.angry.openeuicc.core.EuiccChannelManager
|
||||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
|
import net.typeblog.lpac_jni.ProfileClass
|
||||||
|
import net.typeblog.lpac_jni.ProfileState
|
||||||
|
|
||||||
const val TAG = "LPAUtils"
|
const val TAG = "LPAUtils"
|
||||||
|
|
||||||
|
@ -13,10 +15,10 @@ val LocalProfileInfo.displayName: String
|
||||||
|
|
||||||
|
|
||||||
val LocalProfileInfo.isEnabled: Boolean
|
val LocalProfileInfo.isEnabled: Boolean
|
||||||
get() = state == LocalProfileInfo.State.Enabled
|
get() = state == ProfileState.Enabled
|
||||||
|
|
||||||
val List<LocalProfileInfo>.operational: List<LocalProfileInfo>
|
val List<LocalProfileInfo>.operational: List<LocalProfileInfo>
|
||||||
get() = filter { it.profileClass == LocalProfileInfo.Clazz.Operational }
|
get() = filter { it.profileClass == ProfileClass.Operational }
|
||||||
|
|
||||||
val List<LocalProfileInfo>.enabled: LocalProfileInfo?
|
val List<LocalProfileInfo>.enabled: LocalProfileInfo?
|
||||||
get() = find { it.isEnabled }
|
get() = find { it.isEnabled }
|
||||||
|
|
|
@ -15,6 +15,8 @@ import im.angry.openeuicc.util.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import net.typeblog.lpac_jni.ProfileClass
|
||||||
|
import net.typeblog.lpac_jni.ProfileState
|
||||||
import kotlin.IllegalStateException
|
import kotlin.IllegalStateException
|
||||||
|
|
||||||
class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
||||||
|
@ -200,15 +202,15 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
||||||
setServiceProviderName(it.providerName)
|
setServiceProviderName(it.providerName)
|
||||||
setState(
|
setState(
|
||||||
when (it.state) {
|
when (it.state) {
|
||||||
LocalProfileInfo.State.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED
|
ProfileState.Enabled -> EuiccProfileInfo.PROFILE_STATE_ENABLED
|
||||||
LocalProfileInfo.State.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED
|
ProfileState.Disabled -> EuiccProfileInfo.PROFILE_STATE_DISABLED
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
setProfileClass(
|
setProfileClass(
|
||||||
when (it.profileClass) {
|
when (it.profileClass) {
|
||||||
LocalProfileInfo.Clazz.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING
|
ProfileClass.Testing -> EuiccProfileInfo.PROFILE_CLASS_TESTING
|
||||||
LocalProfileInfo.Clazz.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING
|
ProfileClass.Provisioning -> EuiccProfileInfo.PROFILE_CLASS_PROVISIONING
|
||||||
LocalProfileInfo.Clazz.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL
|
ProfileClass.Operational -> EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}.build()
|
}.build()
|
||||||
|
|
|
@ -17,10 +17,10 @@ interface ApduInterface {
|
||||||
*/
|
*/
|
||||||
val valid: Boolean
|
val valid: Boolean
|
||||||
|
|
||||||
fun <T> withLogicalChannel(aid: ByteArray, cb: ((ByteArray) -> ByteArray) -> T): T {
|
fun <T> withLogicalChannel(aid: ByteArray, callback: ((ByteArray) -> ByteArray) -> T): T {
|
||||||
val handle = logicalChannelOpen(aid)
|
val handle = logicalChannelOpen(aid)
|
||||||
return try {
|
return try {
|
||||||
cb { transmit(handle, it) }
|
callback { transmit(handle, it) }
|
||||||
} finally {
|
} finally {
|
||||||
logicalChannelClose(handle)
|
logicalChannelClose(handle)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.typeblog.lpac_jni
|
||||||
|
|
||||||
|
import android.util.Patterns
|
||||||
|
|
||||||
|
data class EuiccConfiguredAddresses(
|
||||||
|
val defaultDPAddress: String,
|
||||||
|
val rootDSAddress: String
|
||||||
|
) {
|
||||||
|
val isValidDefaultDPAddress: Boolean
|
||||||
|
get() = isValid(defaultDPAddress)
|
||||||
|
|
||||||
|
val isValidRootDSAddress: Boolean
|
||||||
|
get() = isValid(rootDSAddress) || rootDSAddress == "lpa.ds.gsma.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isValid(address: String): Boolean {
|
||||||
|
if (address.isBlank()) return false
|
||||||
|
if (address.endsWith(".gsma.com")) return false
|
||||||
|
if (address.endsWith(".example.com")) return false
|
||||||
|
return Patterns.DOMAIN_NAME.matcher(address).matches()
|
||||||
|
}
|
|
@ -1,32 +1,13 @@
|
||||||
package net.typeblog.lpac_jni
|
package net.typeblog.lpac_jni
|
||||||
|
|
||||||
import javax.net.ssl.TrustManager
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Should reflect euicc_http_interface in lpac/euicc/interface.h
|
* Should reflect euicc_http_interface in lpac/euicc/interface.h
|
||||||
*/
|
*/
|
||||||
interface HttpInterface {
|
interface HttpInterface {
|
||||||
data class HttpResponse(val rcode: Int, val data: ByteArray) {
|
@Suppress("ArrayInDataClass")
|
||||||
override fun equals(other: Any?): Boolean {
|
data class HttpResponse(val rcode: Int, val data: ByteArray)
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as HttpResponse
|
fun transmit(url: String, tx: ByteArray, headers: List<String>): HttpResponse
|
||||||
|
|
||||||
if (rcode != other.rcode) return false
|
|
||||||
if (!data.contentEquals(other.data)) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = rcode
|
|
||||||
result = 31 * result + data.contentHashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
// The LPA is supposed to pass in a list of pkIds supported by the eUICC.
|
||||||
// HttpInterface is responsible for providing TrustManager implementations that
|
// HttpInterface is responsible for providing TrustManager implementations that
|
||||||
// validate based on certificates corresponding to these pkIds
|
// validate based on certificates corresponding to these pkIds
|
||||||
|
|
|
@ -12,9 +12,18 @@ interface LocalProfileAssistant {
|
||||||
val lastApduException: Exception?,
|
val lastApduException: Exception?,
|
||||||
) : Exception("Failed to download profile")
|
) : Exception("Failed to download profile")
|
||||||
|
|
||||||
class ProfileRenameException() : Exception("Failed to rename profile")
|
@Suppress("ArrayInDataClass")
|
||||||
class ProfileNameTooLongException() : Exception("Profile name too long")
|
data class ProfileDiscoveryException(
|
||||||
class ProfileNameIsInvalidUTF8Exception() : Exception("Profile name is invalid UTF-8")
|
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")
|
||||||
|
|
||||||
val valid: Boolean
|
val valid: Boolean
|
||||||
val profiles: List<LocalProfileInfo>
|
val profiles: List<LocalProfileInfo>
|
||||||
|
@ -22,6 +31,7 @@ interface LocalProfileAssistant {
|
||||||
val eID: String
|
val eID: String
|
||||||
// Extended EuiccInfo for use with LUIs, containing information such as firmware version
|
// Extended EuiccInfo for use with LUIs, containing information such as firmware version
|
||||||
val euiccInfo2: EuiccInfo2?
|
val euiccInfo2: EuiccInfo2?
|
||||||
|
val euiccConfiguredAddresses: EuiccConfiguredAddresses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the max segment size (mss) for all es10x commands. This can help with removable
|
* Set the max segment size (mss) for all es10x commands. This can help with removable
|
||||||
|
@ -39,6 +49,8 @@ interface LocalProfileAssistant {
|
||||||
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
fun downloadProfile(smdp: String, matchingId: String?, imei: String?,
|
||||||
confirmationCode: String?, callback: ProfileDownloadCallback)
|
confirmationCode: String?, callback: ProfileDownloadCallback)
|
||||||
|
|
||||||
|
fun discoveryProfile(smds: String, imei: String?, callback: ProfileDiscoveryCallback)
|
||||||
|
|
||||||
fun deleteNotification(seqNumber: Long): Boolean
|
fun deleteNotification(seqNumber: Long): Boolean
|
||||||
fun handleNotification(seqNumber: Long): Boolean
|
fun handleNotification(seqNumber: Long): Boolean
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,28 @@
|
||||||
package net.typeblog.lpac_jni
|
package net.typeblog.lpac_jni
|
||||||
|
|
||||||
|
data class ProfileMetadata(
|
||||||
|
val iccid: String,
|
||||||
|
val name: String,
|
||||||
|
val providerName: String,
|
||||||
|
val profileClass: ProfileClass?,
|
||||||
|
val iconType: IconType?,
|
||||||
|
val icon: String,
|
||||||
|
)
|
||||||
|
|
||||||
data class LocalProfileInfo(
|
data class LocalProfileInfo(
|
||||||
val iccid: String,
|
val iccid: String,
|
||||||
val state: State,
|
val state: ProfileState?,
|
||||||
val name: String,
|
val name: String,
|
||||||
val nickName: String,
|
val nickName: String,
|
||||||
val providerName: String,
|
val providerName: String,
|
||||||
val isdpAID: String,
|
val isdpAID: String,
|
||||||
val profileClass: Clazz
|
val profileClass: ProfileClass?,
|
||||||
) {
|
val iconType: IconType?,
|
||||||
enum class State {
|
val icon: String,
|
||||||
Enabled,
|
)
|
||||||
Disabled;
|
|
||||||
|
|
||||||
companion object {
|
enum class ProfileState { Enabled, Disabled }
|
||||||
@JvmStatic
|
|
||||||
fun fromString(str: String?) =
|
|
||||||
when (str?.lowercase()) {
|
|
||||||
"enabled" -> Enabled
|
|
||||||
"disabled" -> Disabled
|
|
||||||
else -> Disabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Clazz {
|
enum class ProfileClass { Testing, Provisioning, Operational }
|
||||||
Testing,
|
|
||||||
Provisioning,
|
|
||||||
Operational;
|
|
||||||
|
|
||||||
companion object {
|
enum class IconType { JPEG, PNG }
|
||||||
@JvmStatic
|
|
||||||
fun fromString(str: String?) =
|
|
||||||
when (str?.lowercase()) {
|
|
||||||
"test" -> Testing
|
|
||||||
"provisioning" -> Provisioning
|
|
||||||
"operational" -> Operational
|
|
||||||
else -> Operational
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,26 +2,11 @@ package net.typeblog.lpac_jni
|
||||||
|
|
||||||
data class LocalProfileNotification(
|
data class LocalProfileNotification(
|
||||||
val seqNumber: Long,
|
val seqNumber: Long,
|
||||||
val profileManagementOperation: Operation,
|
val profileManagementOperation: ProfileManagementOperation?,
|
||||||
val notificationAddress: String,
|
val notificationAddress: String,
|
||||||
val iccid: String,
|
val iccid: String,
|
||||||
) {
|
)
|
||||||
enum class Operation {
|
|
||||||
Install,
|
|
||||||
Enable,
|
|
||||||
Disable,
|
|
||||||
Delete;
|
|
||||||
|
|
||||||
companion object {
|
enum class ProfileManagementOperation {
|
||||||
@JvmStatic
|
Install, Enable, Disable, Delete
|
||||||
fun fromString(str: String?) =
|
|
||||||
when (str?.lowercase()) {
|
|
||||||
"install" -> Install
|
|
||||||
"enable" -> Enable
|
|
||||||
"disable" -> Disable
|
|
||||||
"delete" -> Delete
|
|
||||||
else -> throw IllegalArgumentException("Unknown operation $str")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -19,16 +19,22 @@ internal object LpacJni {
|
||||||
// es10c
|
// es10c
|
||||||
// null returns signify errors
|
// null returns signify errors
|
||||||
external fun es10cGetEid(handle: Long): String?
|
external fun es10cGetEid(handle: Long): String?
|
||||||
external fun es10cGetProfilesInfo(handle: Long): Long
|
external fun es10cGetProfilesInfo(handle: Long): List<LocalProfileInfo>
|
||||||
external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int
|
external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int
|
||||||
external fun es10cDisableProfile(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 es10cDeleteProfile(handle: Long, iccid: String): Int
|
||||||
external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int
|
external fun es10cSetNickname(handle: Long, iccid: String, nickNullTerminated: ByteArray): Int
|
||||||
|
|
||||||
// es10b
|
// es10b
|
||||||
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 es10bListNotification(handle: Long): List<LocalProfileNotification>
|
||||||
external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int
|
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
|
// es9p + es10b
|
||||||
// We do not expose all of the functions because of tediousness :)
|
// We do not expose all of the functions because of tediousness :)
|
||||||
external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?,
|
external fun downloadProfile(handle: Long, smdp: String, matchingId: String?, imei: String?,
|
||||||
|
@ -41,40 +47,5 @@ internal object LpacJni {
|
||||||
// ES10c
|
// ES10c
|
||||||
external fun es10cEuiccMemoryReset(handle: Long): Int
|
external fun es10cEuiccMemoryReset(handle: Long): Int
|
||||||
// es10cex (actually part of es10b)
|
// es10cex (actually part of es10b)
|
||||||
external fun es10cexGetEuiccInfo2(handle: Long): Long
|
external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2?
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package net.typeblog.lpac_jni
|
||||||
|
|
||||||
|
interface ProfileDiscoveryCallback {
|
||||||
|
fun onDiscovered(servers: List<String>)
|
||||||
|
}
|
|
@ -2,8 +2,7 @@ package net.typeblog.lpac_jni
|
||||||
|
|
||||||
interface ProfileDownloadCallback {
|
interface ProfileDownloadCallback {
|
||||||
companion object {
|
companion object {
|
||||||
fun lookupStateFromProgress(progress: Int): DownloadState =
|
fun lookupStateFromProgress(progress: Int): DownloadState = when (progress) {
|
||||||
when (progress) {
|
|
||||||
0 -> DownloadState.Preparing
|
0 -> DownloadState.Preparing
|
||||||
20 -> DownloadState.Connecting
|
20 -> DownloadState.Connecting
|
||||||
40 -> DownloadState.Authenticating
|
40 -> DownloadState.Authenticating
|
||||||
|
@ -21,5 +20,9 @@ interface ProfileDownloadCallback {
|
||||||
Finalizing(80), // load bpp
|
Finalizing(80), // load bpp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isCancelled: Boolean
|
||||||
|
|
||||||
fun onStateUpdate(state: DownloadState)
|
fun onStateUpdate(state: DownloadState)
|
||||||
|
|
||||||
|
fun onProfileMetadata(metadata: ProfileMetadata)
|
||||||
}
|
}
|
|
@ -4,19 +4,11 @@ import android.annotation.SuppressLint
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
@SuppressLint("CustomX509TrustManager")
|
@SuppressLint("CustomX509TrustManager,TrustAllX509TrustManager")
|
||||||
class AllowAllTrustManager : X509TrustManager {
|
class AllowAllTrustManager : X509TrustManager {
|
||||||
@SuppressLint("TrustAllX509TrustManager")
|
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
|
||||||
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("TrustAllX509TrustManager")
|
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
|
||||||
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAcceptedIssuers(): Array<X509Certificate> {
|
override fun getAcceptedIssuers() = emptyArray<X509Certificate>()
|
||||||
return emptyArray()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ class HttpInterfaceImpl(
|
||||||
override fun transmit(
|
override fun transmit(
|
||||||
url: String,
|
url: String,
|
||||||
tx: ByteArray,
|
tx: ByteArray,
|
||||||
headers: Array<String>
|
headers: List<String>
|
||||||
): HttpInterface.HttpResponse {
|
): HttpInterface.HttpResponse {
|
||||||
Log.d(TAG, "transmit(url = $url)")
|
Log.d(TAG, "transmit(url = $url)")
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class HttpInterfaceImpl(
|
||||||
if (runBlocking { ignoreTLSCertificateFlow.first() }) {
|
if (runBlocking { ignoreTLSCertificateFlow.first() }) {
|
||||||
arrayOf(AllowAllTrustManager())
|
arrayOf(AllowAllTrustManager())
|
||||||
} else {
|
} else {
|
||||||
this.trustManagers
|
trustManagers
|
||||||
}
|
}
|
||||||
val sslContext = SSLContext.getInstance("TLS")
|
val sslContext = SSLContext.getInstance("TLS")
|
||||||
sslContext.init(null, trustManagers, SecureRandom())
|
sslContext.init(null, trustManagers, SecureRandom())
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package net.typeblog.lpac_jni.impl
|
package net.typeblog.lpac_jni.impl
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import net.typeblog.lpac_jni.LpacJni
|
|
||||||
import net.typeblog.lpac_jni.ApduInterface
|
import net.typeblog.lpac_jni.ApduInterface
|
||||||
|
import net.typeblog.lpac_jni.EuiccConfiguredAddresses
|
||||||
import net.typeblog.lpac_jni.EuiccInfo2
|
import net.typeblog.lpac_jni.EuiccInfo2
|
||||||
import net.typeblog.lpac_jni.HttpInterface
|
import net.typeblog.lpac_jni.HttpInterface
|
||||||
import net.typeblog.lpac_jni.HttpInterface.HttpResponse
|
import net.typeblog.lpac_jni.HttpInterface.HttpResponse
|
||||||
import net.typeblog.lpac_jni.LocalProfileAssistant
|
import net.typeblog.lpac_jni.LocalProfileAssistant
|
||||||
import net.typeblog.lpac_jni.LocalProfileInfo
|
import net.typeblog.lpac_jni.LocalProfileInfo
|
||||||
import net.typeblog.lpac_jni.LocalProfileNotification
|
import net.typeblog.lpac_jni.LocalProfileNotification
|
||||||
|
import net.typeblog.lpac_jni.LpacJni
|
||||||
|
import net.typeblog.lpac_jni.ProfileDiscoveryCallback
|
||||||
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
import net.typeblog.lpac_jni.ProfileDownloadCallback
|
||||||
import net.typeblog.lpac_jni.Version
|
|
||||||
|
|
||||||
class LocalProfileAssistantImpl(
|
class LocalProfileAssistantImpl(
|
||||||
isdrAid: ByteArray,
|
isdrAid: ByteArray,
|
||||||
|
@ -61,7 +62,7 @@ class LocalProfileAssistantImpl(
|
||||||
*/
|
*/
|
||||||
var lastHttpException: Exception? = null
|
var lastHttpException: Exception? = null
|
||||||
|
|
||||||
override fun transmit(url: String, tx: ByteArray, headers: Array<String>): HttpResponse =
|
override fun transmit(url: String, tx: ByteArray, headers: List<String>): HttpResponse =
|
||||||
try {
|
try {
|
||||||
httpInterface.transmit(url, tx, headers).also {
|
httpInterface.transmit(url, tx, headers).also {
|
||||||
lastHttpException = null
|
lastHttpException = null
|
||||||
|
@ -106,47 +107,11 @@ class LocalProfileAssistantImpl(
|
||||||
|
|
||||||
override val profiles: List<LocalProfileInfo>
|
override val profiles: List<LocalProfileInfo>
|
||||||
@Synchronized
|
@Synchronized
|
||||||
get() {
|
get() = LpacJni.es10cGetProfilesInfo(contextHandle)
|
||||||
val head = LpacJni.es10cGetProfilesInfo(contextHandle)
|
|
||||||
var curr = head
|
|
||||||
val ret = mutableListOf<LocalProfileInfo>()
|
|
||||||
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<LocalProfileNotification>
|
override val notifications: List<LocalProfileNotification>
|
||||||
@Synchronized
|
@Synchronized
|
||||||
get() {
|
get() = LpacJni.es10bListNotification(contextHandle).sortedBy { it.seqNumber }.reversed()
|
||||||
val head = LpacJni.es10bListNotification(contextHandle)
|
|
||||||
var curr = head
|
|
||||||
val ret = mutableListOf<LocalProfileNotification>()
|
|
||||||
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
|
override val eID: String
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -154,39 +119,9 @@ class LocalProfileAssistantImpl(
|
||||||
|
|
||||||
override val euiccInfo2: EuiccInfo2?
|
override val euiccInfo2: EuiccInfo2?
|
||||||
@Synchronized
|
@Synchronized
|
||||||
get() {
|
get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
||||||
val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle)
|
override val euiccConfiguredAddresses: EuiccConfiguredAddresses
|
||||||
if (cInfo == 0L) return null
|
get() = LpacJni.es10aGetEuiccConfiguredAddresses(contextHandle)
|
||||||
|
|
||||||
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
|
@Synchronized
|
||||||
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
|
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
|
||||||
|
@ -212,7 +147,7 @@ class LocalProfileAssistantImpl(
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
|
|
||||||
if (res != 0) {
|
if (res == 0) return
|
||||||
// Construct the error now to store any error information we _can_ access
|
// Construct the error now to store any error information we _can_ access
|
||||||
val err = LocalProfileAssistant.ProfileDownloadException(
|
val err = LocalProfileAssistant.ProfileDownloadException(
|
||||||
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
lpaErrorReason = LpacJni.downloadErrCodeToString(-res),
|
||||||
|
@ -221,12 +156,22 @@ class LocalProfileAssistantImpl(
|
||||||
apduInterface.lastApduResponse,
|
apduInterface.lastApduResponse,
|
||||||
apduInterface.lastApduException,
|
apduInterface.lastApduException,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces.
|
// Cancel sessions if possible. This will overwrite recorded errors from HTTP and APDU interfaces.
|
||||||
LpacJni.cancelSessions(contextHandle)
|
LpacJni.cancelSessions(contextHandle)
|
||||||
|
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|
|
@ -1,34 +1,43 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include "interface-wrapper.h"
|
#include "interface-wrapper.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
jmethodID method_apdu_connect;
|
static jmethodID method_apdu_connect;
|
||||||
jmethodID method_apdu_disconnect;
|
static jmethodID method_apdu_disconnect;
|
||||||
jmethodID method_apdu_logical_channel_open;
|
static jmethodID method_apdu_logical_channel_open;
|
||||||
jmethodID method_apdu_logical_channel_close;
|
static jmethodID method_apdu_logical_channel_close;
|
||||||
jmethodID method_apdu_transmit;
|
static jmethodID method_apdu_transmit;
|
||||||
|
|
||||||
jmethodID method_http_transmit;
|
static jmethodID method_http_transmit;
|
||||||
|
|
||||||
jfieldID field_resp_rcode;
|
static jfieldID field_resp_rcode;
|
||||||
jfieldID field_resp_data;
|
static jfieldID field_resp_data;
|
||||||
|
|
||||||
void interface_wrapper_init() {
|
#define APDU_INTERFACE_CLASS PACKAGE_NAME "/ApduInterface"
|
||||||
LPAC_JNI_SETUP_ENV;
|
#define HTTP_INTERFACE_CLASS PACKAGE_NAME "/HttpInterface"
|
||||||
jclass apdu_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/ApduInterface");
|
#define HTTP_RESPONSE_CLASS HTTP_INTERFACE_CLASS "$HttpResponse"
|
||||||
|
|
||||||
|
void interface_wrapper_init(JNIEnv *env) {
|
||||||
|
jclass apdu_class = (*env)->FindClass(env, APDU_INTERFACE_CLASS);
|
||||||
method_apdu_connect = (*env)->GetMethodID(env, apdu_class, "connect", "()V");
|
method_apdu_connect = (*env)->GetMethodID(env, apdu_class, "connect", "()V");
|
||||||
method_apdu_disconnect = (*env)->GetMethodID(env, apdu_class, "disconnect", "()V");
|
method_apdu_disconnect = (*env)->GetMethodID(env, apdu_class, "disconnect", "()V");
|
||||||
method_apdu_logical_channel_open = (*env)->GetMethodID(env, apdu_class, "logicalChannelOpen",
|
method_apdu_logical_channel_open = (*env)->GetMethodID(env, apdu_class, "logicalChannelOpen", "([B)I");
|
||||||
"([B)I");
|
method_apdu_logical_channel_close = (*env)->GetMethodID(env, apdu_class, "logicalChannelClose", "(I)V");
|
||||||
method_apdu_logical_channel_close = (*env)->GetMethodID(env, apdu_class, "logicalChannelClose",
|
|
||||||
"(I)V");
|
|
||||||
method_apdu_transmit = (*env)->GetMethodID(env, apdu_class, "transmit", "(I[B)[B");
|
method_apdu_transmit = (*env)->GetMethodID(env, apdu_class, "transmit", "(I[B)[B");
|
||||||
|
|
||||||
jclass http_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/HttpInterface");
|
jclass http_class = (*env)->FindClass(env, HTTP_INTERFACE_CLASS);
|
||||||
method_http_transmit = (*env)->GetMethodID(env, http_class, "transmit",
|
method_http_transmit = (*env)->GetMethodID(
|
||||||
"(Ljava/lang/String;[B[Ljava/lang/String;)Lnet/typeblog/lpac_jni/HttpInterface$HttpResponse;");
|
env, http_class, "transmit",
|
||||||
|
"("
|
||||||
|
"Ljava/lang/String;" // url
|
||||||
|
"[B" // byte array
|
||||||
|
"Ljava/util/List;" // headers
|
||||||
|
")"
|
||||||
|
"L" HTTP_RESPONSE_CLASS ";"
|
||||||
|
);
|
||||||
|
|
||||||
jclass resp_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/HttpInterface$HttpResponse");
|
jclass resp_class = (*env)->FindClass(env, HTTP_RESPONSE_CLASS);
|
||||||
field_resp_rcode = (*env)->GetFieldID(env, resp_class, "rcode", "I");
|
field_resp_rcode = (*env)->GetFieldID(env, resp_class, "rcode", "I");
|
||||||
field_resp_data = (*env)->GetFieldID(env, resp_class, "data", "[B");
|
field_resp_data = (*env)->GetFieldID(env, resp_class, "data", "[B");
|
||||||
}
|
}
|
||||||
|
@ -36,7 +45,7 @@ void interface_wrapper_init() {
|
||||||
static int apdu_interface_connect(struct euicc_ctx *ctx) {
|
static int apdu_interface_connect(struct euicc_ctx *ctx) {
|
||||||
LPAC_JNI_SETUP_ENV;
|
LPAC_JNI_SETUP_ENV;
|
||||||
(*env)->CallVoidMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface, method_apdu_connect);
|
(*env)->CallVoidMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface, method_apdu_connect);
|
||||||
LPAC_JNI_EXCEPTION_RETURN;
|
LPAC_JNI_EXCEPTION_RETURN
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +61,7 @@ apdu_interface_logical_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, u
|
||||||
(*env)->SetByteArrayRegion(env, jbarr, 0, aid_len, (const jbyte *) aid);
|
(*env)->SetByteArrayRegion(env, jbarr, 0, aid_len, (const jbyte *) aid);
|
||||||
jint ret = (*env)->CallIntMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface,
|
jint ret = (*env)->CallIntMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface,
|
||||||
method_apdu_logical_channel_open, jbarr);
|
method_apdu_logical_channel_open, jbarr);
|
||||||
LPAC_JNI_EXCEPTION_RETURN;
|
LPAC_JNI_EXCEPTION_RETURN
|
||||||
LPAC_JNI_CTX(ctx)->logical_channel_id = ret;
|
LPAC_JNI_CTX(ctx)->logical_channel_id = ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -71,16 +80,16 @@ apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, c
|
||||||
uint32_t tx_len) {
|
uint32_t tx_len) {
|
||||||
const int logic_channel = LPAC_JNI_CTX(ctx)->logical_channel_id;
|
const int logic_channel = LPAC_JNI_CTX(ctx)->logical_channel_id;
|
||||||
LPAC_JNI_SETUP_ENV;
|
LPAC_JNI_SETUP_ENV;
|
||||||
jbyteArray txArr = (*env)->NewByteArray(env, tx_len);
|
jbyteArray txArr = (*env)->NewByteArray(env, (jsize) tx_len);
|
||||||
(*env)->SetByteArrayRegion(env, txArr, 0, tx_len, (const jbyte *) tx);
|
(*env)->SetByteArrayRegion(env, txArr, 0, (jsize) tx_len, (const jbyte *) tx);
|
||||||
jbyteArray ret = (jbyteArray) (*env)->CallObjectMethod(
|
jbyteArray ret = (jbyteArray) (*env)->CallObjectMethod(
|
||||||
env, LPAC_JNI_CTX(ctx)->apdu_interface,
|
env, LPAC_JNI_CTX(ctx)->apdu_interface,
|
||||||
method_apdu_transmit, logic_channel, txArr
|
method_apdu_transmit, logic_channel, txArr
|
||||||
);
|
);
|
||||||
LPAC_JNI_EXCEPTION_RETURN;
|
LPAC_JNI_EXCEPTION_RETURN
|
||||||
*rx_len = (*env)->GetArrayLength(env, ret);
|
*rx_len = (*env)->GetArrayLength(env, ret);
|
||||||
*rx = calloc(*rx_len, sizeof(uint8_t));
|
*rx = calloc(*rx_len, sizeof(uint8_t));
|
||||||
(*env)->GetByteArrayRegion(env, ret, 0, *rx_len, *rx);
|
(*env)->GetByteArrayRegion(env, ret, 0, (jsize) *rx_len, (jbyte *) *rx);
|
||||||
(*env)->DeleteLocalRef(env, txArr);
|
(*env)->DeleteLocalRef(env, txArr);
|
||||||
(*env)->DeleteLocalRef(env, ret);
|
(*env)->DeleteLocalRef(env, ret);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -92,31 +101,22 @@ http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode,
|
||||||
const char **headers) {
|
const char **headers) {
|
||||||
LPAC_JNI_SETUP_ENV;
|
LPAC_JNI_SETUP_ENV;
|
||||||
jstring jurl = toJString(env, url);
|
jstring jurl = toJString(env, url);
|
||||||
jbyteArray txArr = (*env)->NewByteArray(env, tx_len);
|
jbyteArray txArr = (*env)->NewByteArray(env, (jsize) tx_len);
|
||||||
(*env)->SetByteArrayRegion(env, txArr, 0, tx_len, (const jbyte *) tx);
|
(*env)->SetByteArrayRegion(env, txArr, 0, (jsize) tx_len, (const jbyte *) tx);
|
||||||
|
|
||||||
int num_headers = 0;
|
jobject header_list = to_string_list(env, (char **) headers);
|
||||||
while (headers[num_headers] != NULL) {
|
|
||||||
num_headers++;
|
|
||||||
}
|
|
||||||
jobjectArray headersArr = (*env)->NewObjectArray(env, num_headers, string_class, NULL);
|
|
||||||
for (int i = 0; i < num_headers; i++) {
|
|
||||||
jstring header = toJString(env, headers[i]);
|
|
||||||
(*env)->SetObjectArrayElement(env, headersArr, i, header);
|
|
||||||
(*env)->DeleteLocalRef(env, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
jobject ret = (*env)->CallObjectMethod(env, LPAC_JNI_CTX(ctx)->http_interface,
|
jobject ret = (*env)->CallObjectMethod(env, LPAC_JNI_CTX(ctx)->http_interface,
|
||||||
method_http_transmit, jurl, txArr, headersArr);
|
method_http_transmit, jurl, txArr, header_list);
|
||||||
LPAC_JNI_EXCEPTION_RETURN;
|
LPAC_JNI_EXCEPTION_RETURN
|
||||||
*rcode = (*env)->GetIntField(env, ret, field_resp_rcode);
|
*rcode = (*env)->GetIntField(env, ret, field_resp_rcode);
|
||||||
jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data);
|
jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data);
|
||||||
*rx_len = (*env)->GetArrayLength(env, rxArr);
|
*rx_len = (*env)->GetArrayLength(env, rxArr);
|
||||||
*rx = calloc(*rx_len, sizeof(uint8_t));
|
*rx = calloc(*rx_len, sizeof(uint8_t));
|
||||||
(*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, *rx);
|
(*env)->GetByteArrayRegion(env, rxArr, 0, (jsize) *rx_len, (jbyte *) *rx);
|
||||||
(*env)->DeleteLocalRef(env, txArr);
|
(*env)->DeleteLocalRef(env, txArr);
|
||||||
(*env)->DeleteLocalRef(env, rxArr);
|
(*env)->DeleteLocalRef(env, rxArr);
|
||||||
(*env)->DeleteLocalRef(env, headersArr);
|
(*env)->DeleteLocalRef(env, header_list);
|
||||||
(*env)->DeleteLocalRef(env, ret);
|
(*env)->DeleteLocalRef(env, ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <euicc/interface.h>
|
#include <euicc/interface.h>
|
||||||
#include "lpac-jni.h"
|
#include "lpac-jni.h"
|
||||||
|
|
||||||
void interface_wrapper_init();
|
void interface_wrapper_init(JNIEnv *env);
|
||||||
|
|
||||||
extern struct euicc_apdu_interface lpac_jni_apdu_interface;
|
extern struct euicc_apdu_interface lpac_jni_apdu_interface;
|
||||||
extern struct euicc_http_interface lpac_jni_http_interface;
|
extern struct euicc_http_interface lpac_jni_http_interface;
|
||||||
|
|
107
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
107
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include <euicc/es10a.h>
|
||||||
|
#include <euicc/es10b.h>
|
||||||
|
#include <euicc/es9p.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "lpac-discovery.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
jclass configured_addresses_class = (*env)->FindClass(env, EUICC_CONFIGURED_ADDRESSES_CLASS);
|
||||||
|
jmethodID configured_addresses_constructor = (*env)->GetMethodID(
|
||||||
|
env, configured_addresses_class, "<init>",
|
||||||
|
"("
|
||||||
|
"Ljava/lang/String;" // default dp address
|
||||||
|
"Ljava/lang/String;" // root ds address
|
||||||
|
")"
|
||||||
|
"V" // (returns) void
|
||||||
|
);
|
||||||
|
ret = (*env)->NewObject(
|
||||||
|
env, configured_addresses_class,
|
||||||
|
configured_addresses_constructor,
|
||||||
|
toJString(env, addresses.defaultDpAddress),
|
||||||
|
toJString(env, addresses.rootDsAddress)
|
||||||
|
);
|
||||||
|
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;
|
||||||
|
|
||||||
|
jclass callback_class = (*env)->GetObjectClass(env, callback);
|
||||||
|
jmethodID on_discovered = (*env)->GetMethodID(env, callback_class, "onDiscovered",
|
||||||
|
"(Ljava/util/List;)V");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
jobject servers = NULL;
|
||||||
|
char **smdp_list = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#define CHECK_INVOKE_RESULT(COND) if (COND) { ret = -ES10B_ERROR_REASON_UNDEFINED; goto out; }
|
||||||
|
|
||||||
|
// region preparing
|
||||||
|
ret = es10b_get_euicc_challenge_and_info(ctx);
|
||||||
|
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
||||||
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region connecting
|
||||||
|
ret = es9p_initiate_authentication(ctx);
|
||||||
|
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
||||||
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region authenticating
|
||||||
|
ret = es10b_authenticate_server(ctx, NULL, _imei);
|
||||||
|
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
||||||
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
|
|
||||||
|
ret = es11_authenticate_client(ctx, &smdp_list);
|
||||||
|
syslog(LOG_INFO, "es11_authenticate_client %d", ret);
|
||||||
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
servers = to_string_list(env, smdp_list);
|
||||||
|
|
||||||
|
(*env)->CallVoidMethod(env, callback, on_discovered, servers);
|
||||||
|
CHECK_INVOKE_RESULT((*env)->ExceptionCheck(env) == JNI_TRUE)
|
||||||
|
|
||||||
|
#undef CHECK_INVOKE_RESULT
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (servers != NULL) (*env)->DeleteLocalRef(env, servers);
|
||||||
|
if (_imei != NULL) (*env)->ReleaseStringUTFChars(env, imei, _imei);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, address, _address);
|
||||||
|
es11_smdp_list_free_all(smdp_list);
|
||||||
|
return ret;
|
||||||
|
}
|
4
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
4
libs/lpac-jni/src/main/jni/lpac-jni/lpac-discovery.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include "lpac-jni.h"
|
|
@ -3,72 +3,59 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include "utils.h"
|
||||||
#include "lpac-download.h"
|
#include "lpac-download.h"
|
||||||
|
|
||||||
jobject download_state_preparing;
|
static jobject download_state_preparing;
|
||||||
jobject download_state_connecting;
|
static jobject download_state_connecting;
|
||||||
jobject download_state_authenticating;
|
static jobject download_state_authenticating;
|
||||||
jobject download_state_downloading;
|
static jobject download_state_downloading;
|
||||||
jobject download_state_finalizing;
|
static jobject download_state_finalizing;
|
||||||
|
|
||||||
jmethodID on_state_update;
|
#define BIND_DOWNLOAD_STATE_STATIC_FIELD(NAME, FIELD) \
|
||||||
|
download_state_##NAME = bind_static_field(env, download_state_class, FIELD, "L" DOWNLOAD_STATE_CLASS ";")
|
||||||
|
|
||||||
void lpac_download_init() {
|
void lpac_download_init(JNIEnv *env) {
|
||||||
LPAC_JNI_SETUP_ENV;
|
jclass download_state_class = (*env)->FindClass(env, DOWNLOAD_STATE_CLASS);
|
||||||
|
|
||||||
jclass download_state_class = (*env)->FindClass(env,
|
BIND_DOWNLOAD_STATE_STATIC_FIELD(preparing, "Preparing");
|
||||||
"net/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState");
|
BIND_DOWNLOAD_STATE_STATIC_FIELD(connecting, "Connecting");
|
||||||
jfieldID download_state_preparing_field = (*env)->GetStaticFieldID(env, download_state_class,
|
BIND_DOWNLOAD_STATE_STATIC_FIELD(authenticating, "Authenticating");
|
||||||
"Preparing",
|
BIND_DOWNLOAD_STATE_STATIC_FIELD(downloading, "Downloading");
|
||||||
"Lnet/typeblog/lpac_jni/ProfileDownloadCallback$DownloadState;");
|
BIND_DOWNLOAD_STATE_STATIC_FIELD(finalizing, "Finalizing");
|
||||||
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
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(
|
||||||
jstring smdp, jstring matching_id,
|
JNIEnv *env,
|
||||||
jstring imei, jstring confirmation_code,
|
__attribute__((unused)) jobject thiz,
|
||||||
jobject callback) {
|
jlong handle,
|
||||||
|
jstring smdp,
|
||||||
|
jstring matching_id,
|
||||||
|
jstring imei,
|
||||||
|
jstring confirmation_code,
|
||||||
|
jobject callback
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10b_load_bound_profile_package_result es10b_load_bound_profile_package_result;
|
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 *_confirmation_code = NULL;
|
||||||
const char *_matching_id = NULL;
|
const char *_matching_id = NULL;
|
||||||
const char *_smdp = NULL;
|
const char *_smdp = NULL;
|
||||||
const char *_imei = NULL;
|
const char *_imei = NULL;
|
||||||
|
jobject bound_profile_metadata = NULL;
|
||||||
int ret;
|
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)
|
||||||
|
#define CHECK_INVOKE_RESULT(COND) if (COND) { ret = -ES10B_ERROR_REASON_UNDEFINED; goto out; }
|
||||||
|
#define EMIT_STATE_UPDATE(STATE) (*env)->CallVoidMethod(env, callback, on_state_update, STATE)
|
||||||
|
|
||||||
if (confirmation_code != NULL)
|
if (confirmation_code != NULL)
|
||||||
_confirmation_code = (*env)->GetStringUTFChars(env, confirmation_code, NULL);
|
_confirmation_code = (*env)->GetStringUTFChars(env, confirmation_code, NULL);
|
||||||
if (matching_id != NULL)
|
if (matching_id != NULL)
|
||||||
|
@ -79,59 +66,88 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
||||||
|
|
||||||
ctx->http.server_address = _smdp;
|
ctx->http.server_address = _smdp;
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_preparing);
|
// region preparing
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
|
EMIT_STATE_UPDATE(download_state_preparing);
|
||||||
ret = es10b_get_euicc_challenge_and_info(ctx);
|
ret = es10b_get_euicc_challenge_and_info(ctx);
|
||||||
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
syslog(LOG_INFO, "es10b_get_euicc_challenge_and_info %d", ret);
|
||||||
if (ret < 0) {
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
// endregion
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_connecting);
|
// region connecting
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
|
EMIT_STATE_UPDATE(download_state_connecting);
|
||||||
ret = es9p_initiate_authentication(ctx);
|
ret = es9p_initiate_authentication(ctx);
|
||||||
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
syslog(LOG_INFO, "es9p_initiate_authentication %d", ret);
|
||||||
if (ret < 0) {
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
// endregion
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_authenticating);
|
// region authenticating
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
|
EMIT_STATE_UPDATE(download_state_authenticating);
|
||||||
ret = es10b_authenticate_server(ctx, _matching_id, _imei);
|
ret = es10b_authenticate_server(ctx, _matching_id, _imei);
|
||||||
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
syslog(LOG_INFO, "es10b_authenticate_server %d", ret);
|
||||||
if (ret < 0) {
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
ret = es9p_authenticate_client(ctx);
|
ret = es9p_authenticate_client(ctx);
|
||||||
|
syslog(LOG_INFO, "es9p_authenticate_client %d", ret);
|
||||||
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region emit profile metadata
|
||||||
|
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) {
|
if (ret < 0) {
|
||||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
bound_profile_metadata = build_profile_metadata(env, profile_metadata);
|
||||||
|
(*env)->CallVoidMethod(env, callback, on_profile_metadata, bound_profile_metadata);
|
||||||
|
CHECK_INVOKE_RESULT((*env)->ExceptionCheck(env) == JNI_TRUE)
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_downloading);
|
// region downloading
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
|
EMIT_STATE_UPDATE(download_state_downloading);
|
||||||
ret = es10b_prepare_download(ctx, _confirmation_code);
|
ret = es10b_prepare_download(ctx, _confirmation_code);
|
||||||
syslog(LOG_INFO, "es10b_prepare_download %d", ret);
|
syslog(LOG_INFO, "es10b_prepare_download %d", ret);
|
||||||
if (ret < 0) {
|
CHECK_INVOKE_RESULT(ret < 0)
|
||||||
ret = -ES10B_ERROR_REASON_UNDEFINED;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
ret = es9p_get_bound_profile_package(ctx);
|
ret = es9p_get_bound_profile_package(ctx);
|
||||||
if (ret < 0)
|
syslog(LOG_INFO, "es9p_get_bound_profile_package %d", ret);
|
||||||
goto out;
|
if (ret < 0) goto out;
|
||||||
|
// endregion
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing);
|
// region finalizing
|
||||||
|
CHECK_INVOKE_RESULT(IS_CANCELLED())
|
||||||
|
EMIT_STATE_UPDATE(download_state_finalizing);
|
||||||
ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result);
|
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) {
|
if (ret < 0) {
|
||||||
ret = - (int) es10b_load_bound_profile_package_result.errorReason;
|
ret = -(int) es10b_load_bound_profile_package_result.errorReason;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
euicc_http_cleanup(ctx);
|
euicc_http_cleanup(ctx);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
// isCancelled() == false, but ret is an error, the set to cancelled
|
||||||
|
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
|
||||||
|
#undef CHECK_INVOKE_RESULT
|
||||||
|
#undef EMIT_STATE_UPDATE
|
||||||
|
if (bound_profile_metadata != NULL)
|
||||||
|
(*env)->DeleteLocalRef(env, bound_profile_metadata);
|
||||||
// We expect Java side to call cancelSessions after any error -- thus, `euicc_http_cleanup` is done there
|
// 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.
|
// This is so that Java side can access the last HTTP and/or APDU errors when we return.
|
||||||
if (_confirmation_code != NULL)
|
if (_confirmation_code != NULL)
|
||||||
|
@ -144,20 +160,26 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_cancelSessions(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_cancelSessions(
|
||||||
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
es9p_cancel_session(ctx);
|
es9p_cancel_session(ctx);
|
||||||
es10b_cancel_session(ctx, ES10B_CANCEL_SESSION_REASON_UNDEFINED);
|
es10b_cancel_session(ctx, ES10B_CANCEL_SESSION_REASON_UNDEFINED);
|
||||||
euicc_http_cleanup(ctx);
|
euicc_http_cleanup(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define QUOTE(S) #S
|
#define ERRCODE_ENUM_TO_STRING(VARIANT) case VARIANT: return toJString(env, #VARIANT)
|
||||||
#define ERRCODE_ENUM_TO_STRING(VARIANT) case VARIANT: return toJString(env, QUOTE(VARIANT))
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_downloadErrCodeToString(JNIEnv *env, jobject thiz, jint code) {
|
Java_net_typeblog_lpac_1jni_LpacJni_downloadErrCodeToString(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jint code
|
||||||
|
) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INCORRECT_INPUT_VALUES);
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INCORRECT_INPUT_VALUES);
|
||||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INVALID_SIGNATURE);
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INVALID_SIGNATURE);
|
||||||
|
@ -167,15 +189,12 @@ 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_UNSUPPORTED_PROFILE_CLASS);
|
||||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_SCP03T_STRUCTURE_ERROR);
|
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_SCP03T_SECURITY_ERROR);
|
||||||
ERRCODE_ENUM_TO_STRING(
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC);
|
||||||
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_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_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_PE_PROCESSING_ERROR);
|
||||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH);
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH);
|
||||||
ERRCODE_ENUM_TO_STRING(
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_TEST_PROFILE_INSTALL_FAILED_DUE_TO_INVALID_NAA_KEY);
|
||||||
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_PPR_NOT_ALLOWED);
|
||||||
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_UNKNOWN_ERROR);
|
ERRCODE_ENUM_TO_STRING(ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_UNKNOWN_ERROR);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include "lpac-jni.h"
|
#include "lpac-jni.h"
|
||||||
|
|
||||||
void lpac_download_init();
|
void lpac_download_init(JNIEnv *env);
|
|
@ -8,38 +8,31 @@
|
||||||
#include "lpac-jni.h"
|
#include "lpac-jni.h"
|
||||||
#include "lpac-download.h"
|
#include "lpac-download.h"
|
||||||
#include "lpac-notifications.h"
|
#include "lpac-notifications.h"
|
||||||
|
#include "lpac-discovery.h"
|
||||||
|
#include "utils.h"
|
||||||
#include "interface-wrapper.h"
|
#include "interface-wrapper.h"
|
||||||
|
|
||||||
JavaVM *jvm = NULL;
|
JavaVM *jvm = NULL;
|
||||||
|
|
||||||
jstring empty_string;
|
jint JNI_OnLoad(JavaVM *vm, __attribute__((unused)) void *reserved) {
|
||||||
|
|
||||||
jclass string_class;
|
|
||||||
jmethodID string_constructor;
|
|
||||||
|
|
||||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|
||||||
jvm = vm;
|
jvm = vm;
|
||||||
interface_wrapper_init();
|
|
||||||
lpac_download_init();
|
|
||||||
|
|
||||||
LPAC_JNI_SETUP_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, "<init>",
|
|
||||||
"([BLjava/lang/String;)V");
|
|
||||||
|
|
||||||
const jchar _unused[1];
|
interface_wrapper_init(env);
|
||||||
empty_string = (*env)->NewString(env, _unused, 0);
|
lpac_convertor_init(env);
|
||||||
empty_string = (*env)->NewGlobalRef(env, empty_string);
|
lpac_download_init(env);
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_createContext(JNIEnv *env, jobject thiz,
|
Java_net_typeblog_lpac_1jni_LpacJni_createContext(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
jbyteArray isdr_aid,
|
jbyteArray isdr_aid,
|
||||||
jobject apdu_interface,
|
jobject apdu_interface,
|
||||||
jobject http_interface) {
|
jobject http_interface
|
||||||
|
) {
|
||||||
struct lpac_jni_ctx *jni_ctx = NULL;
|
struct lpac_jni_ctx *jni_ctx = NULL;
|
||||||
struct euicc_ctx *ctx = NULL;
|
struct euicc_ctx *ctx = NULL;
|
||||||
jbyte *isdr_java = NULL;
|
jbyte *isdr_java = NULL;
|
||||||
|
@ -66,7 +59,11 @@ Java_net_typeblog_lpac_1jni_LpacJni_createContext(JNIEnv *env, jobject thiz,
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_destroyContext(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_destroyContext(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct lpac_jni_ctx *jni_ctx = LPAC_JNI_CTX(ctx);
|
struct lpac_jni_ctx *jni_ctx = LPAC_JNI_CTX(ctx);
|
||||||
|
|
||||||
|
@ -78,46 +75,42 @@ Java_net_typeblog_lpac_1jni_LpacJni_destroyContext(JNIEnv *env, jobject thiz, jl
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_euiccInit(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_euiccInit(
|
||||||
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
return euicc_init(ctx);
|
return euicc_init(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_euiccFini(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_euiccFini(
|
||||||
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
euicc_fini(ctx);
|
euicc_fini(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_euiccSetMss(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_euiccSetMss(
|
||||||
jbyte mss) {
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jbyte mss
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
ctx->es10x_mss = (uint8_t) mss;
|
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
|
JNIEXPORT jstring JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(
|
||||||
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
|
|
||||||
|
@ -129,71 +122,69 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10c_profile_info_list *info = NULL;
|
struct es10c_profile_info_list *info = NULL;
|
||||||
|
jobject profile_list = new_array_list(env);
|
||||||
|
int ret = es10c_get_profiles_info(ctx, &info);
|
||||||
|
if (ret < 0) goto out;
|
||||||
|
|
||||||
if (es10c_get_profiles_info(ctx, &info) < 0) {
|
jclass profile_info_class = (*env)->FindClass(env, LOCAL_PROFILE_INFO_CLASS);
|
||||||
return 0;
|
|
||||||
|
jmethodID profile_info_class_constructor = (*env)->GetMethodID(
|
||||||
|
env, profile_info_class, "<init>",
|
||||||
|
"("
|
||||||
|
"Ljava/lang/String;" // iccid
|
||||||
|
"L" PROFILE_STATE_CLASS ";"
|
||||||
|
"Ljava/lang/String;" // name
|
||||||
|
"Ljava/lang/String;" // nickname
|
||||||
|
"Ljava/lang/String;" // provider name
|
||||||
|
"Ljava/lang/String;" // ISD-P AID
|
||||||
|
"L" PROFILE_CLASS_CLASS ";"
|
||||||
|
"L" ICON_TYPE_CLASS ";"
|
||||||
|
"Ljava/lang/String;" // icon (base64-encoded)
|
||||||
|
")"
|
||||||
|
"V"
|
||||||
|
);
|
||||||
|
|
||||||
|
jclass profile_list_class = (*env)->GetObjectClass(env, profile_list);
|
||||||
|
jmethodID add_profile = (*env)->GetMethodID(env, profile_list_class, "add", "(Ljava/lang/Object;)Z");
|
||||||
|
|
||||||
|
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),
|
||||||
|
to_icon_type(info->iconType),
|
||||||
|
toJString(env, info->icon)
|
||||||
|
);
|
||||||
|
(*env)->CallBooleanMethod(env, profile_list, add_profile, element);
|
||||||
|
info = info->next;
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
return (jlong) info;
|
es10c_profile_info_list_free_all(info);
|
||||||
|
return profile_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(
|
||||||
jstring iccid, jboolean refresh) {
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jstring iccid,
|
||||||
|
jboolean refresh
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
const char *_iccid = NULL;
|
const char *_iccid = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -205,8 +196,13 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cDisableProfile(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cDisableProfile(
|
||||||
jstring iccid, jboolean refresh) {
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jstring iccid,
|
||||||
|
jboolean refresh
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
const char *_iccid = NULL;
|
const char *_iccid = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -218,8 +214,13 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDisableProfile(JNIEnv *env, jobject thi
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cSetNickname(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cSetNickname(
|
||||||
jstring iccid, jbyteArray nick) {
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jstring iccid,
|
||||||
|
jbyteArray nick
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
const char *_iccid = NULL;
|
const char *_iccid = NULL;
|
||||||
jbyte *_nick = NULL;
|
jbyte *_nick = NULL;
|
||||||
|
@ -234,8 +235,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cSetNickname(JNIEnv *env, jobject thiz,
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(
|
||||||
jstring iccid) {
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jstring iccid
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
const char *_iccid = NULL;
|
const char *_iccid = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -246,48 +251,59 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10c_ex_euiccinfo2 *info = malloc(sizeof(struct es10c_ex_euiccinfo2));
|
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, "<init>",
|
||||||
|
"("
|
||||||
|
"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
|
||||||
|
);
|
||||||
|
|
||||||
if (es10c_ex_get_euiccinfo2(ctx, info) < 0) {
|
ret = (*env)->NewObject(
|
||||||
free(info);
|
env, euicc_info_class, euicc_info_constructor,
|
||||||
return 0;
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
return (jlong) info;
|
out:
|
||||||
}
|
es10c_ex_euiccinfo2_free(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;
|
|
||||||
int ret;
|
|
||||||
ret = es10c_euicc_memory_reset(ctx);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_stringDeref(JNIEnv *env, jobject thiz, jlong curr) {
|
Java_net_typeblog_lpac_1jni_LpacJni_es10cEuiccMemoryReset(
|
||||||
return toJString(env, *((char **) curr));
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
|
return es10c_euicc_memory_reset(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
|
@ -19,41 +19,4 @@ struct lpac_jni_ctx {
|
||||||
(*jvm)->AttachCurrentThread(jvm, &env, NULL)
|
(*jvm)->AttachCurrentThread(jvm, &env, NULL)
|
||||||
|
|
||||||
extern JavaVM *jvm;
|
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); \
|
|
||||||
}
|
|
|
@ -1,23 +1,63 @@
|
||||||
#include "lpac-notifications.h"
|
|
||||||
#include <euicc/es9p.h>
|
#include <euicc/es9p.h>
|
||||||
#include <euicc/es10b.h>
|
#include <euicc/es10b.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "lpac-notifications.h"
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) {
|
Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(
|
||||||
|
JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10b_notification_metadata_list *info = NULL;
|
struct es10b_notification_metadata_list *metadata = NULL;
|
||||||
|
jobject notification_list = new_array_list(env);
|
||||||
|
int ret = es10b_list_notification(ctx, &metadata);
|
||||||
|
if (ret < 0) goto out;
|
||||||
|
|
||||||
if (es10b_list_notification(ctx, &info) < 0)
|
jclass local_profile_notification_class = (*env)->FindClass(
|
||||||
return 0;
|
env, LOCAL_PROFILE_NOTIFICATION_CLASS);
|
||||||
|
jmethodID local_profile_notification_constructor = (*env)->GetMethodID(
|
||||||
|
env, local_profile_notification_class, "<init>",
|
||||||
|
"("
|
||||||
|
"J" // seqNumber
|
||||||
|
"L" PROFILE_MANAGEMENT_OPERATION_CLASS ";"
|
||||||
|
"Ljava/lang/String;" // notificationAddress
|
||||||
|
"Ljava/lang/String;" // iccid
|
||||||
|
")"
|
||||||
|
"V" // (returns) void
|
||||||
|
);
|
||||||
|
|
||||||
return (jlong) info;
|
jclass notification_list_class = (*env)->GetObjectClass(env, notification_list);
|
||||||
|
jmethodID add_notification = (*env)->GetMethodID(env, notification_list_class, "add", "(Ljava/lang/Object;)Z");
|
||||||
|
|
||||||
|
jobject element = NULL;
|
||||||
|
while (metadata) {
|
||||||
|
element = (*env)->NewObject(
|
||||||
|
env, local_profile_notification_class, local_profile_notification_constructor,
|
||||||
|
(jlong) metadata->seqNumber,
|
||||||
|
to_profile_management_operation(metadata->profileManagementOperation),
|
||||||
|
toJString(env, metadata->notificationAddress),
|
||||||
|
toJString(env, metadata->iccid)
|
||||||
|
);
|
||||||
|
(*env)->CallBooleanMethod(env, notification_list, add_notification, element);
|
||||||
|
metadata = metadata->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
es10b_notification_metadata_list_free_all(metadata);
|
||||||
|
return notification_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_handleNotification(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_handleNotification(
|
||||||
jlong seq_number) {
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jlong seq_number
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
struct es10b_pending_notification notification;
|
struct es10b_pending_notification notification;
|
||||||
int res;
|
int res;
|
||||||
|
@ -40,40 +80,12 @@ Java_net_typeblog_lpac_1jni_LpacJni_handleNotification(JNIEnv *env, jobject thiz
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject thiz, jlong handle,
|
Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(
|
||||||
jlong seq_number) {
|
__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jlong seq_number
|
||||||
|
) {
|
||||||
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
|
||||||
return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number);
|
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)
|
|
||||||
|
|
220
libs/lpac-jni/src/main/jni/lpac-jni/utils.c
Normal file
220
libs/lpac-jni/src/main/jni/lpac-jni/utils.c
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
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 jobject icon_type_jpeg;
|
||||||
|
static jobject icon_type_png;
|
||||||
|
|
||||||
|
static jclass version_class;
|
||||||
|
static jmethodID version_constructor;
|
||||||
|
|
||||||
|
static jstring empty_string;
|
||||||
|
static 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 ";")
|
||||||
|
|
||||||
|
#define BIND_ICON_TYPE_FIELD(NAME, FIELD) \
|
||||||
|
icon_type_##NAME = bind_static_field(env, icon_type_class, FIELD, "L" ICON_TYPE_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, "<init>",
|
||||||
|
"([BLjava/lang/String;)V");
|
||||||
|
const jchar _unused[1];
|
||||||
|
empty_string = (*env)->NewString(env, _unused, 0);
|
||||||
|
empty_string = (*env)->NewGlobalRef(env, empty_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_version_class(JNIEnv *env) {
|
||||||
|
version_class = (*env)->FindClass(env, VERSION_CLASS);
|
||||||
|
version_class = (*env)->NewGlobalRef(env, version_class);
|
||||||
|
version_constructor = (*env)->GetMethodID(env, version_class, "<init>", "(Ljava/lang/String;)V");
|
||||||
|
}
|
||||||
|
|
||||||
|
void lpac_convertor_init(JNIEnv *env) {
|
||||||
|
init_string_class(env);
|
||||||
|
init_version_class(env);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
jclass icon_type_class = (*env)->FindClass(env, ICON_TYPE_CLASS);
|
||||||
|
BIND_ICON_TYPE_FIELD(jpeg, "JPEG");
|
||||||
|
BIND_ICON_TYPE_FIELD(png, "PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring to_icon_type(enum es10c_icon_type icon_type) {
|
||||||
|
switch (icon_type) {
|
||||||
|
case ES10C_ICON_TYPE_JPEG:
|
||||||
|
return icon_type_jpeg;
|
||||||
|
case ES10C_ICON_TYPE_PNG:
|
||||||
|
return icon_type_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_set(JNIEnv *env, char **values) {
|
||||||
|
jobject elements = new_set_list(env);
|
||||||
|
jclass list_class = (*env)->GetObjectClass(env, elements);
|
||||||
|
jmethodID add_element = (*env)->GetMethodID(env, list_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_list(JNIEnv *env, char **values) {
|
||||||
|
jobject elements = new_array_list(env);
|
||||||
|
jclass list_class = (*env)->GetObjectClass(env, elements);
|
||||||
|
jmethodID add_element = (*env)->GetMethodID(env, list_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, "<init>",
|
||||||
|
"("
|
||||||
|
"Ljava/lang/String;" // iccid
|
||||||
|
"Ljava/lang/String;" // name
|
||||||
|
"Ljava/lang/String;" // provider name
|
||||||
|
"L" PROFILE_CLASS_CLASS ";"
|
||||||
|
"L" ICON_TYPE_CLASS ";"
|
||||||
|
"Ljava/lang/String;" // icon (base64-encoded)
|
||||||
|
")"
|
||||||
|
"V" // (returns) void
|
||||||
|
);
|
||||||
|
|
||||||
|
return (*env)->NewObject(
|
||||||
|
env, profile_metadata_class, profile_metadata_constructor,
|
||||||
|
toJString(env, metadata->iccid),
|
||||||
|
toJString(env, metadata->profileName),
|
||||||
|
toJString(env, metadata->serviceProviderName),
|
||||||
|
to_profile_class(metadata->profileClass),
|
||||||
|
to_icon_type(metadata->iconType),
|
||||||
|
toJString(env, metadata->icon)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject new_set_list(JNIEnv *env) {
|
||||||
|
jclass set_class = (*env)->FindClass(env, SET_CLASS);
|
||||||
|
jmethodID set_constructor = (*env)->GetMethodID(env, set_class, "<init>", "()V");
|
||||||
|
return (*env)->NewObject(env, set_class, set_constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject new_array_list(JNIEnv *env) {
|
||||||
|
jclass list_class = (*env)->FindClass(env, LIST_CLASS);
|
||||||
|
jmethodID list_constructor = (*env)->GetMethodID(env, list_class, "<init>", "()V");
|
||||||
|
return (*env)->NewObject(env, list_class, list_constructor);
|
||||||
|
}
|
46
libs/lpac-jni/src/main/jni/lpac-jni/utils.h
Normal file
46
libs/lpac-jni/src/main/jni/lpac-jni/utils.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <euicc/es8p.h>
|
||||||
|
#include <euicc/es10c.h>
|
||||||
|
|
||||||
|
#define PACKAGE_NAME "net/typeblog/lpac_jni"
|
||||||
|
#define PROFILE_STATE_CLASS PACKAGE_NAME "/ProfileState"
|
||||||
|
#define PROFILE_CLASS_CLASS PACKAGE_NAME "/ProfileClass"
|
||||||
|
#define PROFILE_METADATA_CLASS PACKAGE_NAME "/ProfileMetadata"
|
||||||
|
#define PROFILE_MANAGEMENT_OPERATION_CLASS PACKAGE_NAME "/ProfileManagementOperation"
|
||||||
|
#define ICON_TYPE_CLASS PACKAGE_NAME "/IconType"
|
||||||
|
#define DOWNLOAD_CALLBACK_CLASS PACKAGE_NAME "/ProfileDownloadCallback"
|
||||||
|
#define DOWNLOAD_STATE_CLASS DOWNLOAD_CALLBACK_CLASS "$DownloadState"
|
||||||
|
#define LOCAL_PROFILE_INFO_CLASS PACKAGE_NAME "/LocalProfileInfo"
|
||||||
|
#define LOCAL_PROFILE_NOTIFICATION_CLASS PACKAGE_NAME "/LocalProfileNotification"
|
||||||
|
#define EUICC_CONFIGURED_ADDRESSES_CLASS PACKAGE_NAME "/EuiccConfiguredAddresses"
|
||||||
|
#define VERSION_CLASS PACKAGE_NAME "/Version"
|
||||||
|
#define SET_CLASS "java/util/HashSet"
|
||||||
|
#define LIST_CLASS "java/util/ArrayList"
|
||||||
|
|
||||||
|
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_profile_management_operation(enum es10b_profile_management_operation operation);
|
||||||
|
|
||||||
|
jstring to_icon_type(enum es10c_icon_type icon_type);
|
||||||
|
|
||||||
|
jobject to_version(JNIEnv *env, const char *version);
|
||||||
|
|
||||||
|
jobject to_string_set(JNIEnv *env, char **values);
|
||||||
|
|
||||||
|
jobject to_string_list(JNIEnv *env, char **values);
|
||||||
|
|
||||||
|
jobject build_profile_metadata(JNIEnv *env, struct es8p_metadata *metadata);
|
||||||
|
|
||||||
|
jobject new_set_list(JNIEnv *env);
|
||||||
|
|
||||||
|
jobject new_array_list(JNIEnv *env);
|
Loading…
Add table
Reference in a new issue