diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml deleted file mode 100644 index 913d49d9..00000000 --- a/.idea/deploymentTargetSelector.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 589fc6ca..163d6b48 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,20 +4,11 @@ diff --git a/.idea/migrations.xml b/.idea/migrations.xml deleted file mode 100644 index f8051a6f..00000000 --- a/.idea/migrations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file 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 711658ad..227977c9 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,7 +3,6 @@ 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 @@ -11,10 +10,6 @@ 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 @@ -49,17 +44,7 @@ class OmapiApduInterface( "Unknown channel" } - 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 - } + return lastChannel.transmit(tx) } } \ No newline at end of file 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 ac0a99f8..3374f07b 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() diff --git a/app-deps/build.gradle.kts b/app-deps/build.gradle.kts index 6cde72d6..21114360 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 = 34 + compileSdk = 33 defaultConfig { minSdk = 28 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 8424c550..49811bc5 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", "huawei", "honor") + val BROKEN_MANUFACTURERS = arrayOf("xiaomi") } override val title: String diff --git a/libs/lpac-jni/build.gradle.kts b/libs/lpac-jni/build.gradle.kts index 7f451776..b50a9534 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 = 34 + compileSdk = 33 ndkVersion = "26.1.10909125" defaultConfig { 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 32fbb0aa..5a706b9a 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,14 +14,14 @@ internal object LpacJni { // es10c // null returns signify errors external fun es10cGetEid(handle: Long): String? - external fun es10cGetProfilesInfo(handle: Long): Long + external fun es10cGetProfilesInfo(handle: Long): Array? external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDeleteProfile(handle: Long, iccid: String): Int external fun es10cSetNickname(handle: Long, iccid: String, nick: String): Int // 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): Array? external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int // es9p + es10b @@ -31,39 +31,5 @@ internal object LpacJni { external fun handleNotification(handle: Long, seqNumber: Long): Int // es10cex (actually part of es10b) - external fun es10cexGetEuiccInfo2(handle: Long): Long - - // C <-> Java struct / linked list handling - // C String arrays - external fun stringArrNext(curr: Long): Long - external fun stringDeref(curr: Long): String - // Profiles - external fun profilesNext(curr: Long): Long - external fun profilesFree(head: Long): Long - external fun profileGetIccid(curr: Long): String - external fun profileGetIsdpAid(curr: Long): String - external fun profileGetName(curr: Long): String - external fun profileGetNickname(curr: Long): String - external fun profileGetServiceProvider(curr: Long): String - external fun profileGetStateString(curr: Long): String - external fun profileGetClassString(curr: Long): String - // Notifications - external fun notificationsNext(curr: Long): Long - external fun notificationGetSeq(curr: Long): Long - external fun notificationGetOperationString(curr: Long): String - external fun notificationGetAddress(curr: Long): String - external fun notificationGetIccid(curr: Long): String - external fun notificationsFree(head: Long) - // EuiccInfo2 - external fun euiccInfo2Free(info: Long) - external fun 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 + external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2? } \ 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 61491d79..361c594b 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,85 +42,18 @@ class LocalProfileAssistantImpl( } override val profiles: List - 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 - } + get() = LpacJni.es10cGetProfilesInfo(contextHandle)?.asList() ?: listOf() override val notifications: List - 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.notificationsNext(curr) - } - LpacJni.notificationsFree(head) - return ret.sortedBy { it.seqNumber }.reversed() - } + get() = + (LpacJni.es10bListNotification(contextHandle) ?: arrayOf()) + .sortedBy { it.seqNumber }.reversed() override val eID: String get() = LpacJni.es10cGetEid(contextHandle)!! override val euiccInfo2: EuiccInfo2? - 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) - } - - val ret = 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() - ) - - LpacJni.euiccInfo2Free(cInfo) - - return ret - } + get() = LpacJni.es10cexGetEuiccInfo2(contextHandle) 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-download.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-download.c index 91676daf..f8b27ff0 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, reason %d", ret, es10b_load_bound_profile_package_result.errorReason); + syslog(LOG_INFO, "es10b_load_bound_profile_package %d", ret); out: euicc_http_cleanup(ctx); 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 1721b772..6ba8ebf7 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,28 @@ 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; jmethodID string_constructor; +jclass euicc_info2_class; +jmethodID euicc_info2_constructor; + 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"); @@ -28,6 +41,30 @@ 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, "", + "(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); @@ -108,23 +145,25 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cGetEid(JNIEnv *env, jobject thiz, jlong return ret; } -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; +jobject profile_info_native_to_java(JNIEnv *env, struct es10c_profile_info_list *info) { 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"; @@ -136,13 +175,9 @@ Java_net_typeblog_lpac_1jni_LpacJni_profileGetStateString(JNIEnv *env, jobject t 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; + state = (*env)->CallStaticObjectMethod(env, local_profile_state_class, + local_profile_state_from_string, + toJString(env, profileStateStr)); switch (info->profileClass) { case ES10C_PROFILE_CLASS_TEST: @@ -159,16 +194,51 @@ Java_net_typeblog_lpac_1jni_LpacJni_profileGetClassString(JNIEnv *env, jobject t break; } - return toJString(env, profileClassStr); + 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; } -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 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; +} JNIEXPORT jint JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle, @@ -225,38 +295,58 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10cDeleteProfile(JNIEnv *env, jobject thiz return ret; } -JNIEXPORT jlong JNICALL +JNIEXPORT jobject JNICALL Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) { struct euicc_ctx *ctx = (struct euicc_ctx *) handle; - struct es10c_ex_euiccinfo2 *info = malloc(sizeof(struct es10c_ex_euiccinfo2)); + 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; - if (es10c_ex_get_euiccinfo2(ctx, info) < 0) { - free(info); - return 0; - } + if (es10c_ex_get_euiccinfo2(ctx, &info) < 0) + goto out; - return (jlong) info; -} + 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); -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.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)); + }); -void lpac_jni_euiccinfo2_free(struct es10c_ex_euiccinfo2 *info) { - es10c_ex_euiccinfo2_free(info); - free(info); -} + 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)); + }); -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) + 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_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForSigning, EuiccCiPKIdListForSigning) -LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForVerification, EuiccCiPKIdListForVerification) + 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 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 a5d6262d..1915c5e4 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,42 +17,37 @@ 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; -jstring toJString(JNIEnv *env, const char *pat); - -#define LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(st, st_jname) \ - JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Next(JNIEnv *env, jobject thiz, jlong raw) { \ - st *p = (st *) raw; \ - if (p == NULL) return 0; \ - return (jlong) p->next; \ - } - -#define LPAC_JNI_STRUCT_GETTER_NULL_TERM_LIST_NEXT(st, st_jname) \ - JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Next(JNIEnv *env, jobject thiz, jlong raw) { \ - st *p = (st *) raw; \ - p++; \ - if (*p == NULL) return 0; \ - return (jlong) p; \ - } - -#define LPAC_JNI_STRUCT_FREE(st, st_jname, free_func) \ - JNIEXPORT void JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_jname##Free(JNIEnv *env, jobject thiz, jlong raw) { \ - st *p = (st *) raw; \ - if (p == NULL) return; \ - free_func(p); \ - } - -#define LPAC_JNI_STRUCT_GETTER_LONG(st, st_name, name, jname) \ - JNIEXPORT jlong JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_name##Get##jname(JNIEnv *env, jobject thiz, jlong raw) { \ - st *p = (st *) raw; \ - if (p == NULL) return 0; \ - return (jlong) p->name; \ - } - -#define LPAC_JNI_STRUCT_GETTER_STRING(st, st_name, name, jname) \ - JNIEXPORT jstring JNICALL Java_net_typeblog_lpac_1jni_LpacJni_##st_name##Get##jname(JNIEnv *env, jobject thiz, jlong raw) { \ - st *p = (st *) raw; \ - return toJString(env, p->name); \ - } \ No newline at end of file +jstring toJString(JNIEnv *env, const char *pat); \ 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 cf402cf8..1a5ac7c2 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,15 +4,88 @@ #include #include -JNIEXPORT jlong JNICALL +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 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 0; + return NULL; - return (jlong) info; + 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; } JNIEXPORT jint JNICALL @@ -44,36 +117,4 @@ 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 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) +} \ 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 511de2fa..0b88555c 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,3 +2,5 @@ #include #include "lpac-jni.h" + +void lpac_notifications_init(); \ No newline at end of file