From 01fc07fd78026afbf524bd26c85b529c9be1e3fb Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 11 Aug 2024 20:50:57 -0400 Subject: [PATCH 01/14] EuiccManagementFragment: Add nonnull assertion for platform types Fixes build within AOSP 14 source tree. --- .../main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt index 3374f07b..ac0a99f8 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt @@ -296,7 +296,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener, } iccid.setOnLongClickListener { - requireContext().getSystemService(ClipboardManager::class.java) + requireContext().getSystemService(ClipboardManager::class.java)!! .setPrimaryClip(ClipData.newPlainText("iccid", iccid.text)) Toast.makeText(requireContext(), R.string.toast_iccid_copied, Toast.LENGTH_SHORT) .show() From 44b85ffdea4b208513a78b86d90f2f90c680201a Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Wed, 14 Aug 2024 20:15:47 -0400 Subject: [PATCH 02/14] lpac-jni: Log load bpp error reason --- libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c index f8b27ff0..91676daf 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c @@ -114,7 +114,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_downloadProfile(JNIEnv *env, jobject thiz, j (*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing); // TODO: Expose error code as Java-side exceptions? ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result); - syslog(LOG_INFO, "es10b_load_bound_profile_package %d", ret); + syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, es10b_load_bound_profile_package_result.errorReason); out: euicc_http_cleanup(ctx); From 87ea017b36d7abec34838632dd69d8d0a897dfc4 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Wed, 14 Aug 2024 20:43:54 -0400 Subject: [PATCH 03/14] OmapiApduInterface: Log all APDU exchanges --- .../angry/openeuicc/core/OmapiApduInterface.kt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt index 227977c9..711658ad 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt @@ -3,6 +3,7 @@ package im.angry.openeuicc.core import android.se.omapi.Channel import android.se.omapi.SEService import android.se.omapi.Session +import android.util.Log import im.angry.openeuicc.util.* import net.typeblog.lpac_jni.ApduInterface @@ -10,6 +11,10 @@ class OmapiApduInterface( private val service: SEService, private val port: UiccPortInfoCompat ): ApduInterface { + companion object { + const val TAG = "OmapiApduInterface" + } + private lateinit var session: Session private lateinit var lastChannel: Channel @@ -44,7 +49,17 @@ class OmapiApduInterface( "Unknown channel" } - return lastChannel.transmit(tx) + Log.d(TAG, "OMAPI APDU: ${tx.encodeHex()}") + + try { + return lastChannel.transmit(tx).also { + Log.d(TAG, "OMAPI APDU response: ${it.encodeHex()}") + } + } catch (e: Exception) { + Log.e(TAG, "OMAPI APDU exception") + e.printStackTrace() + throw e + } } } \ No newline at end of file From f073261b603c620f99cc081aba1ed80564591380 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 17 Aug 2024 20:55:03 -0400 Subject: [PATCH 04/14] unpriv: Add Huawei and Honor into the blocklist --- .../src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt b/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt index 49811bc5..8424c550 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt @@ -193,7 +193,7 @@ internal class IsdrChannelAccessCheck(private val context: Context): Compatibili internal class KnownBrokenCheck(private val context: Context): CompatibilityCheck(context) { companion object { - val BROKEN_MANUFACTURERS = arrayOf("xiaomi") + val BROKEN_MANUFACTURERS = arrayOf("xiaomi", "huawei", "honor") } override val title: String From 7c07db0aab03925bb5e41f5c9602b238601b03f9 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 17 Aug 2024 20:57:25 -0400 Subject: [PATCH 05/14] README: Warn about non-standard external eSIMs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5616a327..24f4c9f4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ There are two variants of this project: - OpenEUICC: The full-fledged privileged variant. - Due to its privilege requirement, OpenEUICC must be placed inside `/system/priv-app` and be signed with the platform certificate. - The preferred way to including OpenEUICC in a system image is to [build it along with AOSP](#building-aosp). + - __Note__: When privileged, OpenEUICC supports any eUICC chip that implements the SGP.22 standard, internal or external. However, there is __no guarantee__ that external (removable) eSIMs actually follow the standard. Please __DO NOT__ submit bug reports for non-functioning removable eSIMs. They are __NOT__ officially supported unless they also support / are supported by EasyEUICC, the unprivileged variant. - EasyEUICC: Unprivileged version that can run as a user app. - This version supports two modes of operation: 1. Inserted, removable eSIMs: Due to obvious security requirements, EasyEUICC is only able to access eSIM chips whose [ARF/ARA](https://source.android.com/docs/core/connect/uicc#arf) contains the hash of EasyEUICC's signing certificate. From 7f67000074b5146945a7dd822ef8dd64f6f1a681 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Mon, 2 Sep 2024 17:03:20 -0400 Subject: [PATCH 06/14] refactor: lpac-jni: Handle notification struct / linked list in Kotlin JNI does not seem to like a ton of local references very much on armv7 (32-bit), even if env->EnsureLocalCapacity is called. Let's just avoid doing this by moving most of this logic to Kotlin. This also needs to be done for LocalProfileInfo. --- .../java/net/typeblog/lpac_jni/LpacJni.kt | 11 +- .../impl/LocalProfileAssistantImpl.kt | 19 ++- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 1 - .../main/jni/lpac-jni/lpac-notifications.c | 139 ++++++++---------- .../main/jni/lpac-jni/lpac-notifications.h | 2 - 5 files changed, 89 insertions(+), 83 deletions(-) diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 5a706b9a..884c81a4 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -21,7 +21,7 @@ internal object LpacJni { external fun es10cSetNickname(handle: Long, iccid: String, nick: String): Int // es10b - external fun es10bListNotification(handle: Long): Array? + external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null) external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int // es9p + es10b @@ -32,4 +32,13 @@ internal object LpacJni { // es10cex (actually part of es10b) external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2? + + // C <-> Java struct / linked list handling + // Notifications + external fun notificationNext(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) } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 361c594b..0b6aa1da 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -45,9 +45,22 @@ class LocalProfileAssistantImpl( get() = LpacJni.es10cGetProfilesInfo(contextHandle)?.asList() ?: listOf() override val notifications: List - get() = - (LpacJni.es10bListNotification(contextHandle) ?: arrayOf()) - .sortedBy { it.seqNumber }.reversed() + get() { + val head = LpacJni.es10bListNotification(contextHandle) + var curr = head + val ret = mutableListOf() + while (curr != 0L) { + ret.add(LocalProfileNotification( + LpacJni.notificationGetSeq(curr), + LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)), + LpacJni.notificationGetAddress(curr), + LpacJni.notificationGetIccid(curr), + )) + curr = LpacJni.notificationNext(curr) + } + LpacJni.notificationsFree(head) + return ret.sortedBy { it.seqNumber }.reversed() + } override val eID: String get() = LpacJni.es10cGetEid(contextHandle)!! diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index 6ba8ebf7..561e0278 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -33,7 +33,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; interface_wrapper_init(); lpac_download_init(); - lpac_notifications_init(); LPAC_JNI_SETUP_ENV; string_class = (*env)->FindClass(env, "java/lang/String"); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index 1a5ac7c2..cfb1e598 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -4,88 +4,15 @@ #include #include -jclass local_profile_notification_class; -jmethodID local_profile_notification_constructor; - -jclass local_profile_notification_operation_class; -jmethodID local_profile_notification_operation_from_string; - -void lpac_notifications_init() { - LPAC_JNI_SETUP_ENV; - - local_profile_notification_class = - (*env)->FindClass(env, "net/typeblog/lpac_jni/LocalProfileNotification"); - local_profile_notification_class = - (*env)->NewGlobalRef(env, local_profile_notification_class); - local_profile_notification_constructor = - (*env)->GetMethodID(env, local_profile_notification_class, "", - "(JLnet/typeblog/lpac_jni/LocalProfileNotification$Operation;Ljava/lang/String;Ljava/lang/String;)V"); - - local_profile_notification_operation_class = - (*env)->FindClass(env, "net/typeblog/lpac_jni/LocalProfileNotification$Operation"); - local_profile_notification_operation_class = - (*env)->NewGlobalRef(env, local_profile_notification_operation_class); - local_profile_notification_operation_from_string = - (*env)->GetStaticMethodID(env, local_profile_notification_operation_class, "fromString", - "(Ljava/lang/String;)Lnet/typeblog/lpac_jni/LocalProfileNotification$Operation;"); -} - -JNIEXPORT jobject JNICALL +JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct es10b_notification_metadata_list *info = NULL; - struct es10b_notification_metadata_list *curr = NULL; - const char *profileManagementOperationStr = NULL; - jobject notification = NULL; - jobject operation = NULL; - jobjectArray ret = NULL; - int count = 0; if (es10b_list_notification(ctx, &info) < 0) - return NULL; + return 0; - count = LPAC_JNI_LINKED_LIST_COUNT(info, curr); - - ret = (*env)->NewObjectArray(env, count, local_profile_notification_class, NULL); - - LPAC_JNI_LINKED_LIST_FOREACH(info, curr, { - switch (curr->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"; - } - - operation = - (*env)->CallStaticObjectMethod(env, local_profile_notification_operation_class, - local_profile_notification_operation_from_string, - toJString(env, profileManagementOperationStr)); - - notification = - (*env)->NewObject(env, local_profile_notification_class, - local_profile_notification_constructor, curr->seqNumber, - operation, - toJString(env, curr->notificationAddress), - toJString(env, curr->iccid)); - - (*env)->SetObjectArrayElement(env, ret, i, notification); - - (*env)->DeleteLocalRef(env, operation); - (*env)->DeleteLocalRef(env, notification); - }); - - es10b_notification_metadata_list_free_all(info); - return ret; + return (jlong) info; } JNIEXPORT jint JNICALL @@ -117,4 +44,64 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject jlong seq_number) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); +} + +JNIEXPORT jlong JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationNext(JNIEnv *env, jobject thiz, jlong curr) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; + if (info == NULL) { + return 0; + } + return (jlong) info->next; +} + +JNIEXPORT jlong JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationGetSeq(JNIEnv *env, jobject thiz, jlong curr) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; + return info->seqNumber; +} + +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); +} + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationGetAddress(JNIEnv *env, jobject thiz, jlong curr) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; + return toJString(env, info->notificationAddress); +} + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationGetIccid(JNIEnv *env, jobject thiz, jlong curr) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; + return toJString(env, info->iccid); +} + +JNIEXPORT void JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_notificationsFree(JNIEnv *env, jobject thiz, jlong head) { + struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) head; + if (info == NULL) return; + es10b_notification_metadata_list_free_all(info); } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h index 0b88555c..511de2fa 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h @@ -2,5 +2,3 @@ #include #include "lpac-jni.h" - -void lpac_notifications_init(); \ No newline at end of file From 394cad2eac64eeb8feef50b9e1e2fd71346af1a2 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 3 Sep 2024 21:35:41 -0400 Subject: [PATCH 07/14] refactor: lpac-jni: Use C macros to generate struct-exposing functions --- .../java/net/typeblog/lpac_jni/LpacJni.kt | 2 +- .../impl/LocalProfileAssistantImpl.kt | 2 +- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.h | 29 +++++++++++++- .../main/jni/lpac-jni/lpac-notifications.c | 38 +++---------------- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 884c81a4..37406a74 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -35,7 +35,7 @@ internal object LpacJni { // C <-> Java struct / linked list handling // Notifications - external fun notificationNext(curr: Long): Long + external fun notificationsNext(curr: Long): Long external fun notificationGetSeq(curr: Long): Long external fun notificationGetOperationString(curr: Long): String external fun notificationGetAddress(curr: Long): String diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 0b6aa1da..0b03b647 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -56,7 +56,7 @@ class LocalProfileAssistantImpl( LpacJni.notificationGetAddress(curr), LpacJni.notificationGetIccid(curr), )) - curr = LpacJni.notificationNext(curr) + curr = LpacJni.notificationsNext(curr) } LpacJni.notificationsFree(head) return ret.sortedBy { it.seqNumber }.reversed() diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index 1915c5e4..4d537ee5 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -50,4 +50,31 @@ struct lpac_jni_ctx { extern JavaVM *jvm; extern jclass string_class; -jstring toJString(JNIEnv *env, const char *pat); \ No newline at end of file +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_LINKED_LIST_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, name, jname) \ + JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_notificationGet##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, name, jname) \ + JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_notificationGet##jname(JNIEnv *env, jobject thiz, jlong raw) { \ + st *p = (st *) raw; \ + return toJString(env, p->name); \ + } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index cfb1e598..bd4dffda 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -46,21 +46,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); } -JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationNext(JNIEnv *env, jobject thiz, jlong curr) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; - if (info == NULL) { - return 0; - } - return (jlong) info->next; -} - -JNIEXPORT jlong JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationGetSeq(JNIEnv *env, jobject thiz, jlong curr) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; - return info->seqNumber; -} - JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, jobject thiz, jlong curr) { @@ -87,21 +72,8 @@ Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, return toJString(env, profileManagementOperationStr); } -JNIEXPORT jstring JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationGetAddress(JNIEnv *env, jobject thiz, jlong curr) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; - return toJString(env, info->notificationAddress); -} - -JNIEXPORT jstring JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationGetIccid(JNIEnv *env, jobject thiz, jlong curr) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr; - return toJString(env, info->iccid); -} - -JNIEXPORT void JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_notificationsFree(JNIEnv *env, jobject thiz, jlong head) { - struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) head; - if (info == NULL) return; - es10b_notification_metadata_list_free_all(info); -} \ No newline at end of file +LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications) +LPAC_JNI_STRUCT_LINKED_LIST_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10b_notification_metadata_list, seqNumber, Seq) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notificationAddress, Address) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, iccid, Iccid) \ No newline at end of file From 5ab07d626276e6381e4ce48ad70449d8d2a77b36 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 3 Sep 2024 21:45:50 -0400 Subject: [PATCH 08/14] README: Mention more clearly it's GNU GPL v3 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 24f4c9f4..f8019b2a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ There are two variants of this project: - Prebuilt release-mode EasyEUICC apks can be downloaded [here](https://gitea.angry.im/PeterCxy/OpenEUICC/releases) - For removable eSIM chip vendors: to have your chip supported by official builds of EasyEUICC when inserted, include the ARA-M hash `2A2FA878BC7C3354C2CF82935A5945A3EDAE4AFA` +__This project is Free Software licensed under GNU GPL v3, WITHOUT the "or later" clause.__ Any modification and derivative work __MUST__ be released under the SAME license, which means, at the very least, that the source code __MUST__ be available upon request. + +__If you are releasing a modification of this app, you are kindly asked to make changes to at least the app name and package name.__ + Building (Gradle) === From b101b01228231714e298e09a293a91b99892a6cd Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 15:51:37 -0400 Subject: [PATCH 09/14] chore: Bump all subproject compileSdks ...yes, we'll probably need to bump these again very soon. --- app-deps/build.gradle.kts | 2 +- libs/lpac-jni/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-deps/build.gradle.kts b/app-deps/build.gradle.kts index 21114360..6cde72d6 100644 --- a/app-deps/build.gradle.kts +++ b/app-deps/build.gradle.kts @@ -13,7 +13,7 @@ apply { android { namespace = "im.angry.openeuicc_deps" - compileSdk = 33 + compileSdk = 34 defaultConfig { minSdk = 28 diff --git a/libs/lpac-jni/build.gradle.kts b/libs/lpac-jni/build.gradle.kts index b50a9534..7f451776 100644 --- a/libs/lpac-jni/build.gradle.kts +++ b/libs/lpac-jni/build.gradle.kts @@ -5,7 +5,7 @@ plugins { android { namespace = "net.typeblog.lpac_jni" - compileSdk = 33 + compileSdk = 34 ndkVersion = "26.1.10909125" defaultConfig { From 0afbece3b5b5551fc1735a79c72527ce2b565c33 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 15:53:11 -0400 Subject: [PATCH 10/14] .idea: Whatever updates Android Studio wants --- .idea/deploymentTargetSelector.xml | 10 ++++++++++ .idea/gradle.xml | 16 +++++++++++++--- .idea/migrations.xml | 10 ++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/migrations.xml diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 00000000..913d49d9 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 163d6b48..589fc6ca 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,11 +4,20 @@ diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file From c681e99e4762be890b81fb419b799aca3c935d12 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 16:02:28 -0400 Subject: [PATCH 11/14] refactor: lpac-jni: Move profiles linked list to Kotlin handling too --- .../java/net/typeblog/lpac_jni/LpacJni.kt | 12 +- .../impl/LocalProfileAssistantImpl.kt | 23 +++- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 121 +++++------------- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.h | 8 +- .../main/jni/lpac-jni/lpac-notifications.c | 6 +- 5 files changed, 70 insertions(+), 100 deletions(-) diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index 37406a74..d4ea8b22 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -14,7 +14,7 @@ internal object LpacJni { // es10c // null returns signify errors external fun es10cGetEid(handle: Long): String? - external fun es10cGetProfilesInfo(handle: Long): Array? + external fun es10cGetProfilesInfo(handle: Long): Long external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDeleteProfile(handle: Long, iccid: String): Int @@ -34,6 +34,16 @@ internal object LpacJni { external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2? // C <-> Java struct / linked list handling + // 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 diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 0b03b647..4515ea60 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -42,7 +42,28 @@ class LocalProfileAssistantImpl( } override val profiles: List - get() = LpacJni.es10cGetProfilesInfo(contextHandle)?.asList() ?: listOf() + get() { + val head = LpacJni.es10cGetProfilesInfo(contextHandle) + var curr = head + val ret = mutableListOf() + while (curr != 0L) { + val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr)) + val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr)) + ret.add(LocalProfileInfo( + LpacJni.profileGetIccid(curr), + state, + LpacJni.profileGetName(curr), + LpacJni.profileGetNickname(curr), + LpacJni.profileGetServiceProvider(curr), + LpacJni.profileGetIsdpAid(curr), + clazz + )) + curr = LpacJni.profilesNext(curr) + } + + LpacJni.profilesFree(curr) + return ret + } override val notifications: List get() { diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index 561e0278..5dcddce3 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -12,15 +12,6 @@ JavaVM *jvm = NULL; -jclass local_profile_info_class; -jmethodID local_profile_info_constructor; - -jclass local_profile_state_class; -jmethodID local_profile_state_from_string; - -jclass local_profile_class_class; -jmethodID local_profile_class_from_string; - jstring empty_string; jclass string_class; @@ -40,25 +31,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { string_constructor = (*env)->GetMethodID(env, string_class, "", "([BLjava/lang/String;)V"); - local_profile_info_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/LocalProfileInfo"); - local_profile_info_class = (*env)->NewGlobalRef(env, local_profile_info_class); - local_profile_info_constructor = (*env)->GetMethodID(env, local_profile_info_class, "", - "(Ljava/lang/String;Lnet/typeblog/lpac_jni/LocalProfileInfo$State;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lnet/typeblog/lpac_jni/LocalProfileInfo$Clazz;)V"); - - local_profile_state_class = (*env)->FindClass(env, - "net/typeblog/lpac_jni/LocalProfileInfo$State"); - local_profile_state_class = (*env)->NewGlobalRef(env, local_profile_state_class); - local_profile_state_from_string = (*env)->GetStaticMethodID(env, local_profile_state_class, - "fromString", - "(Ljava/lang/String;)Lnet/typeblog/lpac_jni/LocalProfileInfo$State;"); - - local_profile_class_class = (*env)->FindClass(env, - "net/typeblog/lpac_jni/LocalProfileInfo$Clazz"); - local_profile_class_class = (*env)->NewGlobalRef(env, local_profile_class_class); - local_profile_class_from_string = (*env)->GetStaticMethodID(env, local_profile_class_class, - "fromString", - "(Ljava/lang/String;)Lnet/typeblog/lpac_jni/LocalProfileInfo$Clazz;"); - euicc_info2_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/EuiccInfo2"); euicc_info2_class = (*env)->NewGlobalRef(env, euicc_info2_class); euicc_info2_constructor = (*env)->GetMethodID(env, euicc_info2_class, "", @@ -144,25 +116,23 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong return ret; } -jobject profile_info_native_to_java(JNIEnv *env, struct es10c_profile_info_list *info) { +JNIEXPORT jlong JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) { + struct euicc_ctx *ctx = (struct euicc_ctx *) handle; + struct es10c_profile_info_list *info = NULL; + + if (es10c_get_profiles_info(ctx, &info) < 0) { + return 0; + } + + return (jlong) info; +} + +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_profileGetStateString(JNIEnv *env, jobject thiz, jlong curr) { + struct es10c_profile_info_list *info = (struct es10c_profile_info_list *) curr; const char *profileStateStr = NULL; - const char *profileClassStr = NULL; - jstring serviceProvider = NULL; - jstring nickName = NULL; - jstring isdpAid = NULL; - jstring iccid = NULL; - jstring name = NULL; - jobject state = NULL; - jobject class = NULL; - jobject jinfo = NULL; - iccid = toJString(env, info->iccid); - isdpAid = toJString(env, info->isdpAid); - name = toJString(env, info->profileName); - nickName = toJString(env, info->profileNickname); - serviceProvider = toJString(env, info->serviceProviderName); - - // TODO: Maybe we should pass a Java object directly here? switch (info->profileState) { case ES10C_PROFILE_STATE_ENABLED: profileStateStr = "enabled"; @@ -174,9 +144,13 @@ jobject profile_info_native_to_java(JNIEnv *env, struct es10c_profile_info_list profileStateStr = "unknown"; } - state = (*env)->CallStaticObjectMethod(env, local_profile_state_class, - local_profile_state_from_string, - toJString(env, profileStateStr)); + 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: @@ -193,51 +167,16 @@ jobject profile_info_native_to_java(JNIEnv *env, struct es10c_profile_info_list break; } - class = (*env)->CallStaticObjectMethod(env, local_profile_class_class, - local_profile_class_from_string, - toJString(env, profileClassStr)); - - jinfo = (*env)->NewObject(env, local_profile_info_class, local_profile_info_constructor, - iccid, state, name, nickName, serviceProvider, isdpAid, class); - - (*env)->DeleteLocalRef(env, class); - (*env)->DeleteLocalRef(env, state); - (*env)->DeleteLocalRef(env, serviceProvider); - (*env)->DeleteLocalRef(env, nickName); - (*env)->DeleteLocalRef(env, name); - (*env)->DeleteLocalRef(env, isdpAid); - (*env)->DeleteLocalRef(env, iccid); - - return jinfo; + return toJString(env, profileClassStr); } -JNIEXPORT jobjectArray JNICALL -Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) { - struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10c_profile_info_list *info = NULL; - struct es10c_profile_info_list *curr = NULL; - jobjectArray ret = NULL; - jobject jinfo = NULL; - int count = 0; - - if (es10c_get_profiles_info(ctx, &info) < 0) { - return NULL; - } - - count = LPAC_JNI_LINKED_LIST_COUNT(info, curr); - - ret = (*env)->NewObjectArray(env, count, local_profile_info_class, NULL); - - // Convert the native info array to Java - LPAC_JNI_LINKED_LIST_FOREACH(info, curr, { - jinfo = profile_info_native_to_java(env, curr); - (*env)->SetObjectArrayElement(env, ret, i, jinfo); - (*env)->DeleteLocalRef(env, jinfo); - }); - - es10c_profile_info_list_free_all(info); - return ret; -} +LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10c_profile_info_list, profiles) +LPAC_JNI_STRUCT_LINKED_LIST_FREE(struct es10c_profile_info_list, profiles, es10c_profile_info_list_free_all) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, iccid, Iccid) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, isdpAid, IsdpAid) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileName, Name) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileNickname, Nickname) +LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, serviceProviderName, ServiceProvider) JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle, diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index 4d537ee5..d185551d 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -66,15 +66,15 @@ jstring toJString(JNIEnv *env, const char *pat); free_func(p); \ } -#define LPAC_JNI_STRUCT_GETTER_LONG(st, name, jname) \ - JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_notificationGet##jname(JNIEnv *env, jobject thiz, jlong raw) { \ +#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, name, jname) \ - JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_notificationGet##jname(JNIEnv *env, jobject thiz, jlong raw) { \ +#define LPAC_JNI_STRUCT_GETTER_STRING(st, st_name, name, jname) \ + JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_name##Get##jname(JNIEnv *env, jobject thiz, jlong raw) { \ st *p = (st *) raw; \ return toJString(env, p->name); \ } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index bd4dffda..b2c48258 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -74,6 +74,6 @@ Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications) LPAC_JNI_STRUCT_LINKED_LIST_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all) -LPAC_JNI_STRUCT_GETTER_LONG(struct es10b_notification_metadata_list, seqNumber, Seq) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notificationAddress, Address) -LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, iccid, Iccid) \ No newline at end of file +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) From a43ceea39f09867be95d8e0828fff0a25b602197 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 16:26:33 -0400 Subject: [PATCH 12/14] lpac-jni: linked list free -> struct free --- libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 2 +- libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h | 2 +- libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index 5dcddce3..c4ca95cb 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -171,7 +171,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_profileGetClassString(JNIEnv *env, jobject t } LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10c_profile_info_list, profiles) -LPAC_JNI_STRUCT_LINKED_LIST_FREE(struct es10c_profile_info_list, profiles, es10c_profile_info_list_free_all) +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) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index d185551d..87b07169 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -59,7 +59,7 @@ jstring toJString(JNIEnv *env, const char *pat); return (jlong) p->next; \ } -#define LPAC_JNI_STRUCT_LINKED_LIST_FREE(st, st_jname, free_func) \ +#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; \ diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c index b2c48258..cf402cf8 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c @@ -73,7 +73,7 @@ Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, } LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications) -LPAC_JNI_STRUCT_LINKED_LIST_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all) +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) From bf361882195d003b1b143d1d65f0f45c3237acbe Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 20:32:27 -0400 Subject: [PATCH 13/14] refactor: lpac-jni: Move EuiccInfo2 handling to Kotlin too --- .../java/net/typeblog/lpac_jni/LpacJni.kt | 17 +++- .../impl/LocalProfileAssistantImpl.kt | 31 ++++++- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.c | 82 ++++++------------- .../lpac-jni/src/main/jni/lpac-jni/lpac-jni.h | 38 ++------- 4 files changed, 81 insertions(+), 87 deletions(-) diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt index d4ea8b22..32fbb0aa 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LpacJni.kt @@ -31,9 +31,12 @@ internal object LpacJni { external fun handleNotification(handle: Long, seqNumber: Long): Int // es10cex (actually part of es10b) - external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2? + external fun es10cexGetEuiccInfo2(handle: Long): Long // C <-> Java struct / linked list handling + // C String arrays + external fun stringArrNext(curr: Long): Long + external fun stringDeref(curr: Long): String // Profiles external fun profilesNext(curr: Long): Long external fun profilesFree(head: Long): Long @@ -51,4 +54,16 @@ internal object LpacJni { 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 euiccInfo2GetProfileVersion(info: Long): String + external fun euiccInfo2GetEuiccFirmwareVersion(info: Long): String + external fun euiccInfo2GetGlobalPlatformVersion(info: Long): String + external fun euiccInfo2GetSasAcreditationNumber(info: Long): String + external fun euiccInfo2GetPpVersion(info: Long): String + external fun euiccInfo2GetFreeNonVolatileMemory(info: Long): Long + external fun euiccInfo2GetFreeVolatileMemory(info: Long): Long + // C String Arrays + external fun euiccInfo2GetEuiccCiPKIdListForSigning(info: Long): Long + external fun euiccInfo2GetEuiccCiPKIdListForVerification(info: Long): Long } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 4515ea60..08748d39 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -87,7 +87,36 @@ class LocalProfileAssistantImpl( get() = LpacJni.es10cGetEid(contextHandle)!! override val euiccInfo2: EuiccInfo2? - get() = LpacJni.es10cexGetEuiccInfo2(contextHandle) + get() { + val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle) + if (cInfo == 0L) return null + + val euiccCiPKIdListForSigning = mutableListOf() + var curr = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo) + while (curr != 0L) { + euiccCiPKIdListForSigning.add(LpacJni.stringDeref(curr)) + curr = LpacJni.stringArrNext(curr) + } + + val euiccCiPKIdListForVerification = mutableListOf() + curr = LpacJni.euiccInfo2GetEuiccCiPKIdListForVerification(cInfo) + while (curr != 0L) { + euiccCiPKIdListForVerification.add(LpacJni.stringDeref(curr)) + curr = LpacJni.stringArrNext(curr) + } + + return EuiccInfo2( + LpacJni.euiccInfo2GetProfileVersion(cInfo), + LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo), + LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo), + LpacJni.euiccInfo2GetSasAcreditationNumber(cInfo), + LpacJni.euiccInfo2GetPpVersion(cInfo), + LpacJni.euiccInfo2GetFreeNonVolatileMemory(cInfo).toInt(), + LpacJni.euiccInfo2GetFreeVolatileMemory(cInfo).toInt(), + euiccCiPKIdListForSigning.toTypedArray(), + euiccCiPKIdListForVerification.toTypedArray() + ) + } override fun enableProfile(iccid: String, refresh: Boolean): Boolean = LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0 diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index c4ca95cb..1721b772 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -17,9 +17,6 @@ jstring empty_string; jclass string_class; jmethodID string_constructor; -jclass euicc_info2_class; -jmethodID euicc_info2_constructor; - jint JNI_OnLoad(JavaVM *vm, void *reserved) { jvm = vm; interface_wrapper_init(); @@ -31,11 +28,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { string_constructor = (*env)->GetMethodID(env, string_class, "", "([BLjava/lang/String;)V"); - euicc_info2_class = (*env)->FindClass(env, "net/typeblog/lpac_jni/EuiccInfo2"); - euicc_info2_class = (*env)->NewGlobalRef(env, euicc_info2_class); - euicc_info2_constructor = (*env)->GetMethodID(env, euicc_info2_class, "", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II[Ljava/lang/String;[Ljava/lang/String;)V"); - const char _unused[1]; empty_string = (*env)->NewString(env, _unused, 0); empty_string = (*env)->NewGlobalRef(env, empty_string); @@ -233,58 +225,38 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz return ret; } -JNIEXPORT jobject JNICALL +JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10c_ex_euiccinfo2 info = {0}; - jobjectArray euiccCiPKIdListForVerification = NULL; - jobjectArray euiccCiPKIdListForSigning = NULL; - jstring sas_accreditation_number = NULL; - jstring global_platform_version = NULL; - jstring euicc_firmware_version = NULL; - jstring profile_version = NULL; - jstring pp_version = NULL; - jobject ret = NULL; - char **curr = NULL; - int count = 0; + struct es10c_ex_euiccinfo2 *info = malloc(sizeof(struct es10c_ex_euiccinfo2)); - if (es10c_ex_get_euiccinfo2(ctx, &info) < 0) - goto out; + if (es10c_ex_get_euiccinfo2(ctx, info) < 0) { + free(info); + return 0; + } - profile_version = toJString(env, info.profileVersion); - euicc_firmware_version = toJString(env, info.euiccFirmwareVer); - global_platform_version = toJString(env, info.globalplatformVersion); - sas_accreditation_number = toJString(env, info.sasAcreditationNumber); - pp_version = toJString(env, info.ppVersion); + return (jlong) info; +} - count = LPAC_JNI_NULL_TERM_LIST_COUNT(info.euiccCiPKIdListForSigning, curr); - euiccCiPKIdListForSigning = (*env)->NewObjectArray(env, count, string_class, NULL); - LPAC_JNI_NULL_TERM_LIST_FOREACH(info.euiccCiPKIdListForSigning, curr, { - (*env)->SetObjectArrayElement(env, euiccCiPKIdListForSigning, i, toJString(env, *curr)); - }); +JNIEXPORT jstring JNICALL +Java_net_typeblog_lpac_1jni_LpacJni_stringDeref(JNIEnv *env, jobject thiz, jlong curr) { + return toJString(env, *((char **) curr)); +} - count = LPAC_JNI_NULL_TERM_LIST_COUNT(info.euiccCiPKIdListForVerification, curr); - euiccCiPKIdListForVerification = (*env)->NewObjectArray(env, count, string_class, NULL); - LPAC_JNI_NULL_TERM_LIST_FOREACH(info.euiccCiPKIdListForVerification, curr, { - (*env)->SetObjectArrayElement(env, euiccCiPKIdListForVerification, i, - toJString(env, *curr)); - }); +void lpac_jni_euiccinfo2_free(struct es10c_ex_euiccinfo2 *info) { + es10c_ex_euiccinfo2_free(info); + free(info); +} - ret = (*env)->NewObject(env, euicc_info2_class, euicc_info2_constructor, - profile_version, euicc_firmware_version, - global_platform_version, - sas_accreditation_number, pp_version, - info.extCardResource.freeNonVolatileMemory, - info.extCardResource.freeVolatileMemory, - euiccCiPKIdListForSigning, - euiccCiPKIdListForVerification); +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, 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) - out: - (*env)->DeleteLocalRef(env, profile_version); - (*env)->DeleteLocalRef(env, euicc_firmware_version); - (*env)->DeleteLocalRef(env, global_platform_version); - (*env)->DeleteLocalRef(env, sas_accreditation_number); - (*env)->DeleteLocalRef(env, pp_version); - es10c_ex_euiccinfo2_free(&info); - return ret; -} \ No newline at end of file +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForSigning, EuiccCiPKIdListForSigning) +LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForVerification, EuiccCiPKIdListForVerification) diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index 87b07169..a5d6262d 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -17,36 +17,6 @@ struct lpac_jni_ctx { JNIEnv *env; \ (*jvm)->AttachCurrentThread(jvm, &env, NULL) -#define __LPAC_JNI_LINKED_LIST_FOREACH(list, curr, body, after) { \ - int i = 0; \ - curr = list; \ - while (curr != NULL) { \ - body; \ - curr = curr->next; \ - i++; \ - }; \ - after; \ -} -#define LPAC_JNI_LINKED_LIST_FOREACH(list, curr, body) \ - __LPAC_JNI_LINKED_LIST_FOREACH(list, curr, body, {}) -#define LPAC_JNI_LINKED_LIST_COUNT(list, curr) \ - (__LPAC_JNI_LINKED_LIST_FOREACH(list, curr, {}, i)) - -#define __LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body, after) { \ - int i = 0; \ - curr = list; \ - while (*curr != NULL) { \ - body; \ - curr++; \ - i++; \ - }; \ - after; \ -} -#define LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body) \ - __LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, body, {}) -#define LPAC_JNI_NULL_TERM_LIST_COUNT(list, curr) \ - (__LPAC_JNI_NULL_TERM_LIST_FOREACH(list, curr, {}, i)) - extern JavaVM *jvm; extern jclass string_class; @@ -59,6 +29,14 @@ jstring toJString(JNIEnv *env, const char *pat); 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; \ From 68f1e370fc1b277b9a00b0a266374e24d227bb37 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 7 Sep 2024 20:35:13 -0400 Subject: [PATCH 14/14] lpac-jni: Make sure to free EuiccInfo2 --- .../net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 08748d39..61491d79 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -105,7 +105,7 @@ class LocalProfileAssistantImpl( curr = LpacJni.stringArrNext(curr) } - return EuiccInfo2( + val ret = EuiccInfo2( LpacJni.euiccInfo2GetProfileVersion(cInfo), LpacJni.euiccInfo2GetEuiccFirmwareVersion(cInfo), LpacJni.euiccInfo2GetGlobalPlatformVersion(cInfo), @@ -116,6 +116,10 @@ class LocalProfileAssistantImpl( euiccCiPKIdListForSigning.toTypedArray(), euiccCiPKIdListForVerification.toTypedArray() ) + + LpacJni.euiccInfo2Free(cInfo) + + return ret } override fun enableProfile(iccid: String, refresh: Boolean): Boolean =