ソースを参照

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.
Peter Cai 1 年間 前
コミット
7f67000074

+ 10 - 1
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<LocalProfileNotification>?
+    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)
 }

+ 16 - 3
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<LocalProfileNotification>
-        get() =
-            (LpacJni.es10bListNotification(contextHandle) ?: arrayOf())
-                .sortedBy { it.seqNumber }.reversed()
+        get() {
+            val head = LpacJni.es10bListNotification(contextHandle)
+            var curr = head
+            val ret = mutableListOf<LocalProfileNotification>()
+            while (curr != 0L) {
+                ret.add(LocalProfileNotification(
+                    LpacJni.notificationGetSeq(curr),
+                    LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)),
+                    LpacJni.notificationGetAddress(curr),
+                    LpacJni.notificationGetIccid(curr),
+                ))
+                curr = LpacJni.notificationNext(curr)
+            }
+            LpacJni.notificationsFree(head)
+            return ret.sortedBy { it.seqNumber }.reversed()
+        }
 
     override val eID: String
         get() = LpacJni.es10cGetEid(contextHandle)!!

+ 0 - 1
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");

+ 63 - 76
libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.c

@@ -4,88 +4,15 @@
 #include <malloc.h>
 #include <syslog.h>
 
-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, "<init>",
-                                "(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;
-
-    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);
-    });
+        return 0;
 
-    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);
 }

+ 0 - 2
libs/lpac-jni/src/main/jni/lpac-jni/lpac-notifications.h

@@ -2,5 +2,3 @@
 
 #include <jni.h>
 #include "lpac-jni.h"
-
-void lpac_notifications_init();