Compare commits

..

No commits in common. "0e3a57f948366b83f988d4ee1aedd474af9a973f" and "316abf0a3dc715bf5dcff5bbffc31bee405030fd" have entirely different histories.

15 changed files with 274 additions and 292 deletions

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app-unpriv">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

16
.idea/gradle.xml generated
View file

@ -4,20 +4,11 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<compositeConfiguration> <option name="testRunner" value="GRADLE" />
<compositeBuild compositeDefinitionSource="SCRIPT"> <option name="distributionType" value="DEFAULT_WRAPPED" />
<builds>
<build path="$PROJECT_DIR$/buildSrc" name="buildSrc">
<projects>
<project path="$PROJECT_DIR$/buildSrc" />
</projects>
</build>
</builds>
</compositeBuild>
</compositeConfiguration>
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" /> <option name="gradleHome" value="/usr/share/java/gradle" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> <option name="gradleJvm" value="jbr-17" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
@ -32,7 +23,6 @@
<option value="$PROJECT_DIR$/libs/lpac-jni" /> <option value="$PROJECT_DIR$/libs/lpac-jni" />
</set> </set>
</option> </option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

10
.idea/migrations.xml generated
View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

View file

@ -3,7 +3,6 @@ package im.angry.openeuicc.core
import android.se.omapi.Channel import android.se.omapi.Channel
import android.se.omapi.SEService import android.se.omapi.SEService
import android.se.omapi.Session import android.se.omapi.Session
import android.util.Log
import im.angry.openeuicc.util.* import im.angry.openeuicc.util.*
import net.typeblog.lpac_jni.ApduInterface import net.typeblog.lpac_jni.ApduInterface
@ -11,10 +10,6 @@ class OmapiApduInterface(
private val service: SEService, private val service: SEService,
private val port: UiccPortInfoCompat private val port: UiccPortInfoCompat
): ApduInterface { ): ApduInterface {
companion object {
const val TAG = "OmapiApduInterface"
}
private lateinit var session: Session private lateinit var session: Session
private lateinit var lastChannel: Channel private lateinit var lastChannel: Channel
@ -49,17 +44,7 @@ class OmapiApduInterface(
"Unknown channel" "Unknown channel"
} }
Log.d(TAG, "OMAPI APDU: ${tx.encodeHex()}") return lastChannel.transmit(tx)
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
}
} }
} }

View file

