Compare commits

...
Sign in to create a new pull request.

3 commits

View file

@ -11,12 +11,14 @@ import net.typeblog.lpac_jni.LocalProfileInfo
import net.typeblog.lpac_jni.LocalProfileNotification import net.typeblog.lpac_jni.LocalProfileNotification
import net.typeblog.lpac_jni.ProfileDownloadCallback import net.typeblog.lpac_jni.ProfileDownloadCallback
import net.typeblog.lpac_jni.Version import net.typeblog.lpac_jni.Version
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
class LocalProfileAssistantImpl( class LocalProfileAssistantImpl(
isdrAid: ByteArray, isdrAid: ByteArray,
rawApduInterface: ApduInterface, rawApduInterface: ApduInterface,
rawHttpInterface: HttpInterface rawHttpInterface: HttpInterface
): LocalProfileAssistant { ) : LocalProfileAssistant {
companion object { companion object {
private const val TAG = "LocalProfileAssistantImpl" private const val TAG = "LocalProfileAssistantImpl"
} }
@ -74,6 +76,10 @@ class LocalProfileAssistantImpl(
} }
} }
// Controls concurrency of every single method in this class, since
// the C-side is explicitly NOT thread-safe
private val lock = ReentrantLock()
private val apduInterface = ApduInterfaceWrapper(rawApduInterface) private val apduInterface = ApduInterfaceWrapper(rawApduInterface)
private val httpInterface = HttpInterfaceWrapper(rawHttpInterface) private val httpInterface = HttpInterfaceWrapper(rawHttpInterface)
@ -105,23 +111,24 @@ class LocalProfileAssistantImpl(
} }
override val profiles: List<LocalProfileInfo> override val profiles: List<LocalProfileInfo>
@Synchronized get() = lock.withLock {
get() {
val head = LpacJni.es10cGetProfilesInfo(contextHandle) val head = LpacJni.es10cGetProfilesInfo(contextHandle)
var curr = head var curr = head
val ret = mutableListOf<LocalProfileInfo>() val ret = mutableListOf<LocalProfileInfo>()
while (curr != 0L) { while (curr != 0L) {
val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr)) val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr))
val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr)) val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr))
ret.add(LocalProfileInfo( ret.add(
LpacJni.profileGetIccid(curr), LocalProfileInfo(
state, LpacJni.profileGetIccid(curr),
LpacJni.profileGetName(curr), state,
LpacJni.profileGetNickname(curr), LpacJni.profileGetName(curr),
LpacJni.profileGetServiceProvider(curr), LpacJni.profileGetNickname(curr),
LpacJni.profileGetIsdpAid(curr), LpacJni.profileGetServiceProvider(curr),
clazz LpacJni.profileGetIsdpAid(curr),
)) clazz
)
)
curr = LpacJni.profilesNext(curr) curr = LpacJni.profilesNext(curr)
} }
@ -130,79 +137,87 @@ class LocalProfileAssistantImpl(
} }
override val notifications: List<LocalProfileNotification> override val notifications: List<LocalProfileNotification>
@Synchronized get() = lock.withLock {
get() {
val head = LpacJni.es10bListNotification(contextHandle) val head = LpacJni.es10bListNotification(contextHandle)
var curr = head var curr = head
val ret = mutableListOf<LocalProfileNotification>()
while (curr != 0L) { try {
ret.add(LocalProfileNotification( val ret = mutableListOf<LocalProfileNotification>()
LpacJni.notificationGetSeq(curr), while (curr != 0L) {
LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)), ret.add(
LpacJni.notificationGetAddress(curr), LocalProfileNotification(
LpacJni.notificationGetIccid(curr), LpacJni.notificationGetSeq(curr),
)) LocalProfileNotification.Operation.fromString(
curr = LpacJni.notificationsNext(curr) LpacJni.notificationGetOperationString(
curr
)
),
LpacJni.notificationGetAddress(curr),
LpacJni.notificationGetIccid(curr),
)
)
curr = LpacJni.notificationsNext(curr)
}
return ret.sortedBy { it.seqNumber }.reversed()
} finally {
LpacJni.notificationsFree(head)
} }
LpacJni.notificationsFree(head)
return ret.sortedBy { it.seqNumber }.reversed()
} }
override val eID: String override val eID: String
@Synchronized get() = lock.withLock { LpacJni.es10cGetEid(contextHandle)!! }
get() = LpacJni.es10cGetEid(contextHandle)!!
override val euiccInfo2: EuiccInfo2? override val euiccInfo2: EuiccInfo2?
@Synchronized get() = lock.withLock {
get() {
val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle) val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle)
if (cInfo == 0L) return null if (cInfo == 0L) return null
val ret = EuiccInfo2( try {
Version(LpacJni.euiccInfo2GetSGP22Version(cInfo)), return EuiccInfo2(
Version(LpacJni.euiccInfo2GetProfileVersion(cInfo)), Version(LpacJni.euiccInfo2GetSGP22Version(cInfo)),
Version(LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo)), Version(LpacJni.euiccInfo2GetProfileVersion(cInfo)),
Version(LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo)), Version(LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo)),
LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo), Version(LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo)),
Version(LpacJni.euiccInfo2GetPpVersion(cInfo)), LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo),
LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(), Version(LpacJni.euiccInfo2GetPpVersion(cInfo)),
LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(), LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(),
buildSet { LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(),
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo) buildSet {
while (cursor != 0L) { var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo)
add(LpacJni.stringDeref(cursor)) while (cursor != 0L) {
cursor = LpacJni.stringArrNext(cursor) add(LpacJni.stringDeref(cursor))
} cursor = LpacJni.stringArrNext(cursor)
}, }
buildSet { },
var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo) buildSet {
while (cursor != 0L) { var cursor = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo)
add(LpacJni.stringDeref(cursor)) while (cursor != 0L) {
cursor = LpacJni.stringArrNext(cursor) add(LpacJni.stringDeref(cursor))
} cursor = LpacJni.stringArrNext(cursor)
}, }
) },
)
LpacJni.euiccInfo2Free(cInfo) } finally {
LpacJni.euiccInfo2Free(cInfo)
return ret }
} }
@Synchronized override fun enableProfile(iccid: String, refresh: Boolean): Boolean = lock.withLock {
override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0 LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0
}
@Synchronized override fun disableProfile(iccid: String, refresh: Boolean): Boolean = lock.withLock {
override fun disableProfile(iccid: String, refresh: Boolean): Boolean =
LpacJni.es10cDisableProfile(contextHandle, iccid, refresh) == 0 LpacJni.es10cDisableProfile(contextHandle, iccid, refresh) == 0
}
@Synchronized override fun deleteProfile(iccid: String): Boolean = lock.withLock {
override fun deleteProfile(iccid: String): Boolean =
LpacJni.es10cDeleteProfile(contextHandle, iccid) == 0 LpacJni.es10cDeleteProfile(contextHandle, iccid) == 0
}
@Synchronized override fun downloadProfile(
override fun downloadProfile(smdp: String, matchingId: String?, imei: String?, smdp: String, matchingId: String?, imei: String?,
confirmationCode: String?, callback: ProfileDownloadCallback) { confirmationCode: String?, callback: ProfileDownloadCallback
) = lock.withLock {
val res = LpacJni.downloadProfile( val res = LpacJni.downloadProfile(
contextHandle, contextHandle,
smdp, smdp,
@ -229,18 +244,17 @@ class LocalProfileAssistantImpl(
} }
} }
@Synchronized override fun deleteNotification(seqNumber: Long): Boolean = lock.withLock {
override fun deleteNotification(seqNumber: Long): Boolean =
LpacJni.es10bDeleteNotification(contextHandle, seqNumber) == 0 LpacJni.es10bDeleteNotification(contextHandle, seqNumber) == 0
}
@Synchronized override fun handleNotification(seqNumber: Long): Boolean = lock.withLock {
override fun handleNotification(seqNumber: Long): Boolean =
LpacJni.handleNotification(contextHandle, seqNumber).also { LpacJni.handleNotification(contextHandle, seqNumber).also {
Log.d(TAG, "handleNotification $seqNumber = $it") Log.d(TAG, "handleNotification $seqNumber = $it")
} == 0 } == 0
}
@Synchronized override fun setNickname(iccid: String, nickname: String) = lock.withLock {
override fun setNickname(iccid: String, nickname: String) {
val encoded = try { val encoded = try {
Charsets.UTF_8.encode(nickname).array() Charsets.UTF_8.encode(nickname).array()
} catch (e: CharacterCodingException) { } catch (e: CharacterCodingException) {
@ -259,11 +273,12 @@ class LocalProfileAssistantImpl(
} }
override fun euiccMemoryReset() { override fun euiccMemoryReset() {
LpacJni.es10cEuiccMemoryReset(contextHandle) lock.withLock {
LpacJni.es10cEuiccMemoryReset(contextHandle)
}
} }
@Synchronized override fun close() = lock.withLock {
override fun close() {
if (!finalized) { if (!finalized) {
LpacJni.euiccFini(contextHandle) LpacJni.euiccFini(contextHandle)
LpacJni.destroyContext(contextHandle) LpacJni.destroyContext(contextHandle)