@ -296,7 +296,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
} }
iccid.setOnLongClickListener { iccid.setOnLongClickListener {
requireContext().getSystemService(ClipboardManager::class.java)!! requireContext().getSystemService(ClipboardManager::class.java)
.setPrimaryClip(ClipData.newPlainText("iccid", iccid.text)) .setPrimaryClip(ClipData.newPlainText("iccid", iccid.text))
Toast.makeText(requireContext(), R.string.toast_iccid_copied, Toast.LENGTH_SHORT) Toast.makeText(requireContext(), R.string.toast_iccid_copied, Toast.LENGTH_SHORT)
.show() .show()

View file

@ -13,7 +13,7 @@ apply {
android { android {
namespace = "im.angry.openeuicc_deps" namespace = "im.angry.openeuicc_deps"
compileSdk = 34 compileSdk = 33
defaultConfig { defaultConfig {
minSdk = 28 minSdk = 28

View file

@ -193,7 +193,7 @@ internal class IsdrChannelAccessCheck(private val context: Context): Compatibili
internal class KnownBrokenCheck(private val context: Context): CompatibilityCheck(context) { internal class KnownBrokenCheck(private val context: Context): CompatibilityCheck(context) {
companion object { companion object {
val BROKEN_MANUFACTURERS = arrayOf("xiaomi", "huawei", "honor") val BROKEN_MANUFACTURERS = arrayOf("xiaomi")
} }
override val title: String override val title: String

View file

@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "net.typeblog.lpac_jni" namespace = "net.typeblog.lpac_jni"
compileSdk = 34 compileSdk = 33
ndkVersion = "26.1.10909125" ndkVersion = "26.1.10909125"
defaultConfig { defaultConfig {

View file

@ -14,14 +14,14 @@ internal object LpacJni {
// es10c // es10c
// null returns signify errors // null returns signify errors
external fun es10cGetEid(handle: Long): String? external fun es10cGetEid(handle: Long): String?
external fun es10cGetProfilesInfo(handle: Long): Long external fun es10cGetProfilesInfo(handle: Long): Array<LocalProfileInfo>?
external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cEnableProfile(handle: Long, iccid: String, refresh: Boolean): Int
external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int external fun es10cDisableProfile(handle: Long, iccid: String, refresh: Boolean): Int
external fun es10cDeleteProfile(handle: Long, iccid: String): Int external fun es10cDeleteProfile(handle: Long, iccid: String): Int
external fun es10cSetNickname(handle: Long, iccid: String, nick: String): Int external fun es10cSetNickname(handle: Long, iccid: String, nick: String): Int
// es10b // es10b
external fun es10bListNotification(handle: Long): Long // A native pointer to a linked list. Handle with linked list-related methods below. May be 0 (null) external fun es10bListNotification(handle: Long): Array<LocalProfileNotification>?
external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int external fun es10bDeleteNotification(handle: Long, seqNumber: Long): Int
// es9p + es10b // es9p + es10b
@ -31,39 +31,5 @@ internal object LpacJni {
external fun handleNotification(handle: Long, seqNumber: Long): Int external fun handleNotification(handle: Long, seqNumber: Long): Int
// es10cex (actually part of es10b) // es10cex (actually part of es10b)
external fun es10cexGetEuiccInfo2(handle: Long): Long external fun es10cexGetEuiccInfo2(handle: Long): EuiccInfo2?
// C <-> Java struct / linked list handling
// C String arrays
external fun stringArrNext(curr: Long): Long
external fun stringDeref(curr: Long): String
// Profiles
external fun profilesNext(curr: Long): Long
external fun profilesFree(head: Long): Long
external fun profileGetIccid(curr: Long): String
external fun profileGetIsdpAid(curr: Long): String
external fun profileGetName(curr: Long): String
external fun profileGetNickname(curr: Long): String
external fun profileGetServiceProvider(curr: Long): String
external fun profileGetStateString(curr: Long): String
external fun profileGetClassString(curr: Long): String
// Notifications
external fun notificationsNext(curr: Long): Long
external fun notificationGetSeq(curr: Long): Long
external fun notificationGetOperationString(curr: Long): String
external fun notificationGetAddress(curr: Long): String
external fun notificationGetIccid(curr: Long): String
external fun notificationsFree(head: Long)
// EuiccInfo2
external fun euiccInfo2Free(info: Long)
external fun 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
} }

View file

@ -42,85 +42,18 @@ class LocalProfileAssistantImpl(
} }
override val profiles: List<LocalProfileInfo> override val profiles: List<LocalProfileInfo>
get() { get() = LpacJni.es10cGetProfilesInfo(contextHandle)?.asList() ?: listOf()
val head = LpacJni.es10cGetProfilesInfo(contextHandle)
var curr = head
val ret = mutableListOf<LocalProfileInfo>()
while (curr != 0L) {
val state = LocalProfileInfo.State.fromString(LpacJni.profileGetStateString(curr))
val clazz = LocalProfileInfo.Clazz.fromString(LpacJni.profileGetClassString(curr))
ret.add(LocalProfileInfo(
LpacJni.profileGetIccid(curr),
state,
LpacJni.profileGetName(curr),
LpacJni.profileGetNickname(curr),
LpacJni.profileGetServiceProvider(curr),
LpacJni.profileGetIsdpAid(curr),
clazz
))
curr = LpacJni.profilesNext(curr)
}
LpacJni.profilesFree(curr)
return ret
}
override val notifications: List<LocalProfileNotification> override val notifications: List<LocalProfileNotification>
get() { get() =
val head = LpacJni.es10bListNotification(contextHandle) (LpacJni.es10bListNotification(contextHandle) ?: arrayOf())
var curr = head .sortedBy { it.seqNumber }.reversed()
val ret = mutableListOf<LocalProfileNotification>()
while (curr != 0L) {
ret.add(LocalProfileNotification(
LpacJni.notificationGetSeq(curr),
LocalProfileNotification.Operation.fromString(LpacJni.notificationGetOperationString(curr)),
LpacJni.notificationGetAddress(curr),
LpacJni.notificationGetIccid(curr),
))
curr = LpacJni.notificationsNext(curr)
}
LpacJni.notificationsFree(head)
return ret.sortedBy { it.seqNumber }.reversed()
}
override val eID: String override val eID: String
get() = LpacJni.es10cGetEid(contextHandle)!! get() = LpacJni.es10cGetEid(contextHandle)!!
override val euiccInfo2: EuiccInfo2? override val euiccInfo2: EuiccInfo2?
get() { get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)
val cInfo = LpacJni.es10cexGetEuiccInfo2(contextHandle)
if (cInfo == 0L) return null
val euiccCiPKIdListForSigning = mutableListOf<String>()
var curr = LpacJni.euiccInfo2GetEuiccCiPKIdListForSigning(cInfo)
while (curr != 0L) {
euiccCiPKIdListForSigning.add(LpacJni.stringDeref(curr))
curr = LpacJni.stringArrNext(curr)
}
val euiccCiPKIdListForVerification = mutableListOf<String>()
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
}
override fun enableProfile(iccid: String, refresh: Boolean): Boolean = override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0 LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0

View file

@ -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); (*env)->CallVoidMethod(env, callback, on_state_update, download_state_finalizing);
// TODO: Expose error code as Java-side exceptions? // TODO: Expose error code as Java-side exceptions?
ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result); ret = es10b_load_bound_profile_package(ctx, &es10b_load_bound_profile_package_result);
syslog(LOG_INFO, "es10b_load_bound_profile_package %d, reason %d", ret, es10b_load_bound_profile_package_result.errorReason); syslog(LOG_INFO, "es10b_load_bound_profile_package %d", ret);
out: out:
euicc_http_cleanup(ctx); euicc_http_cleanup(ctx);

View file

@ -12,15 +12,28 @@
JavaVM *jvm = NULL; 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; jstring empty_string;
jclass string_class; jclass string_class;
jmethodID string_constructor; jmethodID string_constructor;
jclass euicc_info2_class;
jmethodID euicc_info2_constructor;
jint JNI_OnLoad(JavaVM *vm, void *reserved) { jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jvm = vm; jvm = vm;
interface_wrapper_init(); interface_wrapper_init();
lpac_download_init(); lpac_download_init();
lpac_notifications_init();
LPAC_JNI_SETUP_ENV; LPAC_JNI_SETUP_ENV;
string_class = (*env)->FindClass(env, "java/lang/String"); 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, "<init>", string_constructor = (*env)->GetMethodID(env, string_class, "<init>",
"([BLjava/lang/String;)V"); "([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, "<init>",
"(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, "<init>",
"(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]; const char _unused[1];
empty_string = (*env)->NewString(env, _unused, 0); empty_string = (*env)->NewString(env, _unused, 0);
empty_string = (*env)->NewGlobalRef(env, empty_string); 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; return ret;
} }
JNIEXPORT jlong JNICALL jobject profile_info_native_to_java(JNIEnv *env, struct es10c_profile_info_list *info) {
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 *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) { switch (info->profileState) {
case ES10C_PROFILE_STATE_ENABLED: case ES10C_PROFILE_STATE_ENABLED:
profileStateStr = "enabled"; profileStateStr = "enabled";
@ -136,13 +175,9 @@ Java_net_typeblog_lpac_1jni_LpacJni_profileGetStateString(JNIEnv *env, jobject t
profileStateStr = "unknown"; profileStateStr = "unknown";
} }
return toJString(env, profileStateStr); state = (*env)->CallStaticObjectMethod(env, local_profile_state_class,
} local_profile_state_from_string,
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) { switch (info->profileClass) {
case ES10C_PROFILE_CLASS_TEST: case ES10C_PROFILE_CLASS_TEST:
@ -159,16 +194,51 @@ Java_net_typeblog_lpac_1jni_LpacJni_profileGetClassString(JNIEnv *env, jobject t
break; 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) JNIEXPORT jobjectArray JNICALL
LPAC_JNI_STRUCT_FREE(struct es10c_profile_info_list, profiles, es10c_profile_info_list_free_all) Java_net_typeblog_lpac_1jni_LpacJni_es10cGetProfilesInfo(JNIEnv *env, jobject thiz, jlong handle) {
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, iccid, Iccid) struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, isdpAid, IsdpAid) struct es10c_profile_info_list *info = NULL;
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileName, Name) struct es10c_profile_info_list *curr = NULL;
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, profileNickname, Nickname) jobjectArray ret = NULL;
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_profile_info_list, profile, serviceProviderName, ServiceProvider) 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 JNIEXPORT jint JNICALL
Java_net_typeblog_lpac_1jni_LpacJni_es10cEnableProfile(JNIEnv *env, jobject thiz, jlong handle, 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; return ret;
} }
JNIEXPORT jlong JNICALL JNIEXPORT jobject JNICALL
Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) { Java_net_typeblog_lpac_1jni_LpacJni_es10cexGetEuiccInfo2(JNIEnv *env, jobject thiz, jlong handle) {
struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
struct es10c_ex_euiccinfo2 *info = malloc(sizeof(struct es10c_ex_euiccinfo2)); struct es10c_ex_euiccinfo2 info = {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) { if (es10c_ex_get_euiccinfo2(ctx, &info) < 0)
free(info); goto out;
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);
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));
});
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));
});
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);
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;
} }
return (jlong) info;
}
JNIEXPORT jstring JNICALL
Java_net_typeblog_lpac_1jni_LpacJni_stringDeref(JNIEnv *env, jobject thiz, jlong curr) {
return toJString(env, *((char **) curr));
}
void lpac_jni_euiccinfo2_free(struct es10c_ex_euiccinfo2 *info) {
es10c_ex_euiccinfo2_free(info);
free(info);
}
LPAC_JNI_STRUCT_GETTER_NULL_TERM_LIST_NEXT(char*, stringArr)
LPAC_JNI_STRUCT_FREE(struct es10c_ex_euiccinfo2, euiccInfo2, lpac_jni_euiccinfo2_free)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, profileVersion, ProfileVersion)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, euiccFirmwareVer, EuiccFirmwareVersion)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, globalplatformVersion, GlobalPlatformVersion)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, sasAcreditationNumber, SasAcreditationNumber)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10c_ex_euiccinfo2, euiccInfo2, ppVersion, PpVersion)
LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, extCardResource.freeNonVolatileMemory, FreeNonVolatileMemory)
LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, extCardResource.freeVolatileMemory, FreeVolatileMemory)
LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForSigning, EuiccCiPKIdListForSigning)
LPAC_JNI_STRUCT_GETTER_LONG(struct es10c_ex_euiccinfo2, euiccInfo2, euiccCiPKIdListForVerification, EuiccCiPKIdListForVerification)

View file

@ -17,42 +17,37 @@ struct lpac_jni_ctx {
JNIEnv *env; \ JNIEnv *env; \
(*jvm)->AttachCurrentThread(jvm, &env, NULL) (*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 JavaVM *jvm;
extern jclass string_class; extern jclass string_class;
jstring toJString(JNIEnv *env, const char *pat); 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); \
}

View file

@ -4,15 +4,88 @@
#include <malloc.h> #include <malloc.h>
#include <syslog.h> #include <syslog.h>
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, "<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
Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) { Java_net_typeblog_lpac_1jni_LpacJni_es10bListNotification(JNIEnv *env, jobject thiz, jlong handle) {
struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
struct es10b_notification_metadata_list *info = NULL; struct es10b_notification_metadata_list *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) 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 JNIEXPORT jint JNICALL
@ -45,35 +118,3 @@ Java_net_typeblog_lpac_1jni_LpacJni_es10bDeleteNotification(JNIEnv *env, jobject
struct euicc_ctx *ctx = (struct euicc_ctx *) handle; struct euicc_ctx *ctx = (struct euicc_ctx *) handle;
return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number); return es10b_remove_notification_from_list(ctx, (unsigned long) seq_number);
} }
JNIEXPORT jstring JNICALL
Java_net_typeblog_lpac_1jni_LpacJni_notificationGetOperationString(JNIEnv *env, jobject thiz,
jlong curr) {
struct es10b_notification_metadata_list *info = (struct es10b_notification_metadata_list *) curr;
const char *profileManagementOperationStr = NULL;
switch (info->profileManagementOperation) {
case ES10B_PROFILE_MANAGEMENT_OPERATION_INSTALL:
profileManagementOperationStr = "install";
break;
case ES10B_PROFILE_MANAGEMENT_OPERATION_DELETE:
profileManagementOperationStr = "delete";
break;
case ES10B_PROFILE_MANAGEMENT_OPERATION_ENABLE:
profileManagementOperationStr = "enable";
break;
case ES10B_PROFILE_MANAGEMENT_OPERATION_DISABLE:
profileManagementOperationStr = "disable";
break;
default:
profileManagementOperationStr = "unknown";
break;
}
return toJString(env, profileManagementOperationStr);
}
LPAC_JNI_STRUCT_GETTER_LINKED_LIST_NEXT(struct es10b_notification_metadata_list, notifications)
LPAC_JNI_STRUCT_FREE(struct es10b_notification_metadata_list, notifications, es10b_notification_metadata_list_free_all)
LPAC_JNI_STRUCT_GETTER_LONG(struct es10b_notification_metadata_list, notification, seqNumber, Seq)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, notificationAddress, Address)
LPAC_JNI_STRUCT_GETTER_STRING(struct es10b_notification_metadata_list, notification, iccid, Iccid)

View file

